C# OpenTKでスクランブルのようなゲームを作成しています。
これまで爆発の描画がありませんでした。弾丸が命中しても爆発なしというのはよくないので爆発の描画をおこないます。
爆発のパターンは2種類あり、最初に爆発させた時間でどちらを描画するかを切り分けます。8回描画して9回目以降は描画しません。
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 71 72 73 |
public class Explosion { public Explosion(double x, double y, double width, double height) { X = x; Y = y; Width = width; Height = height; } public double X { get; private set; } public double Y { get; private set; } public double Width { get; private set; } public double Height { get; private set; } public bool isDead = false; int i = 0; public void Draw() { i++; if(i == 9) { isDead = true; return; } GL.PushMatrix(); { GL.Translate(X, Y, 0); GL.Color3(Color.White); if(i < 4) GL.BindTexture(TextureTarget.Texture2D, Form1.ExplosionTexture1); else GL.BindTexture(TextureTarget.Texture2D, Form1.ExplosionTexture2); GL.Begin(BeginMode.Quads); { GL.TexCoord2(1, 1); GL.Vertex3(0.5 * Width, 0.5 * Height, 0.5); GL.TexCoord2(1, 0); GL.Vertex3(0.5 * Width, -0.5 * Height, 0.5); GL.TexCoord2(0, 0); GL.Vertex3(-0.5 * Width, -0.5 * Height, 0.5); GL.TexCoord2(0, 1); GL.Vertex3(-0.5 * Width, 0.5 * Height, 0.5); } GL.End(); GL.BindTexture(TextureTarget.Texture2D, 0); } GL.PopMatrix(); } } |
爆発の描画が必要なのは
投下された爆弾が地面や敵に命中したとき
発射された弾丸が敵に命中したとき
自機が敵と接触したときや墜落をしたとき
です。
Explosionオブジェクトを格納するリストを作成して、Draw()メソッドが呼び出されたときに描画をおこないます。爆発の描画が終わったオブジェクトはリストのなかから取り除かれます。
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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
public class Stage { // 投下された爆弾が地面に命中したとき 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; Explosions.Add(new Explosion(bomb.X, bomb.Y, 0.5, 0.5)); } } 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); Explosions.Add(new Explosion(missile.X, missile.Y, 0.5, 0.5)); } } Bombs = Bombs.Where(x => !x.isDead).ToList(); return ret; } // 投下された爆弾が燃料タンクに命中したとき List<FuelTank> GetFuelTanksHitBomb() { List<FuelTank> ret = new List<FuelTank>(); List<FuelTank> fuelTanks = FuelTanks.Where(x => !x.isDead).ToList(); foreach(Bomb bomb in Bombs) { RectangleF rect = bomb.DeadRectangleF(); FuelTank fuelTank = fuelTanks.FirstOrDefault(x => IsPiledRectange(rect, x.DeadRectangleF())); if(fuelTank != null) { // 投下された爆弾は燃料タンクに命中した fuelTank.isDead = true; bomb.isDead = true; ret.Add(fuelTank); Explosions.Add(new Explosion(fuelTank.X, fuelTank.Y, 0.5, 0.5)); } } Bombs = Bombs.Where(x => !x.isDead).ToList(); return ret; } // 投下された爆弾がUFOに命中したとき List<UFO> GetUFOsHitBomb() { List<UFO> ret = new List<UFO>(); if(Form1.GetEyeX() < 120 || Form1.GetEyeX() > 270) return ret; List<UFO> ufos = UFOs.Where(x => !x.isDead).ToList(); foreach(Bomb bomb in Bombs) { RectangleF rect = bomb.DeadRectangleF(); UFO ufo = ufos.FirstOrDefault(x => IsPiledRectange(rect, x.DeadRectangleF())); if(ufo != null) { // 投下された爆弾はUFOに命中した ufo.isDead = true; bomb.isDead = true; ret.Add(ufo); Explosions.Add(new Explosion(ufo.X, ufo.Y, 0.5, 0.5)); } } Bombs = Bombs.Where(x => !x.isDead).ToList(); return ret; } // 発射された弾丸がミサイルに命中したとき List<Missile> GetMissilesHitBullet() { List<Missile> ret = new List<Missile>(); List<Missile> missiles = Missiles.Where(x => !x.isDead).ToList(); foreach(Bullet bullet in Bullets) { RectangleF rect = bullet.DeadRectangleF(); Missile missile = missiles.FirstOrDefault(x => IsPiledRectange(rect, x.DeadRectangleF())); if(missile != null) { // 発射された弾丸はミサイルに命中した missile.isDead = true; bullet.isDead = true; ret.Add(missile); Explosions.Add(new Explosion(missile.X, missile.Y, 0.5, 0.5)); } } Bullets = Bullets.Where(x => !x.isDead).ToList(); return ret; } // 発射された弾丸が燃料タンクに命中したとき List<FuelTank> GetFuelTanksHitBullet() { List<FuelTank> ret = new List<FuelTank>(); List<FuelTank> fuelTanks = FuelTanks.Where(x => !x.isDead).ToList(); foreach(Bullet bullet in Bullets) { RectangleF rect = bullet.DeadRectangleF(); FuelTank fuelTank = fuelTanks.FirstOrDefault(x => IsPiledRectange(rect, x.DeadRectangleF())); if(fuelTank != null) { // 発射された弾丸は燃料タンクに命中した fuelTank.isDead = true; bullet.isDead = true; ret.Add(fuelTank); Explosions.Add(new Explosion(fuelTank.X, fuelTank.Y, 0.5, 0.5)); } } Bullets = Bullets.Where(x => !x.isDead).ToList(); return ret; } // 発射された弾丸がUFOに命中したとき List<UFO> GetUFOsHitBullet() { List<UFO> ret = new List<UFO>(); if(Form1.GetEyeX() < 120 || Form1.GetEyeX() > 270) return ret; List<UFO> ufos = UFOs.Where(x => !x.isDead).ToList(); foreach(Bullet bullet in Bullets) { RectangleF rect = bullet.DeadRectangleF(); UFO ufo = ufos.FirstOrDefault(x => IsPiledRectange(rect, x.DeadRectangleF())); if(ufo != null) { // 発射された弾丸はUFOに命中した ufo.isDead = true; bullet.isDead = true; ret.Add(ufo); Explosions.Add(new Explosion(ufo.X, ufo.Y, 0.5, 0.5)); } } Bullets = Bullets.Where(x => !x.isDead).ToList(); return ret; } public void Draw() { DrawGround(); foreach(Missile missile in Missiles) missile.Draw(); foreach(FuelTank fuelTank in FuelTanks) fuelTank.Draw(); foreach(UFO ufo in UFOs) ufo.Draw(); foreach(Fireball fireball in Fireballs) fireball.Draw(); foreach(Bullet bullet in Bullets) bullet.Draw(); foreach(Bomb bomb in Bombs) bomb.Draw(); Explosions = Explosions.Where(x => !x.isDead).ToList(); foreach(Explosion explosion in Explosions) explosion.Draw(); Jiki.Draw(); } } |
自機が敵と接触するとタイマーを停止しているのでミス時は他の方法で再描画をし続けるための手段を用意しないと自機爆発の描画はされません。そこで別のタイマーをセットします。
まずミス時には自機の爆発オブジェクトを生成します。接触した敵も死亡フラグをセットして爆発させます。
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 |
public class Stage { bool IsDead() { RectangleF deadRect = Jiki.DeadRectangleF(); // 地面に接触または墜落 List<Block> blocks = GetTestBlocks(); Block block = blocks.FirstOrDefault(x => IsPiledRectange(deadRect, x.DeadRectangleF())); if(block != null) { Explosions.Add(new Explosion(Jiki.X, Jiki.Y, 2.0, 0.5)); return true; } // ミサイルに接触 Missile missile = Missiles.FirstOrDefault(x => !x.isDead && IsPiledRectange(deadRect, x.DeadRectangleF())); if(missile != null) { Explosions.Add(new Explosion(Jiki.X, Jiki.Y, 2.0, 0.5)); Explosions.Add(new Explosion(missile.X, missile.Y, 0.5, 0.5)); missile.isDead = true; return true; } // 燃料タンクに接触 FuelTank fuelTank = FuelTanks.FirstOrDefault(x => !x.isDead && IsPiledRectange(deadRect, x.DeadRectangleF())); if(fuelTank != null) { Explosions.Add(new Explosion(Jiki.X, Jiki.Y, 2.0, 0.5)); Explosions.Add(new Explosion(fuelTank.X, fuelTank.Y, 0.5, 0.5)); fuelTank.isDead = true; return true; } // UFOに接触 List<UFO> ufos = UFOs.Where(x => !x.isDead && IsInSight(x.X, x.Y)).ToList(); UFO ufo = ufos.FirstOrDefault(x => IsPiledRectange(deadRect, x.DeadRectangleF())); if(ufo != null) { Explosions.Add(new Explosion(Jiki.X, Jiki.Y, 2.0, 0.5)); Explosions.Add(new Explosion(ufo.X, ufo.Y, 0.5, 0.5)); ufo.isDead = true; return true; } // ファイアボールと接触 Fireball fireball = Fireballs.FirstOrDefault(x => !x.isDead && IsPiledRectange(deadRect, x.DeadRectangleF())); if(fireball != null) { Explosions.Add(new Explosion(Jiki.X, Jiki.Y, 2.0, 0.5)); return true; } return false; } } |
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 |
public partial class Form1 : Form { void Miss() { // ミスをしたらタイマーを止める timer.Stop(); // 別のタイマーをセット Timer t = new Timer(); t.Interval = 60; t.Tick += T_Tick; t.Start(); Rest--; if(Rest == 0) { GameOver(); return; } // 一定期間経過後、ゲーム再開 Timer restartTimer = new Timer(); restartTimer.Interval = 3000; restartTimer.Tick += RestartTimer_Tick; restartTimer.Start(); } // ミス時からゲーム再開時まで自機爆発の描画をさせる int T_Tick_Count = 0; private void T_Tick(object sender, EventArgs e) { T_Tick_Count++; glControl1.Refresh(); if(T_Tick_Count > 8) { Timer t = (Timer)sender; t.Stop(); t.Dispose(); T_Tick_Count = 0; } } } |