Unity 之 記錄一個關于剛體穿透的問題
- 一,需求描述
- 二,遇到問題
- 三,嘗試解決
- 四,實作需求
一,需求描述
需求:使得桿能夠接住,依靠重力下落的球,
可是實作起來卻和想象的不太一樣,當桿移動速度快了就傳過去了,
效果如下:

二,遇到問題
看需求感徑訓挺簡單的,實作思路:幾個球根據重力下落,一個“桿”跟隨滑鼠移動,步驟如下:
- 創建幾個球并
Rigidbody組件,并勾選useGravity選項, - 搭建場景如下圖:

- 再創建一個Cube放大點(用來接住下落的球),也添加上
Rigidbody組件并添加MouseMove腳本:
using UnityEngine;
public class MouseMove : MonoBehaviour
{
void Update()
{
if (Input.GetMouseButton(0))
{
// 根據滑鼠位置 設定為 物體位置
Vector3 screenPos = Camera.main.WorldToScreenPoint(this.transform.position);
Vector3 mousePos = Input.mousePosition;
mousePos.z = screenPos.z;
Vector3 worldPos = Camera.main.ScreenToWorldPoint(mousePos);
// 控制物體移動
transform.position = worldPos;
}
}
}
三,嘗試解決
記得Rigidbody組件,可以通過Collision Detection屬性來用于防止快速移動的物件穿過,這下面的檢測方式都嘗試了,也沒有解決上述問題,

Unity 官方API:
| Collision Detection | 用于防止快速移動的物件穿過其他物件而不檢測碰撞, |
|---|---|
| Discrete | 對場景中的所有其他碰撞體使用離散碰撞檢測,其他碰撞體在測驗碰撞時會使用離散碰撞檢測,用于正常碰撞(這是默認值), |
| Continuous | 對動態碰撞體(具有剛體)使用離散碰撞檢測,并對靜態碰撞體(沒有剛體)使用基于掃掠的連續碰撞檢測,設定為__連續動態 (Continuous Dynamic)__ 的剛體將在測驗與該剛體的碰撞時使用連續碰撞檢測,其他剛體將使用離散碰撞檢測,用于__連續動態 (Continuous Dynamic)__ 檢測需要碰撞的物件,(此屬性對物理性能有很大影響,如果沒有快速物件的碰撞問題,請將其保留為 Discrete 設定) |
| Continuous Dynamic | 對設定為__連續 (Continuous)__ 和__連續動態 (Continuous Dynamic)__ 碰撞的游戲物件使用基于掃掠的連續碰撞檢測,還將對靜態碰撞體(沒有剛體)使用連續碰撞檢測,對于所有其他碰撞體,使用離散碰撞檢測,用于快速移動的物件, |
| Continuous Speculative | 對剛體和碰撞體使用推測性連續碰撞檢測,這也是可以設定運動物體的唯一 CCD 模式,該方法通常比基于掃掠的連續碰撞檢測的成本更低, |
測驗小結
- 測驗時也嘗試了快速移動時的檢測邏輯,在速度不是特別快的情況下,修改
Collsion Detection選項調成Continues Dynamic是可以滿足條件的,但是超過一定速度還是能穿透過去, - 記得在嘗試程序中還看到過:調整ProjectSetting -> Time-> FixedTimestep的檢測間隔進一步縮小,(例如0.003;提高物理系統的更新速度)【測驗也沒成功】
- 若是發射子彈這種邏輯,可以使用射線檢測的方式,在子彈發射的時候發射射線檢測到的碰撞點進行邏輯判斷處理,
四,實作需求
最后使用移動剛體的方式,來移動“桿”,測驗結果如下:

修改后的代碼:
using UnityEngine;
public class MouseMove : MonoBehaviour
{
private Rigidbody _rigidbody;
void Start()
{
_rigidbody = transform.GetComponent<Rigidbody>();
// 取消重力
_rigidbody.useGravity = false;
// 設定為不再受物理引擎的影響
_rigidbody.isKinematic = true;
}
void Update()
{
if (Input.GetMouseButton(0))
{
// 根據滑鼠位置 設定為 物體位置
Vector3 screenPos = Camera.main.WorldToScreenPoint(this.transform.position);
Vector3 mousePos = Input.mousePosition;
mousePos.z = screenPos.z;
Vector3 worldPos = Camera.main.ScreenToWorldPoint(mousePos);
// 控制物體移動
//transform.position = worldPos;
// 修改為剛體控制移動 --> 則不會被穿透了
_rigidbody.MovePosition(worldPos);
}
}
}
若還有不明白的地方,可以評論咨詢,或者點擊鏈接查看示例原始碼:原始碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/276285.html
標籤:其他
