今回はスクランブルもどきをつくります。スクランブルとはこんなゲームです。
ジェット機型の宇宙船(スペースファイター)を地形や敵に衝突するのを避けながら操縦し、最終的には敵基地を破壊することがプレイヤーの目的となる。自機は前方向ショットと投下式ミサイルを装備しており、これで空中の敵や地上物を破壊できる。:引用元 スクランブル (ゲーム)
スクロール型のゲームをつくるときは敵の動きを考える必要があります。自機が移動することで背景がそれとは逆方向に移動します。すると敵の移動は敵自体の移動だけでなく背景の移動分も考える必要があるわけです。
スクランブルでいえば敵ミサイルは上方向に移動しますが、自機が移動するため見た目は斜め上方向に移動させる必要があるわけです。自機の移動速度が同じならあまり難しく考える必要はない(ミサイルは最初から斜め上に移動すると考えることも可能)ですが、自機の移動速度(背景の移動速度)が可変である場合でも対応できるようなものとしてアプリケーションを作成することにします。
まずはデザイナで以下のようなものを作成します。
フォームにメニューをつけています。中央にあるのはパネルです。
自機を表示させるためのクラスを作成します。自機の画像は動画にあったものをキャプチャさせていただきました。これを80×30ピクセルで表示させます。
パネルに何かを表示させるのであれば
1 2 3 4 5 6 7 8 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); panel1.Paint += Panel1_Paint; } } |
としてイベントハンドラPanel1_Paint内で描画の処理をすればよいのですが、ここでJikiクラスのなかのメソッドを呼び出して描画させます。自機は常に存在するわけではありません。敵にやられれば消滅するし、ゲーム開始以前に表示されているのはおかしいです。
Jikiクラスに必要なものとして、
自機は存在するのかを示すプロパティまたはフィールド変数
自機の画像となるプロパティまたはフィールド変数
自機を表示させるメソッド
自機を移動させるメソッド
ほかにもあると思いますが、これらは最低必要であると思われます。
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 |
public class Jiki { // 自機の画像となるフィールド変数 Bitmap Bitmap = Properties.Resources.jiki; // 自機は存在するのかを示すフィールド変数 public bool DoesShow = false; // 自機のX座標とY座標を示すフィールド変数 public int X = 0; public int Y = 0; // コンストラクタ public Jiki() {} // 自機を表示させるメソッド public void Show(Graphics g) { if(DoesShow) { // 80×30ピクセルで表示 int sourceWidth = Bitmap.Width; int sourceHeight = Bitmap.Height; g.DrawImage(Bitmap, new Rectangle(X, Y, 80, 30), new Rectangle(0, 0, sourceWidth, sourceHeight), GraphicsUnit.Pixel); } } // 自機を移動させる(自機の表示位置を変更する)メソッド public void MoveUp() { Y -= 5; } public void MoveDown() { Y += 5; } public void MoveLeft() { X -= 5; } public void MoveRight() { X += 5; } } |
まだまだ不十分で追加するメソッドもありますが、とりあえずいまはこれでよいでしょう。
次にForm1クラスでの処理です。
まずメニューの[スタート]がクリックされたら自機を表示させます。そして方向キーがおされたら自機をその方向に移動させます。
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 |
public partial class Form1 : Form { Jiki Jiki = new Jiki(); public Form1() { InitializeComponent(); panel1.BackColor = Color.Black; } private void GameStartMenuItem_Click(object sender, EventArgs e) { Jiki.DoesShow = true; } private void panel1_Paint(object sender, PaintEventArgs e) { Jiki.Show(e.Graphics); } private void Form1_KeyDown(object sender, KeyEventArgs e) { if(e.KeyCode == Keys.Up) Jiki.MoveUp(); if(e.KeyCode == Keys.Down) Jiki.MoveDown(); if(e.KeyCode == Keys.Left) Jiki.MoveLeft(); if(e.KeyCode == Keys.Right) Jiki.MoveRight(); panel1.Invalidate(); } } |
これで一応動くのですが、方向キーを押したときにスムーズに移動させることができません。キーを押すと少しだけ移動してそのまましばらく押したままにしないと移動させ続けることができません。
そこでみんなの大好きなタイマーを使用します。方向キーをおすと自機の移動方向が指定され、離すとクリアされます。そして自機の移動方向が指定されているときにタイマーイベントが発生するとそのあいだその方向に移動するという例のやり方です。
Jikiクラスを以下のように変更します。
そのまえに自機の方向を管理するための列挙体を作成します。
1 2 3 4 5 6 7 8 |
public enum JikiDirect { None = 0, Up = 1, Down = 2, Left = 3, Right = 4, } |
次にJikiクラスを示します。
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 |
public partial class Form1 : Form { Jiki Jiki = new Jiki(); JikiDirect JikiDirect = JikiDirect.None; Timer Timer = new Timer(); public Form1() { InitializeComponent(); panel1.BackColor = Color.Black; Timer.Interval = 50; Timer.Tick += Timer_Tick; } private void Timer_Tick(object sender, EventArgs e) { TimerTick_JikiMove(); panel1.Invalidate(); } void TimerTick_JikiMove() { if(JikiDirect == JikiDirect.Up) Jiki.MoveUp(); if(JikiDirect == JikiDirect.Down) Jiki.MoveDown(); if(JikiDirect == JikiDirect.Left) Jiki.MoveLeft(); if(JikiDirect == JikiDirect.Right) Jiki.MoveRight(); } private void GameStartMenuItem_Click(object sender, EventArgs e) { Jiki.DoesShow = true; Timer.Start(); } private void panel1_Paint(object sender, PaintEventArgs e) { Jiki.Show(e.Graphics); } private void Form1_KeyDown(object sender, KeyEventArgs e) { if(e.KeyCode == Keys.Up) JikiDirect = JikiDirect.Up; if(e.KeyCode == Keys.Down) JikiDirect = JikiDirect.Down; if(e.KeyCode == Keys.Left) JikiDirect = JikiDirect.Left; if(e.KeyCode == Keys.Right) JikiDirect = JikiDirect.Right; } private void Form1_KeyUp(object sender, KeyEventArgs e) { if(e.KeyCode == Keys.Up) JikiDirect = JikiDirect.None; if(e.KeyCode == Keys.Down) JikiDirect = JikiDirect.None; if(e.KeyCode == Keys.Left) JikiDirect = JikiDirect.None; if(e.KeyCode == Keys.Right) JikiDirect = JikiDirect.None; } } |
これで自機がスムーズに動くようになりました。