Contents
モンスターを移動させる
今回はモンスターの表示と移動をやります。
モンスターは4体あります。本当のパックマンには4体それぞれに個性があり、後ろを追う傾向が強かったり、待ち伏せ的な動き方をする傾向が強いものがあるのですが、そこまで厳密につくらず乱数で適当に動いてもらいます。
モンスターの位置の初期化
最初にモンスターが描画される位置を決める必要があります。原作では最初から巣の外にいてパックマンを追いかけるモンスターは1体だけなのですが、ここでは簡単にするために全部巣の外に配置しています。
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 { int[] MonstersPosX = new int[4]; int[] MonstersPosY = new int[4]; int[] MonstersCellX = new int[4]; int[] MonstersCellY = new int[4]; Direct[] MonstersDirect = new Direct[4]; void InitMonstar(int monstar) { Rectangle rect; int initX = 0; int initY = 0; Direct initDirect = Direct.North; if(monstar == 0) { initX = 10; initY = 9; initDirect = Direct.West; } if(monstar == 1) { initX = 9; initY = 9; initDirect = Direct.West; } if(monstar == 2) { initX = 11; initY = 9; initDirect = Direct.East; } if(monstar == 3) { initX = 12; initY = 9; initDirect = Direct.East; } MonstersCellX[monstar] = initX; MonstersCellY[monstar] = initY; rect = GetMazeCell(MonstersCellX[monstar], MonstersCellY[monstar]); MonstersPosX[monstar] = rect.X; MonstersPosY[monstar] = rect.Y; MonstersDirect[monstar] = initDirect; } } |
MoveMonstarメソッド
次にそれぞれのモンスターを動かすMoveMonstarメソッドを示します。単にランダムに動くと似たような位置で行ったり来たりするだけになるので、モンスターは基本的にまっすぐに動き、途中で折り返すような動き方はしないことにします。曲がることができる場所では曲がるかどうか乱数をつかって決めます。
GetMonstarMoveDirectメソッドは通路の状態を調べてどの方向であれば進行可能かを調べます。また途中で折り返す動きはしないので北へ向かっているときは南には行けません。現在の進行方向と真逆のものは除いています。あとは乱数で方向を決めます。
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 |
public partial class Form1 : Form { async Task<bool> MoveMonstar(int monstar) { bool ret; List<Direct> directs = GetMonstarMoveDirect(monstar); int r = 0; if(MonstersDirect[monstar] == Direct.North) { directs.Remove(Direct.South); r = random.Next(0, directs.Count); } else if(MonstersDirect[monstar] == Direct.South) { directs.Remove(Direct.North); r = random.Next(0, directs.Count); } else if(MonstersDirect[monstar] == Direct.West) { directs.Remove(Direct.East); r = random.Next(0, directs.Count); } else if(MonstersDirect[monstar] == Direct.East) { directs.Remove(Direct.West); r = random.Next(0, directs.Count); } Direct direct = directs[r]; ret = await MonstarMoveDirect(monstar, direct); return ret; } } |
GetMonstarMoveDirectメソッド
GetMonstarMoveDirectメソッドは、パックマンを移動させるときにも使用したGetStringMazeCellメソッドをつかってモンスターがいるセルの状態を調べて進行可能な方向を取得します。
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 { List<Direct> GetMonstarMoveDirect(int monstar) { List<Direct> directs = new List<Direct>(); string str = GetStringMazeCell(MonstersCellX[monstar], MonstersCellY[monstar]); if(str == "┌") { directs.Add(Direct.South); directs.Add(Direct.East); } if(str == "┬") { directs.Add(Direct.East); directs.Add(Direct.South); directs.Add(Direct.West); } if(str == "┐") { directs.Add(Direct.South); directs.Add(Direct.West); } if(str == "├") { directs.Add(Direct.North); directs.Add(Direct.East); directs.Add(Direct.South); } if(str == "┼") { directs.Add(Direct.North); directs.Add(Direct.East); directs.Add(Direct.South); directs.Add(Direct.West); } if(str == "┤") { directs.Add(Direct.North); directs.Add(Direct.South); directs.Add(Direct.West); } if(str == "└") { directs.Add(Direct.North); directs.Add(Direct.East); } if(str == "┴") { directs.Add(Direct.North); directs.Add(Direct.East); directs.Add(Direct.West); } if(str == "┘") { directs.Add(Direct.North); directs.Add(Direct.West); } if(str == "─") { directs.Add(Direct.East); directs.Add(Direct.West); } if(str == "│") { directs.Add(Direct.North); directs.Add(Direct.South); } return directs; } } |
MonstarMoveDirectメソッド
動かす方向が決まったらその方向にモンスターを動かします。
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 |
public partial class Form1 : Form { async Task<bool> MonstarMoveDirect(int monstar, Direct direct) { if(direct == Direct.North) { MonstersDirect[monstar] = Direct.North; for(int i = 0; i < 4; i++) { MonstersPosY[monstar] -= CELL_HEIGHT / 4; Invalidate(); await Task.Delay(PACMAN_DELAY); } MonstersCellY[monstar]--; } if(direct == Direct.East) { MonstersDirect[monstar] = Direct.East; for(int i = 0; i < 4; i++) { MonstersPosX[monstar] += CELL_WIDTH / 4; Invalidate(); await Task.Delay(PACMAN_DELAY); } MonstersCellX[monstar]++; } if(direct == Direct.South) { MonstersDirect[monstar] = Direct.South; for(int i = 0; i < 4; i++) { MonstersPosY[monstar] += CELL_HEIGHT / 4; Invalidate(); await Task.Delay(PACMAN_DELAY); } MonstersCellY[monstar]++; } if(direct == Direct.West) { MonstersDirect[monstar] = Direct.West; for(int i = 0; i < 4; i++) { MonstersPosX[monstar] -= CELL_WIDTH / 4; Invalidate(); await Task.Delay(PACMAN_DELAY); } MonstersCellX[monstar]--; } // CELL_WIDTH、CELL_HEIGHTが4で割り切れない場合、ずれが発生するのでその補正のための処理 Rectangle newRect = GetMazeCell(MonstersCellX[monstar], MonstersCellY[monstar]); MonstersPosX[monstar] = newRect.X; MonstersPosY[monstar] = newRect.Y; return true; } } |
モンスターを表示させる
モンスターを表示させるにはInvalidateメソッドを呼ぶことでDrawMonsterメソッドを実行させることで実現します。
まず表示させるモンスターですが、mame icons 03 OKINIIRIで公開しているものを使用しました。
アイコンタイプです。これをリソースとして追加します。
1 2 3 4 5 6 7 |
public partial class Form1 : Form { Icon redMonserIcon = Properties.Resources._08; Icon pinkMonserIcon = Properties.Resources._09; Icon blueMonserIcon = Properties.Resources._10; Icon orangeMonserIcon = Properties.Resources._11; } |
DrawMonsterメソッドは以下のようになっています。それぞれのモンスターを赤、ピンク、青、オレンジ色で表示させます。
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 { protected override void OnPaint(PaintEventArgs e) { DrawMaze(e.Graphics); DrawPac(e.Graphics); DrawMonster(0, e.Graphics); DrawMonster(1, e.Graphics); DrawMonster(2, e.Graphics); DrawMonster(3, e.Graphics); base.OnPaint(e); } void DrawMonster(int i, Graphics g) { Rectangle rect = new Rectangle(new Point(MonstersPosX[i], MonstersPosY[i]), new Size(CELL_WIDTH, CELL_HEIGHT)); if(i == 0) g.DrawIcon(redMonserIcon, rect); if(i == 1) g.DrawIcon(pinkMonserIcon, rect); if(i == 2) g.DrawIcon(blueMonserIcon, rect); if(i == 3) g.DrawIcon(orangeMonserIcon, rect); } } |
MoveMonstarメソッドと呼び出すことでこのようなモンスターを動かす処理をおこなうことができるのですが、この処理はTimer.Tickイベントでおこなわれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public partial class Form1 : Form { bool ignoreTick = false; private async void Timer_Tick(object sender, EventArgs e) { if(ignoreTick) return; ignoreTick = true; Task<bool> pacTask = MovePacmanDirect(pacDirect); Task<bool> monstarsTask = MoveMonstars(); await pacTask; await monstarsTask; ignoreTick = false; } } |