−トップへ−

ブロックくずしゲームを作る
その3 ラケットを表示させる

 その2で,ボールを動かしましたが,今回はボールをはじき返すラケットを作ってみたいと思います。

ラケットの初期設定

 ラケットを表示させるために,いくつか変数を設定します。ここでは次の3つの変数を整数宣言します。

   rakx…ラケットの位置を表すX座標
   raky…ラケットの位置を表すY座標
   rakw…ラケットの幅
 その他に,ラケットを動かすときに使う変数を宣言します。
   keyd…ラケットを動かすときに使用
        右方法のときはプラス,
        左方向に動かすときはマイナス,
        止まっているときは0にする。

 これらの変数をPrivateに宣言します。

 type
  TForm1 = class(TForm)
   Image1: TImage;
   procedure FormCreate(Sender: TObject);
  private
   { Private 宣言 }
   ballx,bally,bx,by,balls:integer;
   rakx,raky,rakw,keyd:integer; //ラケットに使う変数を整数宣言します
  public
   { Public 宣言 }
  end;

 これらの数字を使って,ラケットを描いてみます。書くのは,FormCreateイベントハンドラの中です。

 procedure TForm1.FormCreate(Sender: TObject);
 begin
  //フォームの大きさを決める
  form1.ClientWidth:=400;
  form1.ClientHeight:=500;
  //フォームの大きさに合わせてImageコンポーネントを設置する
  image1.Left:=0;
  image1.Top:=0;
  image1.Width:= form1.ClientWidth;
  image1.Height:= form1.ClientHeight;
  //ラケットの設計
  rakx:=200;// ラケットのX座標を200に設定
  raky:=450;// ラケットのY座標を450に設定
  rakw:=50;// ラケットの幅を50に設定
  //Imageに描く
  with image1.Canvas do
  begin
   //背景
   brush.Color:=clblack;
   fillrect (image1.Canvas.ClipRect);
   ラケットを描く
   brush.Color:=clwhite; //ラケットの色を白にする
   fillrect(rect(rakx,raky,rakx+rakw,raky+10)); //ラケットの厚みを10にして描画
  end;
 end;

 ここまでのプログラムコードの書きかえで,実行すると下のようになります。
 rakxやraky,rakwの数値を変えるとラケットの位置や大きさが変わります。
 

ラケットを動かす

 上で表示されたラケットを動かしてみます。今回は[←]キーと,[→]キーで動かしてみます。
 
 
 [←]キーと[→]キーを使うには,.FormKeyDownとFormKeyUpのイベントハンドラを使います。
 .FormKeyDownイベントはキーを下げたときに発生するイベントで,FormKeyUpイベントは,下げたキーを上げるときに発生するイベントです。
 
 この2つのイベントハンドラを呼び出すには,画面左下の「オブジェクトインスペクタ」のイベントの欄を見ていくとありますので,ダブルクリックして呼び出します。
 
 呼び出したらそこに次のようなプログラムコードを書きます。

 procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
 begin
  if key=VK_right then keyd:=4; //押されたキーが[→]キーならkeydに4を代入
  if key=VK_left then keyd:=-4; //押されたキーが[←]キーならkeydに−4を代入
 end;
 
 procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
 begin
  keyd:=0; //キーを上げたらkeydに0を代入
 end;

 上のコードで,何も押していないときはkeydの値は0です。そして[→]を押している間はkeydは4で,[←]を押している間は−4になります。
 
 このkeydの値を使って,Timer1Timerのイベントハンドラにプログラムを書き,ラケットを動かします。

 procedure TForm1.Timer1Timer(Sender: TObject);
 begin
  //ボールがあった部分を黒く塗る
  with image1.Canvas do
  begin
   brush.Color:=clblack;
   fillrect(rect(ballx,bally,ballx+balls,bally+balls));
  end;
  //ボールの新しい座標を求める
  if (ballx<=0) or (ballx>=image1.Width-balls) then bx:=-bx;
  ballx:=ballx+bx;
  if (bally<=0) or (bally>=image1.Height-balls) then by:=-by;
  bally:=bally+by;
  //bx,by進んだ位置にボールを描く
  with image1.Canvas do
  begin
   brush.Color:=clwhite;
   fillrect(rect(ballx,bally,ballx+balls,bally+balls));
  end;
   //ラケットを動かす
  if keyd<>0 then //もしkeydが0でなければ以下のプログラムを行う
  begin
   with image1.Canvas do
    brush.Color:=clblack; //ブラシの色を黒にする
    fillrect(rect(rakx,raky,rakx+rakw,raky+10)); //ラケットのあった場所を黒で塗りつぶす
    rakx:=rakx+keyd; //新しいラケットの場所を求める
    brush.Color:=clwhite; //ブラシの色を白にする
    fillrect(rect(rakx,raky,rakx+rakw,raky+10)); //新しいラケットの場所を白くする
   end;
  end;
 end;

 上のコードを書いて実行すると,マウスでクリックした後,矢印キーを押すとラケットが動きます。
 
 しかし,このままではラケットを表示しているだけなので,ボールがラケットの上を通過してしまいます。
 
 そこで今度はラケットでボールをはじくようにしてみます。
 
 

