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



Formのpublicに、
procedureを追加します。
procedureは変数宣言の後です。
 public
   { Public 宣言 }
   BackScreen:TBitmap;
   b_img:TBitmap;
   procedure CopyBlockImageToField(x,y:integer;block:TBitmap);
 end;
引数として、
マス座標x,yと、貼り付ける画像を定義しました。
こうしておけば、
のちのちカラー版を作りたくなったとき、
blockに渡すTBitmapを差し替えるだけで、
違うブロックも貼り付けられます。
(その場合は、2次元配列がフラグだけじゃだめになるけど・・・・
では、実装部。
procedure TForm1.CopyBlockImageToField(x,y:integer;block:TBitmap);
begin
   BackScreen.Canvas.Draw(x*15,y*15,block);
end;
どこに定義するかは大丈夫ですよね。
implemantation より下で、 end. より上の、
各種procedure begin-end; の隙間です。
さて、手続き、とかいっちゃったわりに、
1行で終わりました。
引数をちょびっとだけ変更して
裏画面のキャンバスにTGraphicsとしてDraw手続きで転送してるだけです。
この、ちょびっとの変更ですが、
x*15をすることで、
15ピクセル単位でしか指定できなくなるため、
結果的に、フィールドをパネル単位で区切る事ができます。
たとえば、xが0なら0*15で座標0ですが、
xが1なら1*15で座標15に転送します。
xが2なら30です。
このように、パネル単位の座標に限定できます。
そしたら、TMapBlocksに、
自分のBlocksに基づいて、ブロックがある部分を、
CopyBlockImageToField で 画像を描く手続きをつけます。
TMapBlocksのpublicを変更。
   TMapBlocks = Class(TObject)
   private
   public
       //変数定義
       Blocks:Array[0..19,0..9] of Boolean;
       function isBlock(x,y:integer):Boolean;
       procedure Draw;
   end;
シンプルに、Drawです。
実装部を作ります。
procedure   TMapBlocks.Draw;
var i,j:integer;
begin
   For i:=0 to 19 do begin
       For j:=0 to 9 do begin
           if isBlock(j,i) then begin
               Form1.CopyBlockImageToField(j,i,Form1.b_img);
           end;
       end;
   end;
end;
変数宣言の解説
i
forループのカウンタ用です。y座標のループに使います。
j
forループのカウンタ用です。x座標のループに使います。
さて、
ちょっと複雑な構造になってますね。
ここまでサクサク進みましたが、
ここは詳しく説明しましょう。
大雑把に見ると
for to do begin
    for to do begin
    end;
end;
と、forの中にforが入っています。
解りにくいので、内側のforを 処理 と書いて見ます。
for to do begin
    処理
end;
これは簡単ですね。処理がループ回数実行されます。
では、処理を見てみると、
for to do begin
end;
となっています。これ自体はループですが、
外側のforの処理なので、
「このループがループされる」ことになります。
   For i:=0 to 19 do begin
       For j:=0 to 9 do begin
       end;
   end;
カウンタの動きを追ってみましょう。
初期化 i:=0 処理へ進む
    初期化 j:=0
    ループ j:=1
    ループ  j:=2
      ・
      ・
      ・
    ループ  j:=9
処理終わる
ループ i:=1 処理へ進む
    初期化 j:=0
    ループ j:=1
    ループ  j:=2
      ・
      ・
      ・
    ループ  j:=9
処理終わる
ループ i:=2 処理へ進む
    初期化 j:=0
    ループ j:=1
    ループ  j:=2
      ・
      ・
      ・
    ループ  j:=9
処理終わる
  ・
  ・
   ・
ループ i:=19 処理へ進む
    初期化 j:=0
    ループ j:=1
    ループ  j:=2
      ・
      ・
      ・
    ループ  j:=9
処理終わる
と なります。
内側のループは、
外側のループのたびに実行されるので、
結果として一番内側はすごい回数実行されてます。
でも実はこれ、
iがy座標で、jがx座標を示したループですから、
こういう順番で実行していただけです。

nijurupu.png

さて、
この二重ループの内側では、
一マスあたりの処理が行われればよいわけです。
           if isBlock(j,i) then begin
               Form1.CopyBlockImageToField(j,i,Form1.b_img);
           end;
まず、isBlockはわかりますね。
jをx、iをyに、ブロックがあるかないか調べます。
もしあれば真を返すようにつくったので、
あった場合は、
Form1.CopyBlockImageToField(j,i,Form1.b_img); 
が実行されます。
TMapBlocksはFormの外で定義してあるので、
Formの中で定義したブロック描画手続きは
Form1.をつけて参照します。
b_imgも同じ。
CopyBlockImageToFieldは、
x,yのブロックに、引数のTBitmapを表示でした。
では、次回で試しに表示してみます。