もぐら叩きを作ってみよう その4

「もぐら叩きを作ろう その4」です。今回で、最低限「もぐら叩きゲーム」が遊べるようになります。それと同時に、ここから先が作ることの楽しみが一層増える所でもあります。ぜひ、がんばって作ってみてください。

まず最初に、もぐらの出現場所を決めます。今回は、もぐらの出現場所は5ヶ所でやってみたいと思います。これは、フォームでの座標をあらかじめ指定してやれば実現できます。

早速やって見ましょう。前回のプロジェクトを開いてください。そして、以下のコードを追加します。

const
  crUp: Integer = 1;
  crDown: Integer = 2;

type
  // 追加します
  THole = record
    Time: Integer; // もぐらの表示されている時間
    Dead: Boolean; // もぐらが叩かれたか?
    Existence: Boolean; // もぐらの存在
  end;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private 宣言 }
    Mog1: TBitmap;
    Mog2: TBitmap;
    HoleInfo: array[0..4] of THole;
    Holes: array[0..4] of TPoint;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
{$R Mogura.res}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Holes[0] := Point(10, 10);
  Holes[1] := Point(200, 10);
  Holes[2] := Point(100, 100);
  Holes[3] := Point(10, 200);
  Holes[4] := Point(200, 200);

  Screen.Cursors[crUp] := LoadCursor(HInstance, 'UP');
  Screen.Cursors[crDown] := LoadCursor(HInstance, 'DOWN');
  Screen.Cursor := TCursor(crUp);

  Mog1 := TBitmap.Create;
  Mog1.LoadFromResourceName(HInstance, 'MOG1');
  Mog2 := TBitmap.Create;
  Mog2.LoadFromResourceName(HInstance, 'MOG2');

end;

recordという新しい用語が出てきました。これは、単に「まとまり」です。ここでは、Time, Dead, Existenceの3つの変数をTHoleという名前の一つのグループにまとめただけです。そして、HoleInfo: array[0..4] of THoleで、そのまとまりを5つ持ちますと宣言しています。この意味は、単にもぐらは今回5匹出現しているからと思ってください。

次に、Holes: array[0..4] of TPointですが、まず、TPointは画面上のピクセル位置を表示するために使用します。分かりにくいと思うので、エディタでTPoint上にカーソル(エディタ上で点滅している「|」です、キャレットと呼ばれています)を持っていってヘルプを起動させて下さい。TPoint型も同じようなrecordで表現されています。(XとYを持っていますね)これで、X座標とY座標を指定してやればいいですね。それを、

Holes[0] := Point(10, 10);
Holes[1] := Point(200, 10);
Holes[2] := Point(100, 100);
Holes[3] := Point(10, 200);
Holes[4] := Point(200, 200);

で実現しています。これで、もぐらの出現場所を決めることが出来ました。次に、もぐらの出現していられる時間を決めます。この時間を設定するには、Timerコンポーネントを使います。「その2」でTimerコンポーネントを使っているので、今回はその内容を書き換えます。

と、その前に、ここでちょっともぐらの出現時間について考えてみたいと思います。今回、もぐらには2種類の絵を用意しました。(普通の絵と叩かれた絵です)なので、ここでは普通の絵が表示されている時間と、叩かれた絵が表示されている時間を別々に設定します。まず、時間を使うために変数の宣言をします。

TForm1 = class(TForm)
  Timer1: TTimer;
  procedure FormCreate(Sender: TObject);
  procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer);
  procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer);
  procedure Timer1Timer(Sender: TObject);
private
  { Private 宣言 }
  Mog1: TBitmap;
  Mog2: TBitmap;
  HoleInfo: array[0..4] of THole;
  Holes: array[0..4] of TPoint;
public
  { Public 宣言 }
  LiveTime, DeadTime, Frequence: Integer;
end;

これで宣言が完了したので、実際に値を代入します。

procedure TForm1.FormCreate(Sender: TObject);
begin
  Holes[0] := Point(10, 10);
  Holes[1] := Point(200, 10);
  Holes[2] := Point(100, 100);
  Holes[3] := Point(10, 200);
  Holes[4] := Point(200, 200);
  
  Randomize;      // 乱数生成関数の初期化
  LiveTime := 7;  // もぐらを表示している時間
  DeadTime := 3;   // もぐらの叩かれた絵を表示している時間
  Frequence := 20;
  
  Screen.Cursors[crUp] := LoadCursor(HInstance, 'UP');
  Screen.Cursors[crDown] := LoadCursor(HInstance, 'DOWN');
  Screen.Cursor := TCursor(crUp);

  Mog1 := TBitmap.Create;
  Mog1.LoadFromResourceName(HInstance, 'MOG1');
  Mog2 := TBitmap.Create;
  Mog2.LoadFromResourceName(HInstance, 'MOG2');

