@ TOC
一,需求描述
需求:使得杆能夠接住,依靠重力下落的球。
可是實作起來卻和想象的不太一樣,當杆移動速度快了就傳過去了。
效果如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLwMTNxMDOyIjMzEDNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
二,遇到問題
看需求感覺還挺簡單的。實作思路:幾個球根據重力下落,一個“杆”跟随滑鼠移動。步驟如下:
- 建立幾個球并
元件,并勾選Rigidbody
選項。useGravity
- 搭建場景如下圖:
Unity 之 記錄一個關于剛體穿透的問題一,需求描述二,遇到問題三,嘗試解決四,實作需求 - 再建立一個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);
}
}
}