−トップへ−

スライドパズルを作る
その2 ピースを動かす

 今回は,ピースを動かすプログラムを作ってみます。動かし方はタイマーコンポーネントを使って自動で動くようにしてみます。

メインメニューの設置

 今回はフォームの上にメニューを設けて,「ゲームの開始」と「終了」の2つを設置してみます。
 
 メインメニューをフォームに貼り付けた後,それをダブルクリックすると新しいフォームが開きます。


 上のフォームが開いたら,そこで「ゲームの開始」と「終了」のメニューを作ります。今回は2つ横に並べて作りましたが,ほかのレイアウトの仕方として,メニューに「ゲーム」を作り,その下に「ゲームの開始」と「終了」の2つをサブメニューとして作ることもできます。このようにすると最初に「ゲーム」メニューをクリックするとサブメニューが開き,そこに「ゲームの開始」と「終了」メニューが現れます。
 
 このほかにピースを自動で動かすために,timerコンポーネントを設置します。
 timerコンポーネントの初期設定は
  [enabled]…false
  [interval]…10
にしておきます。intervalの数値は変えるとスピードが変化するのでいろいろ試してください。
 
 以下に,プログラムソースを書いてみます。

type
 TForm1 = class(TForm)
 MainMenu1: TMainMenu;
 N1: TMenuItem;
 N2: TMenuItem;
 Timer1: TTimer;
 procedure FormCreate(Sender: TObject);
 procedure N1Click(Sender: TObject);
 procedure N2Click(Sender: TObject);
 procedure ImgClick(Sender: TObject); //←これを追加します
 procedure Timer1Timer(Sender: TObject);
 private
 { Private 宣言 }
  img:array[1..16] of Timage; //imageを動的生成するために,これを記入します
  po:array[0..5,0..5] of integer; //ピースの場所を記録するための変数です
  num,space:integer; //numは,クリックしたピースの番号を記録するため
 public           //spaceはクリックしたピースのどこが空きになっているか記録するため
 { Public 宣言 }
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
 i:integer; //iを整数宣言
begin
 form1.ClientHeight:=402; //フォームの内側の高さを402にする
 form1.ClientWidth:=402; //フォームの内側の幅を402にする
 form1.color:=clblack; //フォームの色を黒にする
 for i:=1 to 16 do begin
  img[i]:=Timage.Create(form1); //イメージコンポーネントを作成
  img[i].Parent:=form1; //イメージコンポーネントをform1上に置く
  img[i].Left:=100*((i-1) mod 4)+2; //イメージコンポーネントのx座標を指定
  img[i].Top:=100*((i-1) div 4)+2; //イメージコンポーネントのy座標を指定
  img[i].Width:=98; //イメージコンポーネントの幅を98にする
  img[i].Height:=98; //イメージコンポーネントの高さを98にする
  with img[i].canvas do begin //ここからイメージコンポーネントの色や文字を設定します
   brush.Color:=clwhite; //ブラシの色を白にする
   fillrect(img[i].Canvas.ClipRect); //イメージコンポーネント全体を塗りつぶす
   font.Color:=clMaroon; //文字の色を茶色っぽい色にする
   if i<=15 then begin //イメージコンポーネント15個に順番に数字を描く
    font.Size:=40; //文字のサイズを40にする
    textout((img[i].Width-textwidth(inttostr(i))) div 2,        //イメージコンポーネントの中央に
         (img[i].Width-textheight(inttostr(i))) div 2,inttostr(i)); //数字を描く
   end else begin //それ以外(16個目)
    font.Size:=15; //文字のサイズを15にする
    textout((img[i].Width-textwidth('DELPHI')) div 2,       //イメージコンポー年の中央に
         (img[i].Width-textheight('DELPHI')) div 2,'DELPHI'); //「DELPHI」と描く
   end;
  end;
  img[i].OnClick:=imgClick; //←これを付け加えます。
 end;                //これで動的に生成したイメージコンポーネントにイベントを設定できます。
