自機から爆弾を投下してミサイルや燃料タンクを破壊します。Xキーを押すと爆弾が投下されます。実際の処理はStageクラスのJikiBomb()メソッド(後述)にやらせます。
Form1.Bomb()は自機から爆弾を投下するためのメソッドです。
1 2 3 4 5 6 7 |
public partial class Form1 : Form { void Bomb() { Stage.JikiBomb(); } } |
Bombクラス
Bombクラスは爆弾を描画する位置を記憶したり移動させるためのクラスです。爆弾の落下軌道はプロパティで管理します。
爆弾が敵や地形に命中したらフィールド変数 isDeadをtrueにします。爆弾としては存在しないものなので移動や描画対象から外します。
それから爆弾は弾丸とちがって同じ速度で同じ方向に飛ぶわけではありません。Move()メソッドが呼び出される回数で移動方向を変えています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
class Bomb { static public float JikiBombSpeed = 0.2f; public bool isDead = false; public Bomb(float x, float y) { X = x; Y = y; } public float X { get; private set; } = 0; public float Y { get; private set; } = 0; int timeCount = 0; public void Move() { if(isDead) return; timeCount++; if(timeCount < 4) X += Form1.ScrollSpeed * 2; else X += Form1.ScrollSpeed; Y -= JikiBombSpeed; } public void Draw() { if(isDead) return; GL.PushMatrix(); { GL.Translate(X, Y, 0); GL.Color3(Color.White); GL.Begin(BeginMode.Quads); { GL.Vertex3(0.1, 0.1, 0); GL.Vertex3(0.1, -0.1, 0); GL.Vertex3(-0.1, -0.1, 0); GL.Vertex3(-0.1, 0.1, 0); } GL.End(); } GL.PopMatrix(); } public RectangleF DeadRectangleF() { float x = X - 0.1f; float y = Y - 0.1f; float width = 0.2f; float height = 0.2f; return new RectangleF(x, y, width, height); } } |
爆弾を投下する処理
実際に爆弾を投下する処理はStageクラスでおこないます。Bombオブジェクトを格納するリストとしてBombsを作成します。連続投下は2個までとして0.5秒開けることにします。最初に爆弾が出現する場所はGetBombStartPosition()メソッドで決めます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
public class Stage { List<Bomb> Bombs = new List<Bomb>(); public void JikiBomb() { if(CanBomb()) { Position position = Jiki.GetBombStartPosition(); Bomb bomb = new Bomb(position.X, position.Y); Bombs.Add(bomb); } } public bool CanBomb() { Console.WriteLine(Bombs.Count); if(Bombs.Count == 0) return true; // 同時に投下できるのは2発まで if(Bombs.Count > 1) return false; if(bombTime.Ticks < DateTime.Now.Ticks - 5 * 1000 * 1000) return true; else return false; } public Position GetBombStartPosition() { return new Position(X + 1f, Y - 0.5f); } } |
爆弾の移動と当たり判定
タイマーによってUpdate()メソッドが呼び出されたら、UpdateBombsPosition()メソッドで爆弾の表示位置の変更し、GetObjectsHitBomb()メソッドで爆弾が敵に命中したかを調べます。
何かに命中した爆弾や画面下まで到達した爆弾(地面に必ず当たるので画面下に到達することはないはずだが・・・)はBombs内から取り除きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
public class Stage { public void Update() { UpdateJikiPosition(); UpdateMissilesPosition(); UpdateBulletsPosition(); GetObjectsHitBullet(); UpdateBombsPosition(); GetObjectsHitBomb(); } void UpdateBombsPosition() { foreach(Bomb bomb in Bombs) bomb.Move(); } void GetObjectsHitBomb() { // 地面に当たった爆弾を取り除く RemoveBombsHitBlock(); // 画面下に到達した爆弾を取り除く Bombs = Bombs.Where(x => !x.isDead && x.Y > - Form1.ProjectionHeight / 2).ToList(); // 爆弾が命中した敵(いまのところミサイルだけだが・・・)のリストを取得する List<Missile> bombMissiles = GetMissilesHitBomb(); } // 地面に当たった爆弾を取り除く void RemoveBombsHitBlock() { List<Block> blocks = GetTestBlocks(); foreach(Bomb bomb in Bombs) { RectangleF rect1 = bomb.DeadRectangleF(); if(blocks.Any(x => IsPiledRectange(rect1, x.DeadRectangleF()))) bomb.isDead = true; } Bombs = Bombs.Where(x => !x.isDead).ToList(); } // 爆弾が命中したミサイルのリストを取得する List<Missile> GetMissilesHitBomb() { List<Missile> ret = new List<Missile>(); List<Missile> missiles = Missiles.Where(x => !x.isDead).ToList(); foreach(Bomb bomb in Bombs) { RectangleF rect = bomb.DeadRectangleF(); Missile missile = missiles.FirstOrDefault(x => IsPiledRectange(rect, x.DeadRectangleF())); if(missile != null) { missile.isDead = true; bomb.isDead = true; ret.Add(missile); } } Bombs = Bombs.Where(x => !x.isDead).ToList(); return ret; } } |
爆弾の描画
描画の処理です。Draw()メソッド内で、Bombs内に残っている爆弾を描画します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class Stage { public void Draw() { DrawGround(); foreach(Missile missile in Missiles) missile.Draw(); foreach(Bullet bullet in Bullets) bullet.Draw(); foreach(Bomb bomb in Bombs) bomb.Draw(); Jiki.Draw(); } } |
爆弾命中時のスコアの変化
爆弾が命中したらスコアを加算し表示させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class AddScoreArgs : EventArgs { public AddScoreArgs(int score) { Score = score; } public int Score { get; private set; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public class Stage { // 得点のイベント public delegate void AddScoreHandler(object sender, AddScoreArgs e); public event AddScoreHandler AddScore; // 地上に置かれているミサイルは50点、飛行中のミサイルは80点を加算する void AddScoreHitMissile(List<Missile> hitMissiles) { foreach(Missile missile in hitMissiles) { AddScoreArgs args = null; if(missile.isMove) args = new AddScoreArgs(80); else args = new AddScoreArgs(50); AddScore?.Invoke(this, args); } } void GetObjectsHitBullet() { RemoveBulletsHitBlock(); Bullets = Bullets.Where(x => !x.isDead && x.X < Form1.GetEyeX() + Form1.ProjectionWidth / 2).ToList(); List<Missile> hitMissiles = GetMissilesHitBullet(); AddScoreHitMissile(hitMissiles); } void GetObjectsHitBomb() { RemoveBombsHitBlock(); Bombs = Bombs.Where(x => !x.isDead && x.Y > - Form1.ProjectionHeight / 2).ToList(); List<Missile> bombMissiles = GetMissilesHitBomb(); AddScoreHitMissile(bombMissiles); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class AddScoreArgs : EventArgs { public AddScoreArgs(int score) { Score = score; } public int Score { get; private set; } } |
得点のイベントが発生したらスコアを更新します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); timer.Tick += Timer_Tick; TimerIntervalReset(); // スコアの初期化 InitScore(); } void InitScore() { labelScore.BackColor = Color.Black; labelScore.ForeColor = Color.White; Score = 0; Stage.AddScore += Stage_AddScore; } private void Stage_AddScore(object sender, AddScoreArgs e) { Score += e.Score; } int _score = 0; int Score { get { return _score; } set { _score = value; labelScore.Text = String.Format("Score {0:000000}", _score); } } } |