質問するログイン新規登録
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

3DCG

コンピュータの演算により、3次元空間の仮想物体を、2次元平面上で表現する手法である。

Q&A

0回答

74閲覧

キネマティックの解除時にOnCollisionExitが誤検知される問題

popyo76

総合スコア0

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

3DCG

コンピュータの演算により、3次元空間の仮想物体を、2次元平面上で表現する手法である。

0グッド

0クリップ

投稿2025/10/03 06:07

編集2025/10/03 06:08

0

0

実現したいこと

  • キネマティックの解除時にOnCollisionExitが発生しないようにしたい

前提

Unityで、球で壁を一定時間押すと動くような挙動を作りたいと考えています。
壁はRigidbodyをキネマティックに設定しているため、球で押しても動きません。

発生している問題・エラーメッセージ

押している最中に壁のキネマティックを解除すると、物理的には壁が動くようになりますが、解除した瞬間、触れているのに接触判定が外れた(OnCollisionExitが発生した)状態になってしまいます。
これにより、接触中の判定が不安定になってしまうのを解消したいです。
箱と球のCollision DetectionはContinuous Speculativeにしています。

該当のソースコード

下記は箱を押す球のソースコードです。

C#

1using UnityEditor; 2using UnityEngine; 3[RequireComponent(typeof(Rigidbody))] 4public class KeyBordMove : MonoBehaviour 5{ 6 public float moveSpeed = 10f; // 移動速度 7 public float verticalSpeed = 3f; 8 private Rigidbody rb; 9 public SphereCollider SphereCol; 10 public Rigidbody BoxRb; 11 public Collider BoxCol; 12 public float stayDuration = 2f; 13 private float timer = 0f; 14 15 void Start() 16 { 17 rb = GetComponent<Rigidbody>(); 18 rb.freezeRotation = true; 19 } 20 21 void FixedUpdate() 22 { 23 // 入力取得 24 float horizontal = Input.GetAxis("Horizontal"); // A/D または ←/→ 25 float vertical = Input.GetAxis("Vertical"); // W/S または ↑/↓ 26 float yMove = 0f; 27 if (Input.GetKey(KeyCode.LeftShift)) 28 yMove = -verticalSpeed; // 上方向 29 else if (Input.GetKey(KeyCode.Space)) 30 yMove = +verticalSpeed; // 下方向 31 // 移動量計算 32 Vector3 movement = new Vector3(horizontal, yMove, vertical) * moveSpeed; 33 34 // Rigidbody による移動 35 rb.MovePosition(rb.position + movement * Time.fixedDeltaTime); 36 } 37 void OnCollisionStay(Collision collision) 38 { 39 timer += Time.deltaTime; 40 if (timer >= stayDuration) 41 { 42 if (BoxRb != null && BoxRb.isKinematic) 43 { 44 BoxRb.isKinematic = false; 45 Debug.Log("BoxRb.isKinematic = false;"); 46 } 47 } 48 } 49 private void OnCollisionExit(Collision collision) 50 { 51 // もっとも近い点を取得 52 Vector3 closestPoint = BoxCol.ClosestPoint(transform.position); 53 // 球の表面までの距離を計算 54 float surfaceDistance = Vector3.Distance(transform.position, closestPoint) - SphereCol.radius; 55 Debug.Log($"OnCollisionExit {surfaceDistance:F3}"); 56 } 57}

このコードを実行して箱を押すと画像のような結果が得られます。
球と表面の距離が負の値であることから接しているのにOnCollisionExitが実行されていることが分かると思います。
イメージ説明

試したこと

上記コードのOnCollisionExit箇所を改良し、接触していたオブジェクトが押される用の壁であり、かつ球と箱の表面の距離が一定以内の場合はOnCollisionExit内の処理を実行しないという方法を試しました。
ただしこの方法は距離判定による補正のため、物理演算そのものは安定しておらず、高速移動や複雑な衝突条件では信頼性が低くなる可能性があります。
理想としては、距離補正に頼らずキネマティック解除時でも接触状態を正しく維持できる物理挙動の設定 を模索したいと考えています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問