チェックポイントを通過すると点数が増え、レッドカーと接触したらミスとなります。当たり判定と点数計算の処理をおこないます。
レッドカーとの接触を判定するのであれば両者の距離が1.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 |
public partial class Form1 : Form { private void Timer_Tick(object sender, EventArgs e) { MoveMyCar(); MoveRedCars(); JudgeContactRedCar(); glControl1.Refresh(); panelRadar.Invalidate(); } bool JudgeContactRedCar() { foreach(var red in RedCars) { double distance = Math.Sqrt(Math.Pow(red.X - EyeX, 2) + Math.Pow(red.Y - EyeY, 2)); // 1.0では違和感があるのでもっと接近している状態を「接触」と判定する if(distance < 0.5) { return true; } } return false; } } |
これではすぐにゲームが終わってしまいます。そこで設定を少し変えます。
[スタート]がクリックされたら初期設定を行ないます。timer.Intervalの設定とマイカー、レッドカー、チェックポイントを初期の位置に設定します。それからマイカーとレッドカーの初期位置が近すぎるのでゲーム開始から3秒間はレッドカーは動かないものとします。
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 |
public class RedCar { public int StopInterval = 3000; public void MoveCar() { // StopInterval > 0 のときは動かない if(StopInterval > 0) { // Timer.Interval が 60なので StopInterval -= 60; return; } if(CurDirect == Direct.North) Y += 0.20; if(CurDirect == Direct.South) Y -= 0.20; if(CurDirect == Direct.West) X -= 0.20; if(CurDirect == Direct.East) X += 0.20; IfCanChengeDirect(); } } |
GameStart()メソッド内で[スタート]がクリックされたときの初期設定をしています。
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 |
public partial class Form1 : Form { public Form1() { // 一部の処理をGameStart()に移動した InitializeComponent(); glControl1.Load += GlControlEx1_Load; glControl1.Paint += GlControlEx1_Paint; glControl1.Resize += GlControl1_Resize; timer.Tick += Timer_Tick; panelRadar.Paint += PanelRadar_Paint; this.Size = new Size(643, 511); } // 残機 int Rest = 0; const int MaxRest = 3; // プレイ中は isGameOver == false bool isGameOver = true; private void StartMenuItem_Click(object sender, EventArgs e) { GameStart(); } void GameStart() { isGameOver = false; Rest = MaxRest; TimerReset(); ResetMyCar(); ResetRedCars(); ResetCheckPoints(); timer.Start(); } void TimerReset() { timer.Interval = 60; } void ResetMyCar() { CurDirect = Direct.North; NextDirect = Direct.North; EyeX = 12; EyeY = 3; } void ResetRedCars() { RedCars.Clear(); RedCars.Add(new RedCar(RoadBlocks, 12, 1, Direct.North)); RedCars.Add(new RedCar(RoadBlocks, 10, 1, Direct.North)); RedCars.Add(new RedCar(RoadBlocks, 14, 1, Direct.North)); // レッドカーは3秒間動かない foreach(RedCar red in RedCars) { red.StopInterval = 3 * 1000; red.CurDirect = Direct.North; } } void ResetCheckPoints() { CheckPoints.Clear(); SetCheckPoints(); } } |
ゲーム中にチェックポイントを通過したらチェックポイントのフィールド変数 Clearedをtrueにします。するとそのチェックポイントは表示されなくなります。そしてすべてのチェックポイントを通過していればステージクリアとなります。
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 |
public partial class Form1 : Form { // チェックポイントを通過したか? void JudgeContactCheckPoint() { foreach(var check in CheckPoints.Where(x => !x.Cleared).ToList()) { double distance = Math.Sqrt(Math.Pow(check.IndexX - EyeX, 2) + Math.Pow(check.IndexY - EyeY, 2)); // distance == 1 なら接触している if(distance < 0.5) { check.Cleared = true; } } } private void GlControlEx1_Paint(object sender, PaintEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); DrawRoad(); DrawMyCar(); DrawRedCars(); // チェックポイントを通過したか? JudgeContactCheckPoint(); // 未通過のチェックポイントを描画 DrawCheckPoints(); // ここで衝突判定する bool ret = JudgeContactRedCar(); if(ret) DrawBang(); glControl1.SwapBuffers(); // レッドカート衝突した場合はミス if(ret) Miss(); // すべてのチェックポイントを通過していればステージクリア if(!CheckPoints.Any(x => !x.Cleared)) StageClear(); } // レッドカーとの衝突時の描画 void DrawBang() { GL.Color3(Color.Red); GL.PushMatrix(); { GL.Translate(EyeX, EyeY, 0); GL.Begin(BeginMode.Quads); { GL.Vertex3(0.0, 1.0, 0.1); GL.Vertex3(1.0, 0.0, 0.1); GL.Vertex3(0.0, -1.0, 0.1); GL.Vertex3(-1.0, 0.0, 0.1); } GL.End(); GL.Begin(BeginMode.Triangles); { GL.Vertex3(1.0, 1.0, 0.1); GL.Vertex3(0.0, 0.5, 0.1); GL.Vertex3(0.5, 0.0, 0.1); GL.Vertex3(1.0, -1.0, 0.1); GL.Vertex3(0.0, -0.5, 0.1); GL.Vertex3(0.5, 0.0, 0.1); GL.Vertex3(-1.0, -1.0, 0.1); GL.Vertex3(0.0, -0.5, 0.1); GL.Vertex3(-0.5, 0.0, 0.1); GL.Vertex3(-1.0, 1.0, 0.1); GL.Vertex3(0.0, 0.5, 0.1); GL.Vertex3(-0.5, 0.0, 0.1); } GL.End(); } GL.PopMatrix(); } void Miss() { // タイマーを一旦止めて、自機をひとつ減らす // 自機 == 0 ならゲームオーバー timer.Stop(); Rest--; if(Rest == 0) { GameOver(); return; } // 3秒後にマイカーとレッドカーを元の位置に戻してゲームを再開する Timer timer2 = new Timer(); timer2.Interval = 3000; timer2.Tick += Timer2_Tick; timer2.Start(); } void GameOver() { isGameOver = true; MessageBox.Show("ゲームオーバー"); } private void Timer2_Tick(object sender, EventArgs e) { Timer t = (Timer)sender; t.Stop(); t.Dispose(); // ゲーム再開 ResetMyCar(); ResetRedCars(); timer.Start(); } void StageClear() { if(!isGameOver) { timer.Stop(); MessageBox.Show("クリア"); } } } |
それから点数の計算も必要です。
ラリーX – Wikipediaによると、
ノーミスで連続してチェックポイントを通過するごとに100、200…と100点ずつ得点が上昇していく。また「スペシャルチェックポイント」(黄旗に赤字でS表記)が各面1箇所存在し、取るとこれ以降のチェックポイント通過得点が2倍になる。
とありますが、スペシャルチェックポイントは省略(ゴメンナサイ)してノーミスで連続して通過した場合の得点増加処理だけおこないます。
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 |
public partial class Form1 : Form { // ノーミスで何回連続しているか? int GetCount = 0; void Miss() { timer.Stop(); // ミス時は GetCountをリセット GetCount = 0; Rest--; if(Rest == 0) { GameOver(); return; } Timer timer2 = new Timer(); timer2.Interval = 3000; timer2.Tick += Timer2_Tick; timer2.Start(); } void JudgeContactCheckPoint() { foreach(var check in CheckPoints.Where(x => !x.Cleared).ToList()) { double distance = Math.Sqrt(Math.Pow(check.IndexX - EyeX, 2) + Math.Pow(check.IndexY - EyeY, 2)); // distance == 1 なら接触している // そのチェックポイントを非表示にするとともに、点数を計算して追加 if(distance < 0.5) { check.Cleared = true; AddScore(); } } } void AddScore() { GetCount++; Score += GetCount * 100; } int _score = 0; int Score { get { return _score; } set { _score = value; label1.Text = String.Format("{0:000000}", _score); } } void GameStart() { Rest = MaxRest; // 開始時のスコアは0 Score = 0; // GetCountをリセット GetCount = 0; TimerReset(); ResetMyCar(); ResetRedCars(); ResetCheckPoints(); timer.Start(); } void StageClear() { if(!isGameOver) { timer.Stop(); // ステージクリア時もGetCountをリセット GetCount = 0; MessageBox.Show("クリア"); } } } |