自機から弾丸を発射してミサイルや燃料タンクを破壊します。Zキーを押すと弾丸が発射されます。実際の処理はStageクラスのJikiShot()メソッド(後述)にやらせます。

Form1.Shot()は自機から弾丸を発射するためのメソッドです。

Bulletクラスは弾丸を描画の位置を記憶したり移動したり描画するためのクラスです。弾丸の飛行速度はフィールド変数で、位置はプロパティで管理します。

フィールド変数 IsDeadは敵や地形に命中したらtrueにします。これは弾丸としては存在しないものなので移動や描画対象から外します。

StageクラスのJikiShot()メソッドが呼び出されたら弾丸の初期位置を決めてBulletオブジェクトを生成します。弾丸の初期位置はJikiクラスのGetBuletStartPosition()メソッドで求めます。この部分は自機の先端部分になります。

生成されたBulletクラスのインスタンスはBulletのリスト Bulletsに格納します。

StageクラスのUpdate()内で自機から発射された弾丸を前方へ移動させます。そしてDraw()でこれを描画します。

当たり判定も必要です。当たったかどうかは弾丸の矩形内に敵や地形が入ったかどうかで判定します。IsPiledRectangeメソッドは二つの矩形は重なっているかを調べて重なっている場合はtrueを返します。

各クラスに弾丸やミサイルの当たり判定のための矩形を求めるメソッド DeadRectangleF()を加えます。

当たり判定はStageクラスのUpdate()メソッドのなかでやればいいのですが、今後あれこれ追加すると長くなるかもしれないので分けました。

最後のGetObjectsHitBullet()メソッドが発射した弾丸が命中した敵(敵はミサイルだけではない)のリストを返します。

GetObjectsHitBullet()メソッドを実行すれば、弾丸が命中した敵を取得することができます。この結果は点数計算をするときに必要になります。この処理を実行する前に、実行時に弾丸のなかで他のオブジェクトに命中したものや、右方向に飛んで画面上に存在しないものは取り除いています。

RemoveBulletsHitBlock()メソッドは地面に当たった弾丸を取り除きます。すべてのブロックについて調べる必要はありません。はるか右側にある見えないブロックやすでに通り過ぎた位置にあるブロックは調べる必要はありません。GetTestBlocks()メソッドで本当に調べる必要があるものだけ調べています。

GetMissilesHitBullet()メソッドは自機から発射された弾丸が命中したミサイルのオブジェクトを返します(同じタイミングで複数のミサイルを撃墜できるのは現実的にはなさそうですが・・・)。

それから無制限に連射ができてしまうとゲームの難度が下がってしまうので、最後に発射された弾丸のX座標と自機のX座標にForm1.ProjectionWidthの3分の1以上の差ができないと弾丸を発射できないようにしました。

これでミサイルを撃墜することができるようになりました。スクランブルではまっすぐ前に飛ぶ弾丸の他に爆弾を投下して地上の敵を倒すことができます。次回は爆弾投下の機能を追加します。