⇒ 動作確認はこちらからどうぞ。
前回は迷路をつくる部分だけをやりましたが、今回はパックマンを動かすためのclassを作成します。
が、そのまえにやっておくことがあります。
まず、パックマンやモンスターを表示するときに必要なイメージファイルの準備です。これは素材が公開されていたのでこれをそのまま使います。
それからパックマンやモンスターの移動方向や座標を管理する手段が必要です。そのためのクラスを示します。
1 2 3 4 5 6 7 8 9 10 11 12 |
class Direct { static None = 0; static North = 1; static South = 2; static West = 3; static East = 4; } class Position { CenterX: number = 0; CenterY: number = 0; } |
ではPacmanクラスを示します。
クラス内でやっていることはパックマンの移動と描画に関することと、ゲーム開始時にパックマンを初期位置に戻す処理です。パックマンが移動して餌を食べたり、モンスターと接触したときの処理はここでは書いていません。パックマンだけで自己完結することのみを書き、他のオブジェクトと関係することはクラスの外部でおこないます。
パックマンの進行方向は変数Directに代入しておき、Move関数が呼ばれるたびにパックマンの座標を変更します。XY座標はパックマンの中心部分の座標です。ところで進行方向を管理する変数がDirect、NextDirect、PrevDirectと3種類もあるのですが、これには理由があります。
移動中にキー操作でパックマンの進行方向を変えるのですが、現在パックマンが存在する場所では方向転換できない場合があります。そこでとりあえずNextDirectに代入しておき、パックマンが交差点やT字路(正しい日本語では丁字路(ていじろ)と呼ぶらしい)に到達して進路変更できるようになってからDirectに代入します。
また壁にぶつかった場合、パックマンはそれ以上、その方向に移動することはできません。このようなときはDirect.Noneを代入しています。
パックマンのイメージの描画は進行方向によって変わります。GetImageFromDirect関数でこれを求めているのですが、Direct == Direct.NoneのときはGetImageFromDirect関数にDirect.Noneを渡すと見当外れなイメージが返されるので、そのときのために前回移動に成功した方向をPrevDirectに保存しています。Direct == Direct.NoneのときはGetImageFromDirect関数にPrevDirectを渡して、パックマンを描画するときのイメージを求めています。
移動できるかどうかはパックマンの現在の座標から調べることができます。モンスターについても同じことがいえるので、それを判断する関数はクラスの外に書いています(後述)。パックマンもモンスターも移動するキャラクタなのでベースになるクラスを作成して、これを継承してPacmanクラスとMonsterクラスをつくるという方法のほうがよかったのかもしれませんが・・・。
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 |
class Pacman { Position: Position = null; Direct: number = Direct.West; NextDirect: number = Direct.West; PrevDirect: number = Direct.West; constructor() { this.Position = new Position(); this.Direct = Direct.West; this.NextDirect = Direct.West; } GoHome() { this.Position.CenterX = 12.5; this.Position.CenterY = 22; this.Direct = Direct.West; this.NextDirect = Direct.West; } Move(): void { if (this.Direct == Direct.West) this.Position.CenterX -= 0.1; if (this.Direct == Direct.East) this.Position.CenterX += 0.1; if (this.Direct == Direct.North) this.Position.CenterY -= 0.1; if (this.Direct == Direct.South) this.Position.CenterY += 0.1; // 小数点以下第二位以降があるとCanMove~関数がうまく機能しないので四捨五入する let x = Math.round(this.Position.CenterX * 10) / 10; let y = Math.round(this.Position.CenterY * 10) / 10; this.Position.CenterX = x; this.Position.CenterY = y; // this.NextDirect が移動できる方向であるならthis.Directに代入する if (CanMoveSouth(x, y) && this.NextDirect == Direct.South) this.Direct = Direct.South; if (CanMoveNorth(x, y) && this.NextDirect == Direct.North) this.Direct = Direct.North; if (CanMoveEast(x, y) && this.NextDirect == Direct.East) this.Direct = Direct.East; if (CanMoveWest(x, y) && this.NextDirect == Direct.West) this.Direct = Direct.West; // ワープトンネルに入った場合、反対側から出てくるようにする if ((x == 0 && y == 13) && this.Direct == Direct.West) this.Position.CenterX = 25; if ((x == 25 && y == 13) && this.Direct == Direct.East) this.Position.CenterX = 0; // this.Directが移動できない方向であるならthis.Directには Direct.Noneを代入して動きを止める if (!CanMoveSouth(x, y) && this.Direct == Direct.South) this.Direct = Direct.None; if (!CanMoveNorth(x, y) && this.Direct == Direct.North) this.Direct = Direct.None; if (!CanMoveEast(x, y) && this.Direct == Direct.East) this.Direct = Direct.None; if (!CanMoveWest(x, y) && this.Direct == Direct.West) this.Direct = Direct.None; // パックマンが餌を食べたか、モンスターと接触したかの処理は // クラスの外部にある下記の2つの関数内でおこなう。 CheckEatDot(); CheckHitMonster(); // 移動に成功した場合、それをthis.PrevDirectに保存しておく if (this.Direct != Direct.None) this.PrevDirect = this.Direct; } // パックマンの移動している方向から適切な描画用のイメージを求める GetImageFromDirect(direct: number): HTMLImageElement { if (direct == Direct.North) return pacmanNorthImage; else if (direct == Direct.South) return pacmanSouthImage; else if (direct == Direct.East) return pacmanEastImage; else if (direct == Direct.West) return pacmanWestImage; else return pacmanWestImage; } Draw() { // 別のところで // const offsetX = 40; const offsetY = 60; // const magnification = 18.0; const charctorSize = 35;と定義されている // パックマンの中心座標から左上の座標を求める let x = this.Position.CenterX * magnification - charctorSize / 2 + offsetX; let y = this.Position.CenterY * magnification - charctorSize / 2 + offsetY; // パックマンのthis.Direct、this.DirectがDirect.Noneの場合は // this.PrevDirectから描画するときに使用するイメージを求める let pacmanImage: HTMLImageElement = pacmanNorthImage; if (this.Direct != Direct.None) pacmanImage = this.GetImageFromDirect(this.Direct); else pacmanImage = this.GetImageFromDirect(this.PrevDirect); con.drawImage(pacmanImage, x, y, charctorSize, charctorSize); } } |
次に指定された進行方向に本当に移動できるのかを調べる関数を示します。
長いですが、迷路上の座標から東西南北に移動できるかどうかを調べているだけです。
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 |
function CanMoveNorth(x, y) { if (x == 0 || x == 25) { if (0 < y && y <= 7) return true; if (19 < y && y <= 22) return true; if (25 < y && y <= 28) return true; return false; } if (x == 2 || x == 23) { if (22 < y && y <= 25) return true; return false; } if (x == 5 || x == 20) { if (0 < y && y <= 25) return true; return false; } if (x == 8 || x == 17) { if (4 < y && y <= 7) return true; if (10 < y && y <= 19) return true; if (22 < y && y <= 25) return true; return false; } if (x == 11 || x == 14) { if (0 < y && y <= 4) return true; if (7 < y && y <= 10) return true; if (19 < y && y <= 22) return true; if (25 < y && y <= 28) return true; return false; } return false; } |
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 |
function CanMoveSouth(x, y) { if (x == 0 || x == 25) { if (0 <= y && y < 7) return true; if (19 <= y && y < 22) return true; if (25 <= y && y < 28) return true; return false; } if (x == 2 || x == 23) { if (22 <= y && y < 25) return true; return false; } if (x == 5 || x == 20) { if (0 <= y && y < 25) return true; return false; } if (x == 8 || x == 17) { if (4 <= y && y < 7) return true; if (10 <= y && y < 19) return true; if (22 <= y && y < 25) return true; return false; } if (x == 11 || x == 14) { if (0 <= y && y < 4) return true; if (7 <= y && y < 10) return true; if (19 <= y && y < 22) return true; if (25 <= y && y < 28) return true; return false; } return false; } |
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 |
function CanMoveEast(x, y) { if (y == 0) { if(0 <= x && x <11) return true; if (14 <= x && x < 25) return true; return false; } if (y == 4) { if (0 <= x && x < 25) return true; return false; } if (y == 7) { if (0 <= x && x < 5) return true; if (8 <= x && x < 11) return true; if (14 <= x && x < 17) return true; if (20 <= x && x < 25) return true; return false; } if (y == 10) { if (8 <= x && x < 17) return true; return false; } if (y == 13) { if (0 <= x && x < 8) return true; if (17 <= x && x < 25) return true; return false; } if (y == 16) { if (8 <= x && x < 17) return true; return false; } if (y == 19) { if (0 <= x && x < 11) return true; if (14 <= x && x < 25) return true; return false; } if (y == 22) { if (0 <= x && x < 2) return true; if (5 <= x && x < 20) return true; if (23 <= x && x < 25) return true; return false; } if (y == 25) { if (0 <= x && x < 5) return true; if (8 <= x && x < 11) return true; if (14 <= x && x < 17) return true; if (20 <= x && x < 25) return true; return false; } if (y == 28) { if (0 <= x && x < 25) return true; return false; } return false; } |
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 |
function CanMoveWest(x, y) { if (y == 0) { if (0 < x && x <= 11) return true; if (14 < x && x <= 25) return true; return false; } if (y == 4) { if (0 < x && x <= 25) return true; return false; } if (y == 7) { if (0 < x && x <= 5) return true; if (8 < x && x <= 11) return true; if (14 < x && x <= 17) return true; if (20 < x && x <= 25) return true; return false; } if (y == 10) { if (8 < x && x <= 17) return true; return false; } if (y == 13) { if (0 < x && x <= 8) return true; if (17 < x && x <= 25) return true; return false; } if (y == 16) { if (8 < x && x <= 17) return true; return false; } if (y == 19) { if (0 < x && x <= 11) return true; if (14 < x && x <= 25) return true; return false; } if (y == 22) { if (0 < x && x <= 2) return true; if (5 < x && x <= 20) return true; if (23 < x && x <= 25) return true; return false; } if (y == 25) { if (0 < x && x <= 5) return true; if (8 < x && x <= 11) return true; if (14 < x && x <= 17) return true; if (20 < x && x <= 25) return true; return false; } if (y == 28) { if (0 < x && x <= 25) return true; return false; } return false; } |