天天看點

Unity 之 記錄一個關于剛體穿透的問題一,需求描述二,遇到問題三,嘗試解決四,實作需求

@ TOC

一,需求描述

需求:使得杆能夠接住,依靠重力下落的球。

可是實作起來卻和想象的不太一樣,當杆移動速度快了就傳過去了。

效果如下:

Unity 之 記錄一個關于剛體穿透的問題一,需求描述二,遇到問題三,嘗試解決四,實作需求

二,遇到問題

看需求感覺還挺簡單的。實作思路:幾個球根據重力下落,一個“杆”跟随滑鼠移動。步驟如下:

  • 建立幾個球并

    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 之 記錄一個關于剛體穿透的問題一,需求描述二,遇到問題三,嘗試解決四,實作需求

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;提高實體系統的更新速度)==【測試也沒成功】==
  • 若是發射子彈這種邏輯,可以使用射線檢測的方式,在子彈發射的時候發射射線檢測到的碰撞點進行邏輯判斷處理。

四,實作需求

最後使用移動剛體的方式,來移動“杆”,測試結果如下:

Unity 之 記錄一個關于剛體穿透的問題一,需求描述二,遇到問題三,嘗試解決四,實作需求

修改後的代碼:

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);
        }
    }
}           

繼續閱讀