end;
 

 //「ゲームの開始」メニューを押したとき,ピースの場所を記録する
procedure TForm1.N1Click(Sender: TObject);
var
 i,j:integer; //iとjを整数宣言
begin
 for i:=0 to 5 do begin //全体を−1にする
  for j:=0 to 5 do begin
   po[i,j]:=-1;
  end;
 end;
 for i:=1 to 16 do begin //パーツの番号をpo[i,j]に記録
  po[(i-1) mod 4+1,(i-1) div 4+1]:=i;
 end;
 po[4,4]:=0; //16番目のピースの場所を0にして空欄扱いにする
 img[16].Visible:=false; //16番目のピースを見えなくする
end;
 
 //「終了」メニューを押したとき,フォームを終了する
procedure TForm1.N2Click(Sender: TObject);
begin
 form1.Close;
end;

 //動的に生成したイメージコンポーネントをクリックしたとき
procedure TForm1.ImgClick(Sender: TObject);
var
 i,j,k:integer;
begin
 for i:=1 to 15 do begin  //img[1]からimg[16]の,どのピースが押されたか調べる
  if sender=img[i] then begin //sender=img[i]が成立するとき,iが押されたピースの番号になります
   num:=i; //変数numにiの値を代入
   for j:=1 to 4 do begin //iが4×4の配列のどこにあるか求める
    for k:=1 to 4 do begin
     if po[k,j]=i then begin
      if po[k,j-1]=0 then begin //iの上に空欄がある場合
       po[k,j-1]:=i; //iの上の欄の値をiにして
       po[k,j]:=0; //iの欄の値を0にする
       space:=1; //変数spaceを1にする(1の場合は上部が空欄とする)
       timer1.Enabled:=true; //timerコンポーネントを作動させる
       exit; //このプロシージャから抜け出す
      end;
      if po[k+1,j]=0 then begin //iの右側に空欄がある場合(以下同じ)
       po[k+1,j]:=i;
       po[k,j]:=0;
       space:=2; //変数spaceを2にする(2の場合は右側が空欄とする)
       timer1.Enabled:=true;
       exit;
      end;
      if po[k,j+1]=0 then begin //iの下に空欄がある場合
       po[k,j+1]:=i;
       po[k,j]:=0;
       space:=3; //変数spaceを3にする(3の場合は下が空欄とする)
       timer1.Enabled:=true;
       exit;
      end;
      if po[k-1,j]=0 then begin //iの左側に空欄がある場合
       po[k-1,j]:=i;
       po[k,j]:=0;
       space:=4; //変数spaceを4にする(4の場合は左側が空欄とする)
       timer1.Enabled:=true;
       exit;
      end;
     end;
    end;
   end;
  end;
 end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 case space of
  1:img[num].top:=img[num].top-2; //変数spaceが1のとき,上に2ピクセル移動させる
  2:img[num].Left:=img[num].Left+2; //変数spaceが2のとき,右に2ピクセル移動させる
  3:img[num].top:=img[num].top+2; //変数spaceが3のとき,下に2ピクセル移動させる
  4:img[num].Left:=img[num].Left-2; //変数spaceが4のとき,左に2ピクセル移動させる
 end;
 timer1.Tag:=timer1.Tag+1; //繰り返しの回数をtimer1.Tagに記録する
 if timer1.Tag=50 then begin //50回繰り返したら
  timer1.Tag:=0; //timer1.Tagの値を0にする
  timer1.Enabled:=false; //timerコンポーネントを無効にする
 end;
end;
 
end.

 上記のプログラムソースを入力して実行して,ピースをクリックするとピースが移動します。
 このとき若干ちらつくことがありますが,ちらつきを抑えるには別の方法をとらなければなりません。
 
 次回は,「ゲームの開始」をクリックしたときに,シャッフルする方法を述べていきます。

−トップへ−