今回は敵をつくり当たり判定を取ります。
このゲームは一応「避けゲー」にする予定なので敵を作らなければなりません。敵をつくりましょう。
まず、zikiを作った時と同じように「teki」という名のTImageを用意して画像を読み込んでください。とりあえずこれで敵が表示されました。
とりあえず此処までは楽勝ですが、ここからちょっと難しいお話になります。当たり判定のとり方は結構頭を使うのでがんばってください。
zikiとtekiが当たったとき、「当たったよ」といって終了するプログラムを書いてみましょう。
今回使うのは四角形同士の当たり判定です。四角形同士の当り判定はたぶん一番使われる当り判定だと思います(2Dでは)。軽いし使いやすいし。マスターしましょう。
四角形同士の当たり判定をとる時には、中心間の距離を考えます。二つの四角形が
こんな状態になった時、Aの中心のX座標とBの中心のX座標間はAの横幅の半分+Bの横幅の半分以下になっています。これをX座標とY座標の両方で行えば当たり判定ができます。
Topは上端の座標なので、中心を出す際にはHeightの半分を足さなければならないことに注意です。実装してみましょう。ちなみに「Abs」は絶対値を返す関数です。
///andを使用しないのは軽量化の為です。
with teki do
begin
if (Abs((Ziki.Left + Ziki.Width / 2) - (Left + Width / 2) ) <= (Ziki.Width + Width) / 2) then
if (Abs((Ziki.Top + Ziki.Height / 2) - (Top + height / 2) ) <= (Ziki.Height + Height) / 2) then
begin
ShowMessage('あたったよ〜');
Form1.Close;///Form1.Closeでプログラムが終了します。
end;
end;
これで、全く動かない敵にあたるとプログラムが終了するようになりました。
正直敵が動かないとゲームとして成り立たないので敵を動かしましょう。
どのような動きをつけるかは貴方が自由に選んで結構ですが、とりあえずZikiのDxとDyにあたるものが必要なので、
{$R *.dfm}
var
Dx,Dy:Extended;
TDx,TDy:Extended;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
///Ziki動かす
with ziki do
begin
if GetKeyState(VK_Up) < 0 then Dy:=Dy - 5;
if GetKeyState(VK_Down) < 0 then Dy:=Dy + 5;
if GetKeyState(VK_Left) < 0 then Dx:=Dx - 5;
if GetKeyState(VK_Right) < 0 then Dx:=Dx + 5;
if (top + Dy < 0) and (Dy < 0) then Dy:=0;
if (top + Dy > form1.height - height) and (Dy > 0) then Dy:=0;
if (left + Dx < 0) and (Dx < 0) then Dx:=0;
if (left + Dx > form1.Width - Width) and (Dx > 0) then Dx:=0;
end;
//Teki動かす
with Teki do
begin
(*****ここに敵の動きを書く******)
if (top + TDy < 0) and (TDy < 0) then TDy:=0;
if (top + TDy > form1.height - height) and (TDy > 0) then TDy:=0;
if (left + TDx < 0) and (TDx < 0) then TDx:=0;
if (left + TDx > form1.Width - Width) and (TDx > 0) then TDx:=0;
end;
//Ziki予測代入
with Ziki do
begin
Top :=Top + Trunc(Dy);
Left:=Left+ Trunc(Dx);
Dx:=Frac(Dx);
Dy:=Frac(Dy);
end;
//Teki予測代入
with Teki do
begin
Top :=Top + Trunc(TDy);
Left:=Left+ Trunc(TDx);
TDx:=Frac(TDx);
TDy:=Frac(TDy);
end;
end;
とだけ書きましょう。いやあ、with文を使ってるとほぼ丸コピーですんじゃうんで楽ですねえ。
Zikiの予測の代入の位置が結構変わってますが、これは最後にやった方がバグが少なくなるし便利です。
敵の動きは自由につけちゃっていいです。といってもいきなりそんなこと言われると困っちゃう人もいるみたいなので、ある程度の敵の動きの種類を此処に書いておきます。
TDx:=TDx + 5
とでも書いとけばOKです。
右端に当たってとまる、悲しい動き。
TDx:=TDx + Random(5)-2;
TDy:=TDy + Random(5)-2;
とんでもない動きをします。これはこれで楽しいかも?Random(5)-2というのに注意。
TDx:=-Ziki.Dx;
TDy:=-Ziki.Dy;
なんかゼ●ダの伝説夢をみる島でこんな敵キャラいたよね。
ウィンドウのの右端に当たるまで右移動、当たったら左移動、今度は左端に当たったら右移動…といった感じで。
これはほかのと違って「ウィンドウを飛び出さない判定」のところもちょっと変えます。ちょっと難しめ?
with Teki do
begin
///TagプロパティについてはLevel0を読めば良いと思うよ。
///此処ではTeki.Tagを「移動してる向き」として使ってます。0未満は左で0以上は右。
if Tag < 0 then TDx:=Dx - 5
else TDx:=Dx + 5;
if (top + TDy < 0) and (TDy < 0) then TDy:=0;
if (top + TDy > form1.height - height) and (TDy > 0) then TDy:=0;
if (left + TDx < 0) and (TDx < 0) then
begin
TDx:=0;
Tag:=1;///右向きにする
end;
if (left + TDx > form1.Width - Width) and (TDx > 0) then
begin
TDx:=0;
Tag:=-1;///左向きにする
end;
end;
上下左右試してみるとおもしろいかも。
こっから先はちょっと難しいお話です。三角関数がわかってる人向けに話すので、特に説明もしません。わからなかったら飛ばしてOKです。
予めVar a:Extended;
としておいてくださいな。
a:=a + 0.3;
TDy:=TDy + Sin(a) * 100; //100は波の幅、
TDx:=TDx + 3;///ヨコに動かす
プログラム5行目くらいにuses Windows, Messages,
--中略--Forms,Dialogs,Math;
と追加しておいてください。
これも予めVar a:Extended;
としておいてくださいな。
a:=ArcTan2(Top - Ziki.Top,Left - Ziki.Left);
TDy:=TDy + Sin(a) * 5;
TDx:=TDx + Cos(a) * 5
TDy + Sin(a) * 5
の符号を変えれば向きがかわるよ。