ラケットでボールをはじき返す

 ボールがラケットに当たったかどうかは,ボールがラケットのあるY座標まで下がってきたとき,ボールのX座標がラケットの左端のX座標ballxから右端のX座標ballx+ballwの間にあるかどうか調べます。
 
 このプログラムを,Timer1Timerイベントハンドラに書き込みます。

 procedure TForm1.Timer1Timer(Sender: TObject);
 begin
  //ボールがあった部分を黒く塗る
  with image1.Canvas do
  begin
   brush.Color:=clblack;
   fillrect(rect(ballx,bally,ballx+balls,bally+balls));
  end;
  //ボールの新しい座標を求める
  if (ballx<=0) or (ballx>=image1.Width-balls) then bx:=-bx;
  ballx:=ballx+bx;
  if (bally<=0) or (bally>=image1.Height-balls) then by:=-by;
  bally:=bally+by;
  //ボールがラケットに当たったか調べる
  if bally>=raky-balls then //ボールのY座標がラケットのY座標より大きくなったとき
  begin
   if (ballx>=rakx) and (ballx<=rakx+rakw) then by:=-by; //ボールがラケットの間にあればボールの進む方向を変える
  end;
  //bx,by進んだ位置にボールを描く
  if bally>=500 then
  begin
   brush.Color:=clwhite;
   fillrect(rect(ballx,bally,ballx+balls,bally+balls));
  end;
  //ラケットを動かす
  if keyd<>0 then
  begin
   with image1.Canvas do
   begin
    brush.Color:=clblack;
    fillrect(rect(rakx,raky,rakx+rakw,raky+10));
    rakx:=rakx+keyd;
    brush.Color:=clwhite;
    fillrect(rect(rakx,raky,rakx+rakw,raky+10));
   end;
  end;
 end;

 太字の部分は,Timer1Timerイベントハンドラのどこに書いても大丈夫だと思いますが,場所によって表示に少し変化が出てくるかもしれません。
 
 
 ここまで記述して,実行してみると,カーソルキーでラケットが動き,ラケットでボールをはじき返すことが確認できたと思います。しかし今現在次のような問題があります。
 @ ボールがラケットに当たらなくても,フォームの下ではね返ってくる。
 A ボールがラケットの横に当たったとき,ボールが奇妙な動きをする。
 
 @については,これから直していきます。
 Aは,今のところ,ラケットの横に当たったときのプログラムを書いていませんので,当たり前と言えば当たり前です。

まとめ

 今までのプログラムをまとめてみます。

 type
 TForm1 = class(TForm)
  Image1: TImage;
  Timer1: TTimer;
  procedure FormCreate(Sender: TObject);
  procedure Timer1Timer(Sender: TObject);
  procedure Image1Click(Sender: TObject);
  procedure FormKeyDown(Sender: TObject; var Key: Word;
   Shift: TShiftState);
  procedure FormKeyUp(Sender: TObject; var Key: Word;
   Shift: TShiftState);
  private
   { Private 宣言 }
   ballx,bally,bx,by,balls:integer;
   rakx,raky,rakw,keyd:integer; //←これを記述
  public
   { Public 宣言 }
 end;
 
 var
  Form1: TForm1;
 
 implementation
 
 {$R *.dfm}
 
 procedure TForm1.FormCreate(Sender: TObject);
 begin
  //フォームの大きさを決める
  form1.ClientWidth:=400;
  form1.ClientHeight:=500;
  //フォームの大きさに合わせてImageコンポーネントを設置する
  image1.Left:=0;
  image1.Top:=0;
  image1.Width:= form1.ClientWidth;
  image1.Height:= form1.ClientHeight;
  //ボールの設計
  rakx:=200;
  raky:=450;
  rakw:=50;
  //Imageに描く
  with image1.Canvas do
  begin
   //背景
   brush.Color:=clblack;
   fillrect (image1.Canvas.ClipRect);
   //ラケットを描く
   brush.Color:=clwhite;
   fillrect(rect(rakx,raky,rakx+rakw,raky+10));
  end;
 end;
 
 procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
 begin
  //[→]キーが押されたとき
  if key=VK_right then keyd:=4;
  //[←]キーが押されたとき
  if key=VK_left then keyd:=-4;
 end;
 
 procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
 begin
  //キーが上げられたとき
  keyd:=0;
 end;
 
 procedure TForm1.Image1Click(Sender: TObject);
 begin
  ballx:=200;
  bally:=300;
  bx:=3;
  by:=-6;
  balls:=6;
  timer1.Enabled:=true;
 end;
 
 procedure TForm1.Timer1Timer(Sender: TObject);
 begin
  //ボールがあった部分を黒く塗る
  with image1.Canvas do
  begin
   brush.Color:=clblack;
   fillrect(rect(ballx, bally,ballx+balls,bally+balls));
  end;
  //ボールの新しい座標を求める
  if (ballx<=0) or (ballx>=image1.Width-balls) then bx:=-bx;
  ballx:=ballx+bx;
  if (bally<=0) or (bally>=image1.Height-balls) then by:=-by;
  bally:=bally+by;
  //ボールがラケットに当たったか調べる
  if bally>=raky-balls then
  begin
   if (ballx>=rakx) and (ballx<=rakx+rakw) then by:=-by;
  end;
  //新たな位置にボールを描く
  with image1.Canvas do
  begin
   brush.Color:=clwhite;
   fillrect(rect(ballx, bally,ballx+balls,bally+balls));
  end;
  //ラケットを動かす
  if keyd<>0 then
  begin
   with image1.Canvas do
   begin
    brush.Color:=clblack;
    fillrect(rect(rakx,raky,rakx+rakw,raky+10));
    rakx:=rakx+keyd;
    brush.Color:=clwhite;
    fillrect(rect(rakx,raky,rakx+rakw,raky+10));
   end;
  end;
 end;
 
end.

−トップへ−