前回はフロアしか作成しなかったので今回はプレイヤーを生成して移動させる処理をおこないます。
プレイヤーを描画する
まずプレイヤーの描画ですが、うまく絵が描けなかったので鍵穴のようなマークを描画してこれをプレイヤーとします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class GameManager { // プレイヤーの初期座標 public static int PlayerX = 7 * CharctorSize; public static int PlayerY = 15 * CharctorSize; public void DrawPlayer(Graphics graphics) { Point point = GetPointForShow(PlayerX, PlayerY); Point[] points = { new Point(point.X + CharctorSize / 2, point.Y), new Point(point.X, point.Y + CharctorSize), new Point(point.X + CharctorSize, point.Y + CharctorSize), }; graphics.FillPolygon(Brushes.Yellow, points, System.Drawing.Drawing2D.FillMode.Winding); graphics.FillEllipse(Brushes.Yellow, new Rectangle(point.X + CharctorSize / 4, point.Y - CharctorSize / 4, 16, 16)); } } |
プレイヤーの移動
次にプレイヤーを移動させる処理ですが、Form1クラスのなかにTimerをつくって座標の変更と描画の処理をおこないます。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 34 35 |
public partial class Form1 : Form { Timer Timer = new Timer(); GameManager GameManager = new GameManager(); public Form1() { InitializeComponent(); GameManager = new GameManager(this); Timer.Interval = 1000 / 60; Timer.Tick += Timer_Tick; Timer.Start(); this.DoubleBuffered = true; this.BackColor = Color.Black; } private void Timer_Tick(object sender, EventArgs e) { GameManager.Update(); Invalidate(); } protected override void OnPaint(PaintEventArgs e) { GameManager.DrawFloor(e.Graphics); GameManager.DrawLadders(e.Graphics); GameManager.DrawPlayer(e.Graphics); base.OnPaint(e); } } |
GameManagerクラスにUpdateメソッドを作成して、ここでプレイヤーの座標を変更します。
1 2 3 4 5 6 7 |
public class GameManager { public void Update() { MovePlayer(); // 後述 } } |
方向キーが押されているときだけその方向にプレイヤーを移動させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class GameManager { public bool IsMoveLeft = false; public bool IsMoveRight = false; public bool IsMoveUp = false; public bool IsMoveDown = false; public void DigHole() { // 穴を掘る(後述) } public void FillHole() { // 穴を埋める(後述) } public void Retry() { // ゲーム再スタート(後述) } } |
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 |
public partial class Form1 : Form { protected override void OnKeyDown(KeyEventArgs e) { if (e.KeyCode == Keys.Left) GameManager.IsMoveLeft = true; if (e.KeyCode == Keys.Right) GameManager.IsMoveRight = true; if (e.KeyCode == Keys.Up) GameManager.IsMoveUp = true; if (e.KeyCode == Keys.Down) GameManager.IsMoveDown = true; if (e.KeyCode == Keys.Z) GameManager.DigHole(); if (e.KeyCode == Keys.X) GameManager.FillHole(); if (e.KeyCode == Keys.S) GameManager.Retry(); base.OnKeyDown(e); } protected override void OnKeyUp(KeyEventArgs e) { if (e.KeyCode == Keys.Left) GameManager.IsMoveLeft = false; if (e.KeyCode == Keys.Right) GameManager.IsMoveRight = false; if (e.KeyCode == Keys.Up) GameManager.IsMoveUp = false; if (e.KeyCode == Keys.Down) GameManager.IsMoveDown = false; base.OnKeyUp(e); } } |
本当に移動できるかどうか調べる
GameManager.Updateメソッドが呼び出されるとどのキーが押されているかを調べてその方向にプレイヤーを移動させるのですが、その前に本当にその方向に移動することができるのかを調べる必要があります。
ハシゴのないところで上下の階に移動することはできません。ハシゴがあるかどうかはコンストラクタ内で取得したLadderPositionsで知ることができます。ちょうどその位置でなくても8ピクセル以内のズレであれば移動できるものとします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class GameManager { public static bool CanMoveUp(int x, int y) { foreach (Point pt in LadderPositions) { // pt.Y - 3 * CharctorSizeはハシゴの上端のY座標 if (pt.X - 8 <= x && x <= pt.X + 8 && pt.Y - 3 * CharctorSize < y && y <= pt.Y) return true; } return false; } public static bool CanMoveDown(int x, int y) { foreach (Point pt in LadderPositions) { if (pt.X - 8 <= x && x <= pt.X + 8 && pt.Y - 3 * CharctorSize <= y && y < pt.Y) return true; } return false; } } |
ハシゴの上り下りをしているときに左右に移動することはできません。またフロアの左右の端よりも向こうに水平移動することもできません。Y座標がフロアのY座標から8ピクセル以内のズレであれば水平移動できるものとします。
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 |
public class GameManager { public static bool CanMoveLeft(int x, int y) { if (x <= 0 || x > 14 * CharctorSize) return false; for (int i = 1; i <= 6; i++) { int y1 = GetYFromNumberOfFloors(i); if (y1 - 8 <= y && y <= y1 + 8) return true; } return false; } public static bool CanMoveRight(int x, int y) { if (x < 0 || x >= 14 * CharctorSize) return false; for (int i = 1; i <= 6; i++) { int y1 = GetYFromNumberOfFloors(i); if (y1 - 8 <= y && y <= y1 + 8) return true; } return false; } } |
実際に移動させる
方向キーが押されていてその方向に移動できる場合は移動させます。移動させる処理を示します。
CanMove~メソッドではX座標がハシゴの座標と完全に一致していなくても上り下りできます。そこでズレがあった場合、修正して移動させます。これで常にハシゴの中央を上り下りできるようになります。
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 |
public class GameManager { public void MovePlayer() { if (IsMoveLeft) { if (CanMoveLeft(PlayerX, PlayerY)) { // 4ピクセル移動させる // この値はCharctorSizeを割り切ることができる値でなければならない PlayerX -= 4; int a = PlayerY % (CharctorSize * 3); if (a <= 8) PlayerY -= a; else if (a != 0) PlayerY += CharctorSize * 3 - a; } } if (IsMoveRight) { if (CanMoveRight(PlayerX, PlayerY)) { PlayerX += 4; int a = PlayerY % (CharctorSize * 3); if (a <= 8) PlayerY -= a; else if (a != 0) PlayerY += CharctorSize * 3 - a; } } if (IsMoveUp) { if (CanMoveUp(PlayerX, PlayerY)) { int a = PlayerX % (CharctorSize * 2); if (a <= 8) PlayerX -= a; else if (a != 0) PlayerX += CharctorSize * 2 - a; PlayerY -= 4; } } if (IsMoveDown) { if (CanMoveDown(PlayerX, PlayerY)) { int a = PlayerX % (CharctorSize * 2); if (a <= 8) PlayerX -= a; else if (a != 0) PlayerX += CharctorSize * 2 - a; PlayerY += 4; } } } } |
タイマーによってMovePlayerメソッドが呼び出されると同時に再描画がおこなわれるので最初に示したDrawPlayerメソッドによって移動したプレイヤーが描画されます。
敵の生成と移動
次に敵を生成して移動させます。いまは端までくると方向を方向転換して左右に移動するだけです。
Enemyクラス
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 |
public class Enemy { int X = 0; int Y = 0; int InitX = 0; int InitY = 0; double EnemySpeed = 2.0; MoveDirect MoveDirect = MoveDirect.Right; Bitmap Bitmap = Properties.Resources.enemy; static Random Random = new Random(); public Enemy(int x, int y) { X = x; Y = y; InitX = x; InitY = y; } public void Move() { if (MoveDirect == MoveDirect.Left) MoveLeft(); if (MoveDirect == MoveDirect.Right) MoveRight(); if (X > 14 * GameManager.CharctorSize) MoveDirect = MoveDirect.Left; if (X < 0) MoveDirect = MoveDirect.Right; } public void MoveLeft() { X -= 2; } public void MoveRight() { X += 2; } public void Draw(Graphics graphics) { Point pt = GameManager.GetPointForShow(X, Y); int size = GameManager.CharctorSize; graphics.FillRectangle(Brushes.Red, new Rectangle(pt.X, pt.Y, size, size)); } } |
1 2 3 4 5 6 7 8 |
public enum MoveDirect { Left, Up, Right, Down, Stop, } |
敵を移動させる
GameManager.Updateメソッド内で敵を移動させる処理をおこないます。
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 class GameManager { public static List<Enemy> Enemies = new List<Enemy>(); public GameManager() { LadderPositions = GetLadderPositions(); Enemies.Add(new Enemy(CharctorSize * 3, GetYFromNumberOfFloors(6))); Enemies.Add(new Enemy(CharctorSize * 6, GetYFromNumberOfFloors(5))); Enemies.Add(new Enemy(CharctorSize * 9, GetYFromNumberOfFloors(4))); Enemies.Add(new Enemy(CharctorSize * 12, GetYFromNumberOfFloors(3))); Enemies.Add(new Enemy(CharctorSize * 15, GetYFromNumberOfFloors(2))); } public void Update() { MovePlayer(); MoveEnemies(); } void MoveEnemies() { foreach (Enemy enemy in Enemies) enemy.Move(); } public void DrawEnemies(Graphics graphics) { foreach (Enemy enemy in Enemies) enemy.Draw(graphics); } } |
Form1クラス内でGameManager.DrawEnemiesメソッドをよびだして描画します。
1 2 3 4 5 6 7 8 9 10 11 12 |
public partial class Form1 : Form { protected override void OnPaint(PaintEventArgs e) { GameManager.DrawFloor(e.Graphics); GameManager.DrawLadders(e.Graphics); GameManager.DrawPlayer(e.Graphics); GameManager.DrawEnemies(e.Graphics); base.OnPaint(e); } } |