コラム / テトリスぽいもの / 22



まず、ゲームの死亡フラグをどこにおくかですが、
ピースはMapBlocksに参照変数を持ってるので、
MapBlocksに持たせるのがちょうどいいです。
それに、
ピースはフィールドにはみ出たことを通知
メインルーチンでフィールドのフラグをチェック
っていう、段階をはさんだ情報転送は、
こう、
cooooooooooooooooooooooooooooooool
まぁ俺の考え方だけど。
TMapBlocksの宣言部編集
   TMapBlocks = Class(TObject)
   private
   public
       //変数定義
       Blocks:Array[0..19,0..9] of Boolean;
       GameOver:Boolean;
       function isBlock(x,y:integer):Boolean;
       procedure Draw;
   end;
GameOverフラグを定義。
こっちでは実装するものは無し。
TPiece.CopySelfToMapBlocksの実装部を編集します。
procedure TPiece.CopySelfToMapBlocks;
var i,j:integer;
begin
   For i:=0 to 3 do begin
       For j:=0 to 3 do begin
           if shape[i,j] then begin
               MapBlocks.Blocks[y+i,x+j]:=True;
           end;
       end;
   end;
end;
procedure TPiece.CopySelfToMapBlocks;
var i,j:integer;
begin
   For i:=0 to 3 do begin
       For j:=0 to 3 do begin
           if shape[i,j] then begin
               if y+i<0 then begin
                   MapBlocks.GameOver:=True;
               end else begin
                   MapBlocks.Blocks[y+i,x+j]:=True;
               end;
           end;
       end;
   end;
end;
y+iが、負の数だったら、
フラグを立てて、blocksには触りません。(触ったらエラー
そうじゃなければ今までどおり。
フラグが立つようになったので、
Timerのメインルーチンをいじります。
procedure TForm1.Timer1Timer(Sender: TObject);
begin
   if MapBlocks.GameOver then begin
       showmessage('m@(^Д^)プギャー 死んでやがるwwwアヒャヒャヒャヒャ');
       Close;
       Exit;
   end;

   with BackScreen.Canvas do begin
       Brush.Color:=clBlack;
       FillRect(Rect(0,0,150,300));
   end;

   if Assigned(Piece) then begin
       Piece.Main;
       if Piece.death then begin
           FreeAndNil(Piece);
       end;
   end;

   MapBlocks.Draw;

   PaintBox1.Canvas.Draw(0,0,BackScreen);
end;
新しく追加されたのは
   if MapBlocks.GameOver then begin
       showmessage('m@(^Д^)プギャー 死んでやがるwwwアヒャヒャヒャヒャ');
       Close;
       Exit;
   end;
ですが、
なぜ後ろではなく、先頭に追加したのか説明します。
今、メインルーチンは
「画面黒塗りつぶし→ピース移動→ピース描画→フィールド描画→裏画面転送」
となっています。
もし、このルーチンの、
裏画面転送 より前に、ゲームオーバー判定をしてしまうと、
ゲームオーバー状態で、最後のブロックが描かれないかもしれません。
実は、ちょっと複雑でどうなるか考えてないんですが、
次のループの先頭で判定なら何か誤作動が連鎖することは無いのでw多分w
で、追加コードの説明です。
  if MapBlocks.GameOver then begin ですから、
ゲームオーバーフラグが立っていたら処理を実行します。
処理は、 
       showmessage('m@(^Д^)プギャー 死んでやがるwwwアヒャヒャヒャヒャ');
       Close;
       Exit;
です。
一つ目はわかりますね。
二つ目は、フォームを閉じる処理です。
といっても、実際には閉じません。
今実行されている命令が終わったら即座に閉じるようになります。
三つ目はExitで、命令の脱出ですから、
Closeを指定したら、すぐ脱出し、
結局フォームが閉じるわけです。
ゲームガチャ切りはちょいとアレですが、
状態管理が要らなくなるので簡単なのです。
もし、ガチャ切りじゃなくて、
ゲームオーバー画面 とかがある場合、
今のメインルーチンとは全然違うループになるため、
もう一回り大きい技が必要になるんです。
まぁ、これで、
積もったらフラグ→終了
の流れができたので、
次で、次のピース落下処理を作りましょう。