トップ制作ノート > 床をすり抜けるバグ

床をすり抜けるバグは、なぜ速く落ちたときだけ起きるのか

制作ノート / ヤネランの当たり判定

この記事の内容
  1. ゆっくり落ちれば乗れるのに、速く落ちると抜ける
  2. ゲームは「パラパラ漫画」で動いている
  3. 点で調べると、間を飛び越える
  4. 直し方1:前のコマの位置も見る
  5. 直し方2:落ちる速さに上限をつける
  6. もう1つ見つかった、めり込んで即死するバグ
  7. まとめ

ゆっくり落ちれば乗れるのに、速く落ちると抜ける

ヤネランは、屋根から屋根へ跳び移りながら走るゲームです。 当然、屋根に着地できなければ成立しません。

ところが、あるとき妙な現象に気づきました。 普通に跳んで落ちる分には問題なく着地できるのに、 高いところから一気に落ちたときや、急降下したときだけ、屋根をすり抜けて下まで落ちていくのです。

当たり判定のコード自体は間違っていません。実際、ゆっくり落ちれば正しく着地します。 では、なぜ速いときだけ失敗するのか。

ゲームは「パラパラ漫画」で動いている

ブラウザのゲームは、なめらかに動いているように見えて、実際には1秒間に約60枚の絵を描き替えているだけです。 パラパラ漫画と同じで、1枚ごとに登場人物の位置を少しずつずらしています。

落下も同じで、1枚ごとに「下へ何ピクセル動かす」という計算をしています。 落ちる速さが増すほど、1枚あたりの移動距離は大きくなります。

ここに落とし穴がありました。落下が速いと、1枚の絵と次の絵の間で20ピクセル以上も移動していたのです。 屋根の厚みより、1コマの移動量のほうが大きくなっていました。

点で調べると、間を飛び越える

当時の着地判定は、こういう考え方でした。

「今この瞬間、足の位置が屋根の高さの近くにあるか?」

ゆっくり落ちているときは、足が屋根のすぐ上を通る瞬間が必ず1コマは存在するので、これで問題ありません。

しかし速く落ちると、屋根の上にいたコマの次には、もう屋根の下まで通り過ぎている。 判定の窓を、1コマで丸ごと飛び越えてしまうのです。 各コマでは常に「屋根の近くにいない」ので、着地は一度も検出されません。

ここで大事なのは、判定の式そのものは間違っていなかったということです。 「足が屋根の高さにあるか」を調べる計算は正しく動いていました。 問題は、調べるタイミングとタイミングの間に、体が屋根を通り過ぎていたことです。 式ではなく、調べる回数と間隔のほうに原因がありました。

これは特定のゲームの問題ではなく、2Dでも3Dでも起きる古典的な現象です。 「速く動く物体が薄い壁を通過してしまう」というのは、当たり判定の定番の落とし穴でした。

直し方1:前のコマの位置も見る

解決策は、点で見るのをやめることです。今の位置だけでなく、1つ前のコマの足の位置も一緒に見るようにしました。

判定の考え方は、こう変わります。

「前のコマでは屋根より上にいて、今のコマでは屋根より下にいる。ならば、その間に屋根を通過したはずだ」

間にあるものを直接は見ていなくても、前後を比べれば通過したことは分かります。 通過したと判定できたら、足を屋根の上に戻して着地させる。これですり抜けはなくなりました。

ちなみにこの考え方は、指でなぞる操作の取りこぼしを直したときとまったく同じ発想です。 点ではなく、前回と今回を結んだ線で考える。別のゲームの、別の不具合でしたが、原因の形は同じでした。

直し方2:落ちる速さに上限をつける

判定を直したうえで、保険として落下速度そのものに上限も設けました。 どれだけ高いところから落ちても、1コマの移動量が一定以上にはならないようにしています。

判定を直したのだから不要にも思えますが、 速さが青天井だと、いずれ別の場所で似た問題が出ます。 上限を決めておけば、そもそも極端な状況が起きません。 遊び心地の面でも、落下が速すぎると反応する時間がなくなるので、上限があったほうが自然でした。

もう1つ見つかった、めり込んで即死するバグ

当たり判定を見直す過程で、別の不具合も見つかりました。 ゲーム開始から15メートルほどで、ほぼ必ず死ぬという症状です。

原因は建物の並べ方にありました。建物どうしをすき間なく並べてしまうと、 前の建物より高い屋根に対して、横から体がめり込む状態が発生します。 横からぶつかったのに、判定上は「屋根の下にいる」となり、そのまま落下扱いになっていました。

対策は3つです。

  • 建物を並べるとき、必ずすき間を空ける(初期配置も含めて)
  • 隣の建物との屋根の高低差を制限する。上りは特に厳しく制限した
  • 「屋根よりかなり下に体がある=壁に激突」という判定を明示的に足す

2つ目の高低差の制限には、遊びやすさの理由もあります。 このゲームの傘は落下を遅くするだけで、高さは稼げません。 上りの段差が大きすぎると、どうやっても越えられない場所が生まれて詰んでしまいます。 そのため上りの段差は下りより厳しく制限しています。

まとめ

  • すり抜けの多くは、当たり判定の式ではなく1コマの移動量が大きすぎることが原因
  • 今の位置だけを見る「点の判定」は、速い動きに弱い
  • 前のコマと今のコマを比べると、間を通過したことが分かる
  • 速度に上限を設けておくと、将来の似た問題も防げる
  • プレイヤーの移動能力(このゲームでは傘)を基準に、越えられない地形が生まれないよう制限する

実際に走ってみる

修正後のヤネランは、急降下を使って攻めても、ちゃんと屋根に乗れます。1回1〜3分です。

🏃 ヤネランを遊ぶ

ほかの制作ノート

CPUを「ちょうどよく弱く」する方法相手が絶対に勝てないバグを見つけた話制作ノートの一覧