実現したいこと
- キネマティックの解除時に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内の処理を実行しないという方法を試しました。
ただしこの方法は距離判定による補正のため、物理演算そのものは安定しておらず、高速移動や複雑な衝突条件では信頼性が低くなる可能性があります。
理想としては、距離補正に頼らずキネマティック解除時でも接触状態を正しく維持できる物理挙動の設定 を模索したいと考えています。

あなたの回答
tips
プレビュー