2024/6/22(土)

2Dゲームの当たり判定処理に関する研究をした。いずれブログにまとめたい。

主にこの記事を参考にしたのだが、ちょっと実装をミスっただけで大きくバグるので、どういう仕組みで動いていてどの部分がキモなのかを整理した。

1つ目、右下座標の取り方。この記事の例だと主人公のサイズが32×32なので、タイルとの交差判定を行う右下座標は(x+31,y+31)になる。これを(x+32,y+32)にしてしまうと大変なことになる。

自機座標を整数で管理しているなら単に(x+w-1,y+h-1)とすればよいのだが、floatなど浮動小数で管理している場合は難しい。自分は試しに(x+w-0.01,y+h-0.01)などとして実装したらうまく動作した。0でない極小の値なら多分よい。あるいは大なり小なり以上以下を駆使して真面目に端を計算すればいいのかもしれない。

2つ目、「重力加速度の加算」「速度の加算」「衝突判定」の順番。これはこの通りの順番で処理を行わないと床の上で振動する。例えば速度の加算を先にやると、重力で床に衝突するフレームと速度0で床の上に存在するだけのフレームが交互になる。このせいでジャンプができたりできなくなったりする。

3つ目、Y軸移動→Y軸衝突判定→X軸移動→X軸衝突判定という順番を守ること。X軸とY軸の計算順序は入れ替えても良いが、移動と判定のセットを座標軸別にやるというのがキモなのでそこを外すとバグる。

例えばXY軸それぞれ移動→衝突判定などとするとこうなってしまう。

一応の回避策として、else ifを用いて天井判定と床判定を排他的にしたり左壁判定と右壁判定を排他的にすることで一見良い感じに動かすことができる。しかしこれは天井判定と床判定のどちらを優先するかにより、L字の配置と上下逆L字の配置のどちらかで結局バグってしまうのでオススメできない。

この移動→衝突判定のセットを座標軸別にやるという手法はどうやら広く知られているようなのだが、名前が付いていない。「座標軸別変位衝突法」と仮に呼ぶことにした。

単純な座標軸別変位衝突法には弱点がある。ジャンプして壁に触れるか触れないかあたりの場所でジャンプすると横にずれる挙動ができない。これは考えてみれば当たり前のことで、X軸方向に動かして衝突チェック→X軸補正という仕組みである以上、X軸方向の変位が0ならばX軸方向に補正されようがない。この辺を良い感じにする実装は色々あると思うが、ちょっと実際の実装例をネットで見つけれていない。CelesteのPlayer.csは公開されているのでいずれ読解したい。

Categories: