【クソゲープロジェクト】前提として普通のパックマンをつくる(2)の続きです。ようやくメインコンテンツです。挟み撃ちのアルゴリズムで絶対に逃げられないパックマンをつくる方法を考えます。

単純に最短経路を採用するだけではモンスターが列をなして動くだけで挟み撃ちにはなりません。そこで以下のように考えます。

(1) もっとも近い敵には最短経路でプレイヤーを追跡する。
(2) もっとも近い敵が最後にプレイヤーを捕まえるときどの方向から捕まえるかをしらべて、その他の敵にはそれとは別の方向から捕まえるための最短経路を考える。
(3) これを繰り返す。もし適切な行動が存在しない敵はランダムで移動方向を考える。

最短経路の計算

何度も最短経路を計算すると計算量が増えるのでマップを4分の1に縮小したものを考えます。これで計算量をだいぶ減らせます。

これは4分の1に縮小したマップの二次元配列を取得する関数です。一度取得したら同じものを使い回します。

ShortestInfoクラスの定義

ShortestInfoクラスを定義します。どの方向から捕まえるかで最短経路とそのコストを取得して格納できるようにします。プレイヤーの位置によってはその方向からは捕まえることができない場合があります。その場合はFromXXXCost は 9999、FromXXXPath配列の要素は空です。

最短経路に情報の収集

それぞれの敵のプレイヤーまでの最短経路に関する情報を取得する処理を示します。

プレイヤーと敵はminiMap上であればどの座標に存在するかを調べます。そのあとプレイヤーがいる座標は通れないことにしてその上下左右の座標への最短経路を計算します。これで各敵の最大4通りの最短経路が取得できます(実際に4通りの最短経路が存在するのはプレイヤーが交差点にいるときだけ。ほとんどの場合は2通りしか存在しない)。

getShortestPathToPower関数はプレイヤーの現在位置から引数で渡されたパワー餌までの最短経路のコストを計算します。

最短経路から敵の行動を決定する

最短経路から敵が次に移動すべき方向を取得する処理を示します。

enemiesThink関数の修正

enemiesThink関数を定義しなおします。

最短経路に関する情報を取得したあとどの方向から捕まえるかでそれぞれのコストと最初に動くべき方向を調べてオブジェクトに格納します。

そのあともっともプレイヤーの近くにいる敵には最短経路で追跡させます。それ以外の敵には別の方向から捕まえるための最短経路が短い敵に追跡させます。行動がすでに決定した敵と捕まえる方向が確定したオブジェクトは除外して対象がなくなるまでこれを繰り返します。

イジケ状態のときやプレイヤーの近くにパワー餌がある場合は逆襲を避けるためにプレイヤーからは離れる行動を取らせます。ただしプレイヤーとその近くにあるパワー餌があっても敵がもっと近くに接近している場合は逃げずに追跡させます(もちろん敵がイジケ状態であってはならない)。

移動方向がきまってもマップを4分の1にしているので実際にはその方向に移動することができない場合があります。その場合は移動方向の変更はしません。すでに壁に突き当たっている場合は移動できる方向を設定します。

この方法で適切な移動方向を見つけることができなかった敵は、取得できた移動方向に移動できない場合と同様に、現在の進行方向に移動可能ならその方向を、すでに壁に突き当たっている場合は移動できる方向を設定します。

プレイした感想

実際にプレイしてみた感想。[パワー餌なし]だと[敵の折り返しを禁止する]オプションを有効にしても無理ゲーです。パワー餌があると敵が自分から逃げてくれる場合があるのでやりやすく感じる場合が間々あります。