Unityで「オブジェクトがすり抜ける」原因と対処法まとめメモ【実体験のお話】

Unityを使って、3Dのキャラクターを動かして衝突判定を検知させる処理を書いた時、オブジェクトがすり抜けるのはあるあるだと思います。
かくいう私もその一人で、一度調べても内容を忘れてまた同じような調査からはじめて時間を無駄にしてしまうのもまたあるあるです。

なので一旦自分が調べた内容をここにまとめることにしました。
内容に間違いがあったり、追加情報が必要なときは追記していきたいと思います。
使っているUnityのバージョンは2022が多めです(状況によってバージョンが違ったり)

よくミスってた項目まとめ

チェックリストのように、注意すべき点を先に列挙しておきます。

  1. 物理判定の更新頻度(FixedUpdate)に対して移動速度が速すぎる
  2. Rigidbodyの Collision Detection が「Discrete」になっていた
  3. Colliderのサイズがギリギリで、すき間に入り込んでいた
  4. Transform.Translate()で移動していた

自分がよく遭遇するのはこの辺りです。

と、ここまで書いたはいいもののまとめるのは面倒だな…と思って、最近の相棒である「ChatGPT」先生に上記の問題点・確認事項について問いかけて情報をまとめてもらうことにしました←

以下は、ChatGPTで上記内容についてまとめてもらった回答です。


物理判定の更新頻度(FixedUpdate)に対して移動速度が速すぎる(GPT回答)

Unityの物理演算は FixedUpdate() 内で処理されます。つまり、毎フレームではなく、一定の間隔(デフォルトでは0.02秒=50FPS相当)で物理演算が実行されています。

これに対してキャラクターの移動速度が速すぎると、「1回の物理判定で壁の向こう側まで移動してしまい、衝突を検知できない」状態になります。これがいわゆる**トンネル現象(Tunneling)**です。

🔧対策:
  • Time.fixedDeltaTime を確認して必要なら調整する
  • 移動速度を物理フレームレートに合わせて制御する
  • Rigidbody の Collision Detection を Continuous にする(次項)

Rigidbodyの Collision Detection が「Discrete」になっていた(GPT回答)

Collision Detection は Rigidbody に設定されている衝突判定方式で、デフォルトでは Discrete(離散的)になっています。

💥違いの概要:
モード説明
Discrete通常の処理。高速移動で衝突を検知できないこともある
Continuous高速移動中の衝突も検知。処理負荷はやや増える
Continuous Dynamicより精度の高い衝突検知。動くもの vs 動くものにも対応(主に Rigidbody 同士)
🔧対策コード例:
csharp
var rb = GetComponent<Rigidbody>();
rb.collisionDetectionMode = CollisionDetectionMode.Continuous;

これを使うことで、移動中の軌跡も考慮され、すり抜けにくくなります。


Colliderのサイズがギリギリで、すき間に入り込んでいた(GPT回答)

これは主に複数のオブジェクトで壁などを構成している場合に起こりがちです。

一見つながって見えるブロックでも、Collider の境目に微妙なすき間ができていることがあります。プレイヤーのコライダーがそこにハマってしまい、物理的にすり抜けてしまうパターンです。

🔧対策:
  • コライダーのサイズをわずかに拡張(0.05〜0.1程度)
  • コリジョン判定用の Invisible Collider を別で配置
  • MeshCollider を手動結合する(動的に生成すると負荷高め)
  • 複数の壁を物理的に1つの「地形」として扱う(Staticにする)

Transform.Translate()で移動していた(GPT回答)

これも初心者あるあるですが、Transform.Translate()transform.position = ~ でオブジェクトを動かしていると、物理エンジンを通さずに移動するため、衝突判定が無視されることになります。

🔧代わりに使うべきもの:
  • Rigidbody.MovePosition()(物理演算に則った移動)
  • Rigidbody.velocity の調整(移動力を制御)
csharp
// 推奨される移動方法の例
rb.MovePosition(rb.position + moveDirection * moveSpeed * Time.fixedDeltaTime);

MovePositionFixedUpdate() 内で呼び出すことを推奨します。


まとめ(GPT回答)

オブジェクトがすり抜ける原因は1つではなく、複数の要素が絡み合っていることが多いです。
特に以下の4点は、開発中に何度も見直すことになるので、チェックリストとして手元に置いておくと安心です。

  • 移動速度と FixedUpdate の関係
  • Rigidbody の Collision Detection 設定
  • Collider の構造やすき間
  • Transform による直接移動を避ける

最後に

ここまでがChatGPTが書いた文章です。


……自分が対策したこと、調べたことは大体まとめてくれちゃってますね。
この間なんと数十秒程度。
もうほんとこいつが全部ブログやればいいんじゃないかな?←

はい、というわけで特に書くことがなくなったので、もし内容に何か問題があったらChatGPTのせいです。という言い訳を置いてこの話は一旦締めたいと思います。

—–

もし本当に間違ったこと・認識違いなことを書いていた場合、修正しますのでご指摘のほどよろしくお願いしますmm

コメント

タイトルとURLをコピーしました