⇒ 動作確認はこちらからどうぞ。
これまでは撃退されたモンスターをただちに巣に戻していましたが、原作のパックマンでは撃退されたモンスターは目玉だけになって通路を通って巣に戻ります。今回はこれを再現します。
パックマンに撃退されたらMonsterクラスのGoHome関数が呼ばれるのですが、そのとき新しく作成したメンバー変数IsGoingHomeをtrueにします。
それからMove関数も少し変更します。IsGoingHomeがtrueのときはBeginGoToHome関数とMoveGoToHome関数(後述)が呼び出されるようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class Monster { IsGoingHome: boolean = false; GoHome() { this.Direct = Direct.None; // 巣の方向がわからないのでとりあえずDirect.Noneにする this.IsGoingHome = true; } Move() { this.Position.CenterX = Math.round(this.Position.CenterX * 10) / 10; this.Position.CenterY = Math.round(this.Position.CenterY * 10) / 10; if (this.IsGoingHome) { if (this.Direct == Direct.None) this.BeginGoToHome(); else this.MoveGoToHome(); return; } // ここから下は前回と同じです。 } } |
次に問題のBeginGoToHome関数ですが、巣の方向を調べる必要があるのと巣まで戻るためには早く移動させたいので0.2移動させます。この場合、普通に移動させると0.2とか0.4ならいいのですが、0.1とか0.3の場合、交差点をオーバーランしてしまうので最初に小数点以下第一位が偶数になるようにしています。
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 |
class Monster { BeginGoToHome() { this.IsIjike = false; // IsIjikeがtrueだとMove関数が2回に1回しか実行されないのでfalseにする let x = this.Position.CenterX; let y = this.Position.CenterY; // 巣の方向を調べる。移動できる方向であるならその方向にセットする if (x < 12.5) { if (CanMoveEast(x, y)) { this.Direct = Direct.East; // 小数点以下第一位が偶数になるようにする if (x * 10 % 2 != 0) this.Position.CenterX += 0.1; } else { // 横に移動できない場合は縦なら確実に移動できる if (y <= 11 && CanMoveSouth(x, y)) { this.Direct = Direct.South; if (y * 10 % 2 != 0) this.Position.CenterY += 0.1; } else { this.Direct = Direct.North; if (y * 10 % 2 != 0) this.Position.CenterY -= 0.1; } } } else { if (CanMoveWest(x, y)) { this.Direct = Direct.West; if (x * 10 % 2 != 0) this.Position.CenterX -= 0.1; } else { if (y <= 11 && CanMoveSouth(x, y)) { this.Direct = Direct.South; if (y * 10 % 2 != 0) this.Position.CenterY += 0.1; } else { this.Direct = Direct.North; if (y * 10 % 2 != 0) this.Position.CenterY -= 0.1; } } } } } |
MoveGoToHome関数の処理は角にいるかどうか調べてその場合は適切な方向に方向転換しています。またY座標が10でX座標が12.4か12.6の場合は巣の前に到着したということなのでそのまま下に移動させています。
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 |
class Monster { MoveGoToHome() { this.Position.CenterX = Math.round(this.Position.CenterX * 10) / 10; this.Position.CenterY = Math.round(this.Position.CenterY * 10) / 10; let x = this.Position.CenterX; let y = this.Position.CenterY; if (x == 12.4 && y == 10 || x == 12.6 && y == 10) { this.Position.CenterX = 12.5; this.Position.CenterY = 13; this.Direct = Direct.North; this.IsGoingHome = false; return; } if (this.IsCrossPosition()) this.Direct = GetMonsterDirect(this, 12.5, 10, true); // 移動させる if (this.Direct == Direct.West) this.Position.CenterX -= 0.2; if (this.Direct == Direct.East) this.Position.CenterX += 0.2; if (this.Direct == Direct.North) this.Position.CenterY -= 0.2; if (this.Direct == Direct.South) this.Position.CenterY += 0.2; } } |
それから描画に関する処理も修正が必要です。IsGoingHomeがtrueのときは目玉だけ表示させます。
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 |
// 最初に目玉のイメージを取得しておく let monsterEyeImage: HTMLImageElement = null; monsterEyeImage = GetHTMLImageElement("./images/eye.png"); class Monster { Draw() { let monsterImage: HTMLImageElement = monsterImages[this.Id]; if (this.IsIjike) { if (CounterattackTime > 5000 || stoping) monsterImage = ijikeImages[0]; else { if (CounterattackTime % 1000 < 500) monsterImage = ijikeImages[0]; else monsterImage = ijikeImages[1]; } } // 目玉だけのイメージにする if (this.IsGoingHome) monsterImage = monsterEyeImage; let x = this.Position.CenterX * magnification - charctorSize / 2 + offsetX; let y = this.Position.CenterY * magnification - charctorSize / 2 + offsetY; con.drawImage(monsterImage, x, y, charctorSize, charctorSize); } } |
また当たり判定ですが、monster.IsGoingHomeがtrueなら無視しないとおかしなことになります。それからモンスターを撃退したらすぐにmonster.IsGoingHome = trueにしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
function EatMonster(monster: Monster) { // モンスターを撃退したらすぐにmonster.IsGoingHome = trueにする monster.IsGoingHome = true; // そのほかは前回と同じ stoping = true; CounterattackTime += 1000; eatMonsterCount++; score += (2 ** eatMonsterCount) * 100; setTimeout(AfterEatMonster, 1000, monster); } function IsHitMonster(monster: Monster): boolean { if (monster.IsGoingHome) return false; let x2 = (pacman.Position.CenterX - monster.Position.CenterX) ** 2; let y2 = (pacman.Position.CenterY - monster.Position.CenterY) ** 2; if (x2 + y2 < 1) { return true; } else return false; } |
それからモンスターを撃退したときに得点を表示させます。showMonsterPointフラグがtrueのあいだモンスターを撃退することで得た点数を表示させます。
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 |
let showMonsterPoint: boolean = false; let monsterX: number = 0; let monsterY: number = 0; function EatMonster(monster: Monster) { showMonsterPoint = true; monsterX = monster.Position.CenterX; monsterY = monster.Position.CenterY; stoping = true; // ここから下は同じなので省略 } function AfterEatMonster(monster: Monster) { showMonsterPoint = false; // ここから下は同じ monster.GoHome(); stoping = false; } function Draw() { DrawMazes(); DrawDots(); DrawPowerDots(); if (!isGameOver) DrawPac(); DrawMonsters(); DrawScore(); DrawRest(); if (isGameOver) { con.fillStyle = "white"; con.font = "28px 'MS ゴシック'"; con.fillText("Game Over", offsetX + 170, offsetY+295, 250); } // showMonsterPointがtrueの場合はモンスターを撃退したときの得点を表示する if (showMonsterPoint) { con.fillStyle = "white"; con.font = "28px 'MS ゴシック'"; let addscore = (2 ** eatMonsterCount) * 100; con.fillText(addscore.toString(), monsterX * magnification + offsetX, monsterY * magnification + offsetY, 250); } } |