こんな感じのゲームをつくります。
戦車をフィールドのなかで移動させます。
まずゲームがスタートしたら戦車の位置と視点を最初にリセットします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public partial class Form1 : Form { void Start() { EnemyTanks.Clear(); // 視界をもとに戻す ResetSight(); // 自分の戦車の位置・方向・状態をもとに戻す ResetMyTank(); SmallExplosions.Clear(); Explosions.Clear(); timer.Start(); } } |
これは読み込ませたテキストファイルですが、最初に自分の戦車が置かれるのはこの位置です。そして1文字のサイズが2.0なのと、Z座標は手前が+であることから最初の戦車の座標は(10,-6)になります。それから戦車を撮影するカメラの位置は戦車の手前 2.0の位置なのでEyeZはZ(戦車のZ座標)に2.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 |
public partial class Form1 : Form { void ResetMyTank() { X = 10.0f; Z = -6.0f; RotateY = 180; Tank.isDead = false; Tank.Bullets.Clear(); } void ResetSight() { EyeX = X; EyeY = 1.0f; EyeZ = Z + 2.0f; TargetX = X; TargetY = 1.0f; TargetZ = Z; } } |
また戦車の方向は0度、90度、180度、270度のどれかなので、戦車の位置をしめす座標は小数点1桁で充分です。そこでX、Zプロパティを以下のように変更します。
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 |
public partial class Form1 : Form { float X { get { return (float)Tank.X; } set { Tank.X = (float)Math.Round(value, 2, MidpointRounding.AwayFromZero); ShowLabel(); SetSight(); } } float Y { get { return (float)Tank.Y; } set { Tank.Y = (float)Math.Round(value, 2, MidpointRounding.AwayFromZero); ShowLabel(); SetSight(); } } float Z { get { return (float)Tank.Z; } set { Tank.Z = (float)Math.Round(value, 2, MidpointRounding.AwayFromZero); ShowLabel(); SetSight(); } } } |
それから方向転換は左と右キーを押すだけで90度自動的に回転します。後退はできず、前方にしか移動できません(タンクバタリアンがそのような仕様になっているので・・・)。
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 |
public partial class Form1 : Form { protected override bool ProcessDialogKey(Keys keyData) { //キーの本来の処理を //させたくないときは、trueを返す if((keyData & Keys.KeyCode) == Keys.Left) { TurnLeft(); return true; } else if((keyData & Keys.KeyCode) == Keys.Right) { TurnRight(); return true; } else if((keyData & Keys.KeyCode) == Keys.Up) { Go(); return true; } else if((keyData & Keys.KeyCode) == Keys.Down) { return true; } else if((keyData & Keys.KeyCode) == Keys.Space) { Tank.Shot(); glControl.Refresh(); return true; } return base.ProcessDialogKey(keyData); } } |
方向転換するときはだんだんその方向に方向転換しているようにタイマーを使っています。
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 |
public partial class Form1 : Form { // どちらかが-1でない場合は方向転換または移動中なのでなにもしない int turnCounter = -1; int goCounter = -1; void TurnLeft() { // 方向転換中はなにもしない if(turnCounter != -1 || goCounter != -1) return; turnCounter = 0; Timer turnTimer = new Timer(); turnTimer.Interval = 30; turnTimer.Tick += TurnTimer_Tick; turnTimer.Start(); void TurnTimer_Tick(object sender, EventArgs e) { TurnLeft0(); turnCounter++; if(turnCounter >= 18) { Timer t = (Timer)sender; t.Stop(); t.Dispose(); turnCounter = -1; return; } } } void TurnLeft0() { int angle = 5; RotateY += angle; float x1 = EyeX; float z1 = EyeZ; EyeX = Cos(-angle) * (x1 - X) - Sin(-angle) * (z1 - Z) + X; EyeZ = Sin(-angle) * (x1 - X) + Cos(-angle) * (z1 - Z) + Z; float x2 = TargetX; float z2 = TargetZ; TargetX = Cos(-angle) * (x2 - X) - Sin(-angle) * (z2 - Z) + X; TargetZ = Sin(-angle) * (x2 - X) + Cos(-angle) * (z2 - Z) + Z; glControl.Refresh(); } void TurnRight() { // 方向転換中はなにもしない if(turnCounter != -1 || goCounter != -1) return; turnCounter = 0; Timer turnTimer = new Timer(); turnTimer.Interval = 30; turnTimer.Tick += TurnTimer_Tick; turnTimer.Start(); void TurnTimer_Tick(object sender, EventArgs e) { TurnRight0(); turnCounter++; if(turnCounter >= 18) { Timer t = (Timer)sender; t.Stop(); t.Dispose(); turnCounter = -1; return; } } } void TurnRight0() { int angle = 5; RotateY -= angle; float x1 = EyeX; float z1 = EyeZ; EyeX = Cos(angle) * (x1 - X) - Sin(angle) * (z1 - Z) + X; EyeZ = Sin(angle) * (x1 - X) + Cos(angle) * (z1 - Z) + Z; float x2 = TargetX; float z2 = TargetZ; TargetX = Cos(angle) * (x2 - X) - Sin(angle) * (z2 - Z) + X; TargetZ = Sin(angle) * (x2 - X) + Cos(angle) * (z2 - Z) + Z; glControl.Refresh(); } } |
以下は戦車が向いている方向に移動するためのメソッドです。
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 |
public partial class Form1 : Form { void Go() { if(turnCounter != -1 || goCounter != -1) return; goCounter = 0; Timer goTimer = new Timer(); goTimer.Interval = 30; goTimer.Tick += GoTimer_Tick; goTimer.Start(); void GoTimer_Tick(object sender, EventArgs e) { Go0(); goCounter++; Console.WriteLine(goCounter); if(goCounter >= 20) { Timer t = (Timer)sender; t.Stop(); t.Dispose(); goCounter = -1; return; } } } void Go0() { if(RotateY == 0) { Z += 0.1f; EyeZ += 0.1f; TargetZ += 0.1f; } else if(RotateY == 90) { X += 0.1f; EyeX += 0.1f; TargetX += 0.1f; } else if(RotateY == 180) { Z += -0.100000f; EyeZ += -0.1f; TargetZ += -0.1f; } else if(RotateY == 270) { X += -0.1f; EyeX += -0.1f; TargetX += -0.1f; } glControl.Refresh(); } } |
Thank you for your blog article. Awesome. Troy Merkt