「テトリスもどき」ゲームのプログラムを紹介します。

case 2:
piece[3][1] = bp;
piece[3][2] = bp;
break;
case 3:
piece[1][2] = bp;
piece[1][3] = bp;
break;
copy_piece[4-j][i] = piece[i][j];
で右回転が表現できます。
(piece[i][j] >= 1 && area[bx + i - 2][by + j - 1] == 0)
であれば、つまり、ピースのダイスがある位置のフィールドが空白であれば、その位置にピースを移動することができます。bx + i - 2 の -2 はピースの中心から左端までの距離です。by
+ j - 1 の -1 は、ピースを一つ下に落としたときの、中心から上端までの距離になります。このチェックを checkPiece(piece,x,y)
で行います。 ld=1;
for(j=2; j<12; j++) ld = ld * area[j][i];
で、ld が 0 でなければ、横方向にすべてダイスがありますから、削除可能です。行を削除するには、上の行を1行下げれば良いので、 for(k=i-1;k>0;k--)
for(s=2;s<12;s++) area[s][k+1]=area[s][k];
となります。//テトリスもどき
//フォントが必要 MS-Gothic-48.vlw
//音用ライブラリ
//import ddf.minim.*;
//Minim minim;//音のクラス
//AudioSample sound_roll, sound_clear;
PImage backImage;
PFont font;
int area[][] = new int[14][24];//ピース記憶領域
int piece[][] = new int[5][5];//ブロック生成領域
int piece_next[][] = new int[5][5];//次のピース
int copy_piece[][] = new int[5][5];
int preFrame;//前の時刻
int startTime = 0;//時間
int playTime;//利用時間
int nline = 0;//消したラインの総数
int nlevel = 1;//現在のレベル
int nfast = 800;//落下時間間隔
int bx, by;//落下中のピースの座標
int x = 2, y = 0;
int z = 0;
boolean rs;
void setup() {
size(320, 440);
frameRate(45);
//minim = new Minim(this);
//sound_roll = minim.loadSample("meka_ta_sui01.mp3");
//sound_clear = minim.loadSample("magic23.mp3");
backImage = createBackgroundImage();
font = loadFont("MS-Gothic-48.vlw");
bx = 7;
by = 2;
getNewPiece(piece_next);
updatePiece();
for (int i = 2;i < 12;i++)
for (int j = 0;j < 22;j++) area[i][j] = 0;
startTime = millis();
preFrame = startTime;
//0 : ピースが存在しない、-1 :壁
//左右の壁
for (int i = 0;i < 22;i++) {
area[1][i] = -1;
area[12][i] = -1;
}//for i
//下の壁
for (int i = 2;i < 12;i++) {
area[i][22] = -1;
area[i][23] = -1;
}//for i
}//setup
void draw() {
int i, j, count;
//背景フィールド再描画
image(backImage, 0, 0);
//落とす時間がチェック
int nowFrame = millis();
int frameSpan = nowFrame - preFrame;
if (frameSpan >= nfast) {
if (by <= 22)
by++;//ピースを落とす
preFrame = nowFrame;
}//if frame
//利用時間
playTime = (int)((nowFrame - startTime) / 1000);
//ピースをひとつ下に落下が可能かどうか?
if (!checkPiece(piece, bx, by+1)) {
//落下は不可:ピースをフィールドにおく
for (i = 0;i < 5;i++)
for (j = 0;j < 5;j++)
if (piece[i][j] >= 1) area[bx + i - 2][by + j - 2] = piece[i][j];
Check_Clear();//行クリアできたか
updatePiece();//次のピース作成
bx = 7;
by = 2;//最初の位置
}//if count
//落下中のピースを描く
for (i = 0;i < 5;i++)
for (j = 0;j < 5;j++) Draw_Block(piece[i][j], i + bx - 3, j + by - 3);
//エリアのピースを描く
for (i = 0;i < 12;i++)
for (j = 2;j < 22;j++) Draw_Block(area[i][j], i - 1, j - 2);
//次のピースを描画
for (i = 1;i < 5;i++)
for (j = 1;j < 5;j++) Draw_Block(piece_next[i][j], i + 11, j + 3);
if (area[7][2] >= 1) {
//ゲームオーバー
noLoop();//停止
fill(255, 0, 0);
textFont(font, 32);
textAlign(CENTER, CENTER);
text("GameOver", 120, height / 2 - 10);
}//if gameover
//数字の描画
textFont(font, 18);
fill(0);
textAlign(RIGHT);
text(int(playTime), 294, 48);//時間
text(int( nlevel), 294, height - 80);//現在のレベル
text(int( nline), 294, height - 26);//消したラインの数
}//draw
void stop() {
super.stop();
//sound_roll.close();
//sound_clear.close();
//minim.stop();
}//stop
void keyPressed() {
if (keyCode==LEFT) {
Move_Left();
}//if left
else if (keyCode == RIGHT) {
Move_Right();//右移動
}//if right
else if (keyCode == DOWN) {
Move_Down();//下移動
}//if down
else if (keyCode == UP) {
Roll_piece();
}//if up
// repaint();
}//keypress
//次ぎに落とすピースを作成
void updatePiece() {
for (int i = 0;i < 5;i++)
for (int j = 0;j < 5;j++) piece[i][j] = piece_next[i][j];
getNewPiece(piece_next);
}//createBlock
//ピースの要素を描画
void Draw_Block(int blockID, int addressX, int addressY) {
if (blockID >= 1) {
stroke(64);
//番号から色を決定
fill(0 + blockID * 22, 150 + blockID % 2 * 70, 100 + blockID * 25);
rect(addressX * 20, 20 + addressY * 20, 20, 20);
}//if blockID
}//draw_block
public int[][] getNewPiece(int[][] newPiece) {
//int[][] newPiece = new int[5][5];
int pieceID = (int)(Math.random() * 140000) % 7 + 1;
for (int i = 0;i < 5;i++)
for (int j = 0;j < 5;j++) newPiece[i][j] = 0;
newPiece[2][2] = pieceID;
newPiece[2][3] = pieceID;
switch(pieceID) {
case 1:
newPiece[1][1] = pieceID;
newPiece[1][2] = pieceID;
break;
case 2:
newPiece[3][1] = pieceID;
newPiece[3][2] = pieceID;
break;
case 3:
newPiece[1][2] = pieceID;
newPiece[1][3] = pieceID;
break;
case 4:
newPiece[2][1] = pieceID;
newPiece[3][3] = pieceID;
break;
case 5:
newPiece[2][1] = pieceID;
newPiece[1][3] = pieceID;
break;
case 6:
newPiece[1][3] = pieceID;
newPiece[3][3] = pieceID;
break;
case 7://I 型ピース
newPiece[2][1] = pieceID;
newPiece[2][4] = pieceID;
break;
}//switch
return newPiece;
}//getnewpiece
public void Check_Clear() {
//ピースが消えるかどうかを判定・ピースの消去
int i, j, s, k;
int ld;
boolean cleared = false;
//ラインが消せるかどうか判定
for (i = 21;i > 0;i--) {
ld = 1;
for (j = 2;j < 12;j++)ld = ld * area[j][i];
if (ld != 0) {
//一行が揃った
cleared = true;
//上からプレスする
for (k = i - 1;k > 0;k--)
for (s = 2;s < 12;s++) area[s][k + 1] = area[s][k];
i++;
nline++;
}//if ld
}//for i
if (cleared) {
//レベル上げの処理
delay(100);
//level up
nlevel=(int)sqrt(nline+10);
nfast = 850 - (50 * nlevel);
//最低でも0.1秒
if (nfast <= 100) nfast = 100;
}//if cleared
}//check_clear
public void Move_Down() {
if (checkPiece(piece, bx, by+1)) by++;
}//down
void Move_Right() {
if (checkPiece(piece, bx+1, by)) bx++;
}//right
void Move_Left() {
if (checkPiece(piece, bx-1, by)) bx--;
}//left
public void Roll_piece() {
int i, j, count;
count = 0;
//仮回転体生成
for (i=0;i<5;i++)
for (j=0;j<5;j++) copy_piece[4 - j][i] = piece[i][j];
//回転可能なら回転する
if (checkPiece(copy_piece, bx, by)) {
//生成したピースを回転後の形に更新
for (i = 0;i < 5;i++)
for (j = 0;j < 5;j++) piece[i][j] = copy_piece[i][j];
//sound_roll.trigger();
}//if
}//roll
boolean checkPiece(int[][] piece, int bx, int by) {
int count=0;
for (int i = 0;i < 5;i++) {
for (int j = 0;j < 5;j++)
if (piece[i][j] >= 1 && area[bx + i - 2][by + j - 2] == 0) count++;
}
if (count==4) return true;
else return false;
}
PImage createBackgroundImage() {
PFont ft = createFont("MS Gothic", 14);
fill(232, 240, 255);//background
noStroke();
rect(0, 0, width, height);
//white background
fill(255);
stroke(208);
rect( 20, 20, 200, height - 40);//game field
rect(240, 10, 60, 46);//time back
rect(240, 70, 60, 114);//next back
rect(240, height - 123, 60, 46);//level back
rect(240, height - 67, 60, 46);//line back
//label background
fill(32, 80, 128);
noStroke();
rect(241, 11, 59, 15);//time
rect(241, 71, 59, 15);//next
rect(241, height - 123, 59, 16);//level
rect(241, height - 67, 59, 16);//line
//text
textFont(ft);
fill(0, 6, 16);
textAlign(RIGHT, BASELINE);
text("←→:move ↑:roll ↓:fall", width, height - 2);//guide
fill(250);
textAlign(LEFT, BASELINE);
text( "TIME", 246, 24);
text( "NEXT", 246, 84);
text("LEVEL", 246, height - 109);
text( "LINE", 246, height - 53);
return get();
}