トップページ > 電子工作インデックス > テトリス > 8. 落下関数
main()関数のループの中で主に呼び出される関数です。 操作中のブロックを地面(フィールドの底or他の積み上がったブロック) に当たるまで落下させます。 落下完了した後は、操作していたブロックをstage配列(背景)の一部として、 次に上から降ってくる新しいブロックを生成して終わります。
処理を分かりやすくするために、処理をいくつかの関数にわけてあります。 ブロックを移動させるmove_block()関数や、 ブロックが一列すべてそろっているかを判断するcheck_lines()関数 は前述の通りです。 それに加えて、操作中のブロックが背景(フィールド&落下済みブロック)に干渉して いないかをチェックする関数と、落下完了した後に操作していたブロックを背景の 一部として組み込んで操作対象外にする関数もつくっておきます。
操作中のブロックが壁にめり込んだり、積み上がったブロックをすり抜ける ことを防ぐために、背景に対して重なっている場合に"1"を返す関数をつくります。 操作中のブロックの座標は、左上の頂点の座標を使っていますが、 そのブロックの座標を引数として、ブロックが存在する点 (block配列の要素が"1"である点)においてback配列(背景を管理する配列) の要素が"1"であれば、ステージと干渉しているということなので、見つかり次第"1"を返します。 最後までひっかからなければ"0"を返します。
//********************************************************************
//ブロックがbackと重なっているか判断
//2つの引数new_xとnew_yは、ブロックが干渉するかどうかを調べる座標。
int check_back_block(int new_x,int new_y)
{
int i,j; //for文用の変数
//ブロックのデータを扱うblock配列は8×8ですので、そのすべてのマスを調べます。
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
//各ブロックの形は違うので、blockの要素が"1"のところを狙ってチェックします。
if(block[i][j] ==1)
{
//stageは背景を扱う配列です。背景にすでにブロックがある場所には
//ブロックを移動させることはできません…
if(back[new_y+i][new_x+j] ==1)
{
//干渉する場合は"1"を返します。
return 1;
}
}
}
}
//最後までif文の条件にひっかからなかった場合は、干渉なしと判断します。
return 0;
}
//********************************************************************
操作中のブロック以外は、別の背景用配列(back)にデータを入れて管理します。 処理内容は単純で、backの指定座標にblockを加算するだけです。
//********************************************************************
//ブロック固定関数
void lock_block(void) //ブロックの固定と消し判定
{
int i,j;
//backは「固定済みのブロック+壁」を記憶する背景用配列です。
//check_lines()関数はbackを処理対象とするので、一度画面のデータを移します。
for(i=1;i<36;i++)
{
for(j=0;j<24;j++)
{
back[i][j]=field[i][j];
}
}
//1列そろっているかどうかの判定、得点の管理、1列分の消去など、
//すべてここで処理します。
check_lines();
//1列消されている場合も、そうでない場合も、とりあえず画面を更新。
for(i=1;i<36;i++)
{
for(j=0;j<24;j++)
{
display[i][j] = back[i][j];
}
}
//ブロックが着地した時の音。
voice1();
}
//********************************************************************
//********************************************************************
//ブロックを落とす…
void drop_block(void)
{
//スコア管理用変数。
unsigned long temp;
//下に1マスずらした場合の干渉がなければ、check_stage_block関数が"0"を返します。
//x,yはブロックの現在座標を扱うグローバル変数です。
if(check_stage_block(x,y+1) == 0)
{
//下に1マスずらす。
moveblock(x,y+1);
}
//ブロックが下まで落ちきった場合
else
{
//まず操作していたブロックを背景扱いにする。
//lock_block()関数内で、1列そろった場合の処理も実行します。
lockblock();
//新しい操作ブロックを呼び出します。
createblock();
//一通りの処理結果を画面に表示します。
putout();
}
temp=score;
//ゲームスピードを決める変数eは、2000点ごとに小さくなっていきます。
e = 8-temp/2000;
//eが3より小さくなる場合は3で止めておきます。(速すぎるので…)
if(e<3) e=3;
}
//********************************************************************