スクランブルもどきに燃料計を表示させます。
スクランブルには燃料計があります。燃料がなくなると墜落してしまいます。燃料切れを回避するためには敵の燃料タンクを破壊して補給する必要があります(破壊すると燃料が炎上して補給にならないような気がするのだが・・・)。
そこで今回は燃料計と燃料タンクを作成します。
まず燃料計を表示させます。コンストラクタ内でInitFuel()を実行して燃料計の初期化をおこないます。表示の初期化だけでなく燃料が増加するときのイベント(後述)も処理できるようにしておきます。燃料の最大値は70とします。
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 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); FormSizeFix(); timer.Tick += Timer_Tick; TimerIntervalReset(); this.BackColor = Color.Black; InitScore(); InitFuel(); } void InitFuel() { labelFuel.BackColor = Color.Black; labelFuel.ForeColor = Color.White; labelFuel.Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right; pictureBoxFuel.Anchor = AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right; pictureBoxFuel.BackColor = Color.Blue; pictureBoxFuel.Paint += PictureBoxFuel_Paint; Stage.AddFuel += Stage_AddFuel; // 燃料増加のイベント(後述) Fuel = FuelMax; } // 現在の燃料を表示するプロパティ int _fuel = 0; int Fuel { get { return _fuel; } set { _fuel = value; if(_fuel <= 0) _fuel = 0; if(_fuel >= FuelMax) _fuel = FuelMax; pictureBoxFuel.Invalidate(); } } private void Stage_AddFuel(object sender, AddFuelArgs e) { Fuel += e.Value; } } |
自機は飛行することで燃料を消費します。そして燃料が0になると墜落し始めます。
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 |
public partial class Form1 : Form { const int FuelMax = 70; void GameStart() { TimerIntervalReset(); EyeX = 0; EyeY = 0; Stage.Jiki.IsShow = true; Stage.Jiki.SetStartPosition(); // 燃料は満タンの状態で開始する Fuel = FuelMax; Stage.Init(); timer.Start(); } private void Timer_Tick(object sender, EventArgs e) { EyeX += ScrollSpeed; Stage.Update(); // 飛行1秒につき10点 AddCcoreByFlight(); // 飛行することで燃料が消費される UseFuel(); } glControl1.Refresh(); } // 1秒間の飛行につき10点加算 int tickCountFly = 0; void AddCcoreByFlight() { tickCountFly++; if(tickCountFly > 1000 / timer.Interval) { tickCountFly = 0; Score += 10; } } // 燃料の消費 int tickCountFuel = 0; int mileage = 10; // 燃費(この値を下げると燃費が悪くなる) void UseFuel() { tickCountFuel++; if(tickCountFuel > mileage) { tickCountFuel = 0; Fuel--; // 燃料が0になると墜落し始める // ただしそのあと燃料が1以上に増えた場合は墜落状態から復帰する if(Fuel <= 0) Stage.IsFalling = true; else Stage.IsFalling = false; } } } |
ステージクラスのUpdateJikiPosition()メソッド内でIsFallingフラグをチェックして墜落処理が必要なときはそのための処理をしています。墜落中は操作ができず機体の高度がだんだん下がっていきます(ただしここでは地上との当たり判定の処理をしていないので画面下に消えていく・・・)。
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 |
public class Stage { public bool IsFalling = false; void UpdateJikiPosition() { if(IsFalling) { Jiki.Move(Form1.ScrollSpeed, -0.15f); return; } Direct direct = Form1.CurDirect; if(direct == Direct.Up) Jiki.Move(0, 0.5f); if(direct == Direct.Down) Jiki.Move(0, -0.5f); if(direct == Direct.Accelerate) Jiki.Move(0.5f, 0); // 通常の飛行 if(Jiki.X <= Form1.GetEyeX() + Jiki.startX) Jiki.Move(Form1.ScrollSpeed, 0); } } |
それでは燃料補給の鍵となる燃料タンクを表示させましょう。まずFuelTankクラスを作ります。
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 |
class FuelTank { public float X = 0f; public float Y = 0f; public bool isDead = false; public FuelTank(float x, float y) { X = x; Y = y; } public void Draw() { if(isDead) return; GL.PushMatrix(); { GL.Translate(X, Y, 0); GL.Color3(Color.White); GL.BindTexture(TextureTarget.Texture2D, Form1.FuelTankTexture); GL.Begin(BeginMode.Quads); { GL.TexCoord2(1, 1); GL.Vertex3(0.5, 0.5, 0.1); GL.TexCoord2(1, 0); GL.Vertex3(0.5, -0.5, 0.1); GL.TexCoord2(0, 0); GL.Vertex3(-0.5, -0.5, 0.1); GL.TexCoord2(0, 1); GL.Vertex3(-0.5, 0.5, 0.1); } GL.End(); GL.BindTexture(TextureTarget.Texture2D, 0); } GL.PopMatrix(); } public RectangleF DeadRectangleF() { float x = X - 0.5f; float y = Y - 0.5f; float width = 1f; float height = 1f; return new RectangleF(x, y, width, height); } } |
次にStageクラスのInit()メソッドに燃料タンクに関する処理を追加します。
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 |
public class Stage { public bool Init() { // マップデータの初期化 ClearMap(); // マップを記述したテキストファイルを読み込む処理 List<string> Blocks = LoadMapFile(); if(Blocks == null) return false; int countY = 0; float x = Form1.ProjectionWidth / 2; float y = Form1.ProjectionHeight / 2; foreach(string str in Blocks) { Char[] vs = str.ToArray(); int countX = 0; foreach(Char char1 in vs) { // マップを記述したテキストのなかに「F」があれば、それが燃料タンク if(char1 == 'F') FuelTanks.Add(new FuelTank(BlockAspect * countX - x, countY - y)); // 以下は前回と同じなので省略 // ステージの境界線を見つけたら保存する // if(char1 == '1') // if(char1 == '2') // if(char1 == '3') // if(char1 == '4') // if(char1 == '5') // if(char1 == '6') // 地形に関する情報 // if(char1 == '■') // if(char1 == '▲') // if(char1 == '△') // if(char1 == '▼') // if(char1 == '▽') // if(char1 == '●') // ミサイルの初期位置 // if(char1 == 'M') // Missiles.Add(new Missile(BlockAspect * countX - x, countY - y)); countX++; } countY++; } return true; } void ClearMap() { Type1s = new List<Block>(); Type2s = new List<Block>(); Type3s = new List<Block>(); Type4s = new List<Block>(); Type5s = new List<Block>(); Missiles = new List<Missile>(); FuelTanks = new List<FuelTank>(); } public void Draw() { DrawGround(); foreach(Missile missile in Missiles) missile.Draw(); foreach(FuelTank fuelTank in FuelTanks) fuelTank.Draw(); foreach(Bullet bullet in Bullets) bullet.Draw(); foreach(Bomb bomb in Bombs) bomb.Draw(); Jiki.Draw(); } } |
上記の処理で燃料タンクを描画することができるようになりましたが、破壊することができません。自機から発射された弾丸や投下された爆弾が命中したら燃料が破壊され、燃料が補給されるようにしましょう。
GetObjectsHitBullet()とGetObjectsHitBomb()メソッドに弾丸と爆弾が命中した燃料タンクを取得する処理を追加します。
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 Stage { void GetObjectsHitBullet() { RemoveBulletsHitBlock(); Bullets = Bullets.Where(x => !x.isDead && x.X < Form1.GetEyeX() + Form1.ProjectionWidth / 2).ToList(); List<Missile> hitMissiles = GetMissilesHitBullet(); AddScoreHitMissile(hitMissiles); // 弾丸は燃料タンクに命中したか? List<FuelTank> hitFuelTanks = GetFuelTanksHitBullet(); // 命中したものが見つかれば加点処理 AddScoreHitFuelTank(hitFuelTanks); } void GetObjectsHitBomb() { RemoveBombsHitBlock(); Bombs = Bombs.Where(x => !x.isDead && x.Y > - Form1.ProjectionHeight / 2).ToList(); List<Missile> bombMissiles = GetMissilesHitBomb(); AddScoreHitMissile(bombMissiles); // 爆弾は燃料タンクに命中したか? List<FuelTank> bombFuelTanks = GetFuelTanksHitBomb(); // 命中したものが見つかれば加点処理 AddScoreHitFuelTank(bombFuelTanks); } 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); } } // 命中した弾丸はリストから取り除く Bullets = Bullets.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); } } // 命中した爆弾はリストから取り除く Bombs = Bombs.Where(x => !x.isDead).ToList(); return ret; } } |
燃料タンクに命中した場合は得点と燃料補給のイベントを発生させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Stage { void AddScoreHitFuelTank(List<FuelTank> hitFuelTanks) { foreach(FuelTank fuelTank in hitFuelTanks) { // 得点と燃料補給のイベントを発生させる // 150点加算。燃料は10回復する AddScore?.Invoke(this, new AddScoreArgs(150)); AddFuel?.Invoke(this, new AddFuelArgs(10)); } } public delegate void AddFuelHandler(object sender, AddFuelArgs e); public event AddFuelHandler AddFuel; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class AddFuelArgs : EventArgs { public AddFuelArgs(int value) { Value = value; } public int Value { get; private set; } } |