ブロックくずしゲームを作る
その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
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.