IMPLEMENTATION NOTES / C++ / SFML
Pac-Man (SFML Remake)
C++とSFMLで制作したPac-Manリメイク。衝突判定、候補マスから目標への二乗距離を比較するゴーストの方向選択、スプライト描画などを学習。
IMPLEMENTATION / EQUATIONS & SOURCE
入力から出力まで、コードで追う。
各節は「何を計算するか → 数式 → 実際のコード」の順に読めます。コードは動作する実装からの抜粋で、単独実行用ではありません。省略した周辺処理は参照元で確認できます。
01 / ゴーストは経路全体ではなく次の1歩を選ぶ
壁と逆走方向を除いた候補マスごとに、目標までの二乗距離を比較します。平方根は順位を変えないので計算不要です。最短経路を探索するA*ではなく、交差点ごとに局所的な方向を選ぶルールです。同距離ならコードの<=により後の候補で上書きされます。Distanceの引数はintなので、小数座標は整数へ変換した後に比較します。
D²(q,t) = (qx−tx)² + (qy−ty)²
nextDirection = arg min D²(candidate,target)float Distance(int x, int y, int x1, int y1)
{
return ((x - x1) * (x - x1)) + ((y - y1) * (y - y1));
}
// the original game didnt use a pathfinding algorithm
// simple distance comparisons are fine enough
Dir GetShortestDir(const std::vector<Dir>& squares, const Ghost& ghost, sf::Vector2f target)
{
int min_dist = 20000000;
Dir min_dir = NONE;
if (squares.size() == 0)
printf("EMPTY\n");
for (auto dir : squares) {
sf::Vector2f square = ghost.pos + dir_addition[dir];
float dir_dist = Distance(target.x, target.y, square.x, square.y);
if (dir_dist <= min_dist) {
min_dir = dir;
min_dist = dir_dist;
}
}
return min_dir;
}02 / 同じ方向選択でも目標を変えると性格が変わる
赤は現在のプレイヤー位置、桃は進行方向の4マス先、青はプレイヤー2マス先を基準に赤の位置を反転した点を目標にします。橙はプレイヤーとの二乗距離が64未満なら隅(0,31)へ切り替えます。方向選択ロジックを共有しつつ、目標の計算を分けています。
tred = player
tpink = player + 4·direction
a = player + 2·direction, tblue = 2a − red
torange = corner if D² < 64, otherwise playerこの式は公開コードのロジックを表しています。原作の全仕様や、自分独自のアルゴリズム開発を主張するものではありません。
sf::Vector2f BlinkyUpdate(Ghost& ghost)
{
return gState.player->pos;
}
sf::Vector2f PinkyUpdate(Ghost& ghost)
{
return gState.player->pos + dir_addition[gState.player->cur_dir] * 4;
}
sf::Vector2f InkyUpdate(Ghost& ghost)
{
sf::Vector2f target = gState.player->pos + dir_addition[gState.player->cur_dir] * 2;
sf::Vector2f offset = gState.ghosts[RED]->pos - target;
target = target + offset * -1;
return target;
}
sf::Vector2f ClydeUpdate(Ghost& ghost)
{
sf::Vector2f target = gState.player->pos;
// if clyde is 8 tiles away, target player, else target corner
if (Distance(ghost.pos.x, ghost.pos.y, gState.player->pos.x, gState.player->pos.y) < 64)
target = { 0,31 };
return target;
}SOURCE / SCOPE
実装の読み方。
各コード抜粋はリンク先の固定コミットから取得しています。数式は該当処理を説明するための表記です。性能や品質の数値は、掲載した計算例を除き新しい実測を行っていません。ビルド手順と依存環境は各リポジトリを参照してください。
リポジトリへ ↗