Contents
モンスターを食べる
パワー餌の効果がある時間を決めてそのあいだはモンスターをいわゆる「いじけ状態」にさせます。いじけ状態にあるモンスターは動作方向が逆方向になり、移動速度も遅くなります。得点は1匹目が200点、2匹目が400点、3匹目は800点、4匹目は1600点とします。パワー餌の効果がある時間は10秒程度です。
OnEatPowerFoodメソッド
パワー餌を食べたかどうかはOnPacmanMovedメソッド内で判断することができます。パワー餌を食べたら50点を加算してOnEatPowerFoodメソッドを呼びます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public partial class Form1 : Form { void OnPacmanMoved(int cellX, int cellY) { if(IsFoodlesBeginningCell(cellX, cellY)) return; if(passedPacman[cellY, cellX] == false) { passedPacman[cellY, cellX] = true; if(!IsPowerFoodCell(cellX, cellY)) score += 10; else { score += 50; OnEatPowerFood(); } label1.ForeColor = Color.White; label1.Text = "Score " + score.ToString(); } } } |
OnEatPowerFoodメソッドが呼ばれるとモンスターをいじけ状態にします。そのためのフラグを用意します。
いじけ状態になると移動方向を逆にして移動速度も低下させます。表示もいじけ状態に変えます。
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 |
public partial class Form1 : Form { bool[] isMonsterIjike = new bool[4]; Icon ijikeMonsterIcon = Properties.Resources._12; void OnEatPowerFood() { for(int i = 0; i < isMonsterIjike.Length; i++) { isMonsterIjike[i] = true; Direct direct = MonstersDirect[i]; // 移動方向を逆にできるなら逆にする List<Direct> directs = GetMonstarMoveDirect(i); if(direct == Direct.North && directs.Any(x => x == Direct.South)) MonstersDirect[i] = Direct.South; if(direct == Direct.South && directs.Any(x => x == Direct.North)) MonstersDirect[i] = Direct.North; if(direct == Direct.East && directs.Any(x => x == Direct.West)) MonstersDirect[i] = Direct.West; if(direct == Direct.West && directs.Any(x => x == Direct.East)) MonstersDirect[i] = Direct.East; } powerFoodTimer.Stop(); powerFoodTimer.Interval = 10 * 1000; // ステージによって変化するかも powerFoodTimer.Start(); } void DrawMonster(int i, Graphics g) { Rectangle rect = new Rectangle(new Point(MonstersPosX[i], MonstersPosY[i]), new Size(CELL_WIDTH, CELL_HEIGHT)); if(!isMonsterIjike[i]) { 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); } else { g.DrawIcon(ijikeMonsterIcon, rect); } } } |
MoveMonstarメソッドの変更とIjikeMonstarMoveDirectメソッドの作成
いじけ状態のモンスターは動作速度するので、そのためのメソッドを作成します。IjikeMonstarMoveDirectメソッドは通常の2分の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 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 |
public partial class Form1 : Form { int[] ijikeMonstarMoveCounts = new int[4]; const int ijikeMonstarSpeedDownRate = 2; async Task<bool> MoveMonstar(int monstar) { bool ret; int ijikeMonstarMoveCount = ijikeMonstarMoveCounts[monstar]++; 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 = Direct.North; if(isMonsterIjike[monstar] && ijikeMonstarMoveCount % ijikeMonstarSpeedDownRate != 0) direct = MonstersDirect[monstar]; else direct = directs[r]; if(!isMonsterIjike[monstar]) ret = await MonstarMoveDirect(monstar, direct); else ret = await IjikeMonstarMoveDirect(monstar, direct); return ret; } async Task<bool> IjikeMonstarMoveDirect(int monstar, Direct direct) { int ijikeMonstarMoveCount = ijikeMonstarMoveCounts[monstar]; if(direct == Direct.North) { MonstersDirect[monstar] = Direct.North; for(int i = 0; i < 4; i++) { MonstersPosY[monstar] -= CELL_HEIGHT / 4 / ijikeMonstarSpeedDownRate; Invalidate(); await Task.Delay(PACMAN_DELAY); } if(ijikeMonstarMoveCount % ijikeMonstarSpeedDownRate == 0) MonstersCellY[monstar]--; } if(direct == Direct.East) { MonstersDirect[monstar] = Direct.East; for(int i = 0; i < 4; i++) { MonstersPosX[monstar] += CELL_WIDTH / 4 / ijikeMonstarSpeedDownRate; Invalidate(); await Task.Delay(PACMAN_DELAY); } if(ijikeMonstarMoveCount % ijikeMonstarSpeedDownRate == 0) MonstersCellX[monstar]++; } if(direct == Direct.South) { MonstersDirect[monstar] = Direct.South; for(int i = 0; i < 4; i++) { MonstersPosY[monstar] += CELL_HEIGHT / 4 / ijikeMonstarSpeedDownRate; Invalidate(); await Task.Delay(PACMAN_DELAY); } if(ijikeMonstarMoveCount % ijikeMonstarSpeedDownRate == 0) MonstersCellY[monstar]++; } if(direct == Direct.West) { MonstersDirect[monstar] = Direct.West; for(int i = 0; i < 4; i++) { MonstersPosX[monstar] -= CELL_WIDTH / 4 / ijikeMonstarSpeedDownRate; Invalidate(); await Task.Delay(PACMAN_DELAY); } if(ijikeMonstarMoveCount % ijikeMonstarSpeedDownRate == 0) MonstersCellX[monstar]--; } // ijikeMonstarMoveCountが偶数のときだけ // CELL_HEIGHTが4で割り切れない場合、ずれが発生するのでその補正のための処理 if(ijikeMonstarMoveCount % ijikeMonstarSpeedDownRate == 0) { Rectangle newRect = GetMazeCell(MonstersCellX[monstar], MonstersCellY[monstar]); MonstersPosX[monstar] = newRect.X; MonstersPosY[monstar] = newRect.Y; } return true; } } |
パワー餌の効果を管理する
パワー餌の効果はタイマーで管理します。パワー餌の効果が切れたらOnEndPowerFoodメソッドが実行され、モンスターがいじけ状態から復帰します。
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 |
public partial class Form1 : Form { Timer powerFoodTimer = new Timer(); public Form1() { InitializeComponent(); this.DoubleBuffered = true; this.StartPosition = FormStartPosition.CenterScreen; timer.Interval = 100; timer.Tick += Timer_Tick; timer.Start(); InitPacman(); InitMonstar(0); InitMonstar(1); InitMonstar(2); InitMonstar(3); ClearPassedPacman(); Invalidate(); // 追加部分 powerFoodTimer.Tick += PowerFoodTimer_Tick; } // パワー餌の効果が切れる private void PowerFoodTimer_Tick(object sender, EventArgs e) { OnEndPowerFood(); powerFoodTimer.Stop(); } void OnEndPowerFood() { for(int monstar = 0; monstar < isMonsterIjike.Length; monstar++) { // いじけ状態から復帰 isMonsterIjike[monstar] = false; // モンスターの位置がセルからずれている場合は補正する Rectangle newRect = GetMazeCell(MonstersCellX[monstar], MonstersCellY[monstar]); MonstersPosX[monstar] = newRect.X; MonstersPosY[monstar] = newRect.Y; } } } |
モンスターを食らう
パワー餌の効果があるときはモンスターを食べる処理も必要です。
モンスターとの当たり判定をするときにモンスターがいじけ状態かどうかを調べます。いじけ状態であるならOnEatMonsterメソッドが呼ばれます。
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 { 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; bool isGameOver = false; int monster = IsPacmanDead(); if(monster >= 0 && !isMonsterIjike[monster]) isGameOver = !await OnPacmanDead(); else if(monster >= 0 && isMonsterIjike[monster]) await OnEatMonster(monster); ignoreTick = false; if(IsStageClear) { timer.Stop(); MessageBox.Show("ゲームクリア!"); } if(isGameOver) { timer.Stop(); MessageBox.Show("GameOver"); } } } |
OnEatMonsterメソッドでは得点を計算するためにパワー餌を食べてからモンスターを何匹撃退したかも記憶させています。そして得点は原作と同じように、1匹目が200点、2匹目が400点、3匹目は800点、4匹目は1600点としています。
不思議な話なのですが、パワー餌を食べたパックマンに撃退されたモンスターは巣にもどるといじけ状態から復帰した状態で再生されます。パワー餌の効果があるときでも再生したモンスターにはやられてしまいます。(パワー餌はパックマンのパワーをアップさせる餌ではなく、モンスターをいじけさせる餌なのか??)
不思議な話ですがそのようになっているので、これもそのような仕様にしています。
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 |
public partial class Form1 : Form { int eatMonsterCount = 0; async Task<bool> OnEatMonster(int monster) { // 得点の計算 eatMonsterCount++; int add = 0; if(eatMonsterCount == 1) add = 200; if(eatMonsterCount == 2) add = 400; if(eatMonsterCount == 3) add = 800; if(eatMonsterCount == 4) add = 1600; Score += add; // 食べられたモンスターがいた位置にも点数を表示 Graphics g = Graphics.FromHwnd(this.Handle); g.DrawString( add.ToString(), new Font("MS ゴシック", 12, FontStyle.Bold), new SolidBrush(Color.White), MonstersPosX[monster], MonstersPosY[monster]); // 少し止める await Task.Delay(1000); // モンスターをもとの位置に戻す InitMonstar(monster); // いじけ状態から復帰させる isMonsterIjike[monster] = false; ijikeMonstarMoveCounts[monster] = 0; return true; } void OnEndPowerFood() { // モンスターを食べたときの得点計算用のフィールド変数をゼロに戻す eatMonsterCount = 0; // ここから下は上記と同じ for(int monstar = 0; monstar < isMonsterIjike.Length; monstar++) { isMonsterIjike[monstar] = false; Rectangle newRect = GetMazeCell(MonstersCellX[monstar], MonstersCellY[monstar]); MonstersPosX[monstar] = newRect.X; MonstersPosY[monstar] = newRect.Y; } } } |
これはスコア表示用のプロパティです。
1 2 3 4 5 6 7 8 9 10 11 12 |
public partial class Form1 : Form { int Score { get { return score; } set { score = value; label1.Text = "Score " + score.ToString(); } } } |