end;

それぞれの値は、どうやって決めたのか気になると思いますけど、これは今の段階では、あまり気にしないで下さい。遊んだ時にこの値を変更すると、それぞれ表示時間を短くしたり長くしたり出来るだけですので・・。また、Frequenceは、もぐらの出現にランダム制を持たせるために使います。Randomizeは、そのランダム制の手助けをしているぐらいの感覚でいいと思います(^^;詳しくはヘルプでお願いします。

それでは、フォームに貼り付けたTimerをダブルクリックして以下のコードを書きます。

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i: Integer;
begin
  i := Random(Frequence);

  if (i < 5) then
  begin
    // もぐらが表示されていないなら
    if (HoleInfo[i].Existence = False) then
    begin
      HoleInfo[i].Existence := True; // もぐらの存在を設定
      HoleInfo[i].Time := LiveTime; // もぐらの表示時間を設定
      HoleInfo[i].Dead := False;    // 「もぐらはまだ叩かれていない」を設定
      Canvas.Draw(Holes[i].X, Holes[i].Y, Mog1); // 実際にもぐらを表示
    end;
  end;

  // 表示しているもぐらがいれば、その表示時間を減らす
  for i := 0 to 4 do
  begin
    if (HoleInfo[i].Existence = True) and (HoleInfo[i].Time > 0) then
      Dec(HoleInfo[i].Time); // 表示時間を減らしています
  end;

  // 表示しているもぐらの表示時間が過ぎていないか
  // 過ぎていたら、もぐらを消す
  for i := 0 to 4 do
  begin
    if (HoleInfo[i].Time = 0) then // 表示時間が0になったら
    begin

      // もぐらを消します
      HoleInfo[i].Existence := False;
      Canvas.FillRect(Rect(Holes[i].X, Holes[i].Y,
        Holes[i].X+Mog2.Width, Holes[i].Y+Mog2.Height));
    end;
  end;
end;

少しプログラムが長いですが、ゆっくり見ていけば大丈夫だと思います。それぞれの意味はコメント通りです。また、for 文で 0 から 4 までの5回ループしているのは、今回もぐらを 5 匹使用している為(これは、言い換えると5つのもぐらを表示できる場所があるためとも言えます)です。それでは次に、オブジェクトインスペクタで Timer を選択して Interval プロパティを 200 に設定してください。そうすることで、上記のprocedure TForm1.Timer1Timer(Sender: TObject);が、200 ms 感覚で呼ばれ続けます。( 1000 ms = 1 s( 秒 ) )今回は少し長いですが、もうちょっとで終わりますのでがんばってください。

次に、マウスのイベントを書きます。もぐらをマウスでクリックした時は、叩かれたもぐらを表示しなければなりません。また、もぐらとマウスカーソルとの当たり判定は前回やりましたので、そちらを参考にして下さい。それでは、以下のコードを書いてください。

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  i: Integer;
begin
  Screen.Cursor := Tcursor(crDown);

  for i := 0 to 4 do
  begin
    if (HoleInfo[i].Dead = False) and (HoleInfo[i].Time > 0) then
      if (X > Holes[i].X) and (X < (Holes[i].X+Mog1.Width)) and
        (Y > Holes[i].Y) and (Y < (Holes[i].Y +Mog1.Height)) then
      begin
        HoleInfo[i].Dead := True;    // 「もぐらが叩かれた」を設定
        HoleInfo[i].Time := DeadTime; // 叩かれた絵の表示時間を設定
        Canvas.Draw(Holes[i].X, Holes[i].Y, Mog2); // 叩かれた絵の表示
      end;
  end;
end;

もぐらを叩いたら、叩かれた絵の表示時間の設定とその絵の表示をここでは行っています。

それでは、最後にオブジェクトインスペクタでForm1を選択してイベントページのOnDestroyの右側の空白をダブルクリックして以下のように書いてください。

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Mog1.Free;
  Mog2.Free;
end;

これは、何をやっているかというとMog1 := TBitmap.Create;で生成したメモリの開放を行っています。これについては、今の所「こういうものだ」という感じでいいと思います。今後もうちょっと詳しく説明したいと思いますので・・。

お疲れ様です、やっと終わりました。コンパイルして実行してみてください。一応「もぐら叩き」が遊べます。ただ、これだとまだまだ機能不足です。次回は、さらに遊びやすくするためにゲーム時間の設定や得点の表示をやってみたいと思います。一定数のもぐらを叩いたら巨大もぐらが出てくる等の設定をすると、もっと面白くなりますね。

まだまだ未完成です。

次回はメニューを作成したいと思います。


up next
Last update: 2002/3/3