トップページ > 電子工作インデックス > テトリス > 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; } //********************************************************************