Unity物理系統由淺入深第一節:Unity 物理系統基礎與應用
Unity物理系統由淺入深第二節:物理系統高級特性與優化
Unity物理系統由淺入深第三節:物理引擎底層原理剖析
Unity物理系統由淺入深第四節:物理約束求解與穩定性
Unity 引擎內置了一套強大且易用的物理系統,它基于 NVIDIA 的 PhysX 物理引擎。這個系統能讓你在游戲中模擬真實的物理效果,比如重力、碰撞、摩擦、彈跳等,極大地提升游戲的沉浸感和交互性。本篇教程將帶你了解 Unity 物理系統的核心組件和常用 API,讓你能夠快速地在項目中應用物理效果。
1. Rigidbody(剛體)組件:賦予物體物理屬性
在 Unity 中,任何想要受到物理系統影響的 GameObject 都必須附加一個 Rigidbody 組件。Rigidbody 賦予了 GameObject 質量、速度、角速度等物理屬性,并使其能夠響應重力、力、碰撞等物理事件。
核心屬性:
- Mass (質量):物體的質量,以千克(kg)為單位。質量越大,受到相同力的作用時加速度越小。
- Drag (阻力):線性阻力,模擬空氣阻力或液體阻力。值越大,物體運動減速越快。
- Angular Drag (角阻力):角阻力,模擬物體旋轉時的阻力。值越大,物體旋轉減速越快。
- Use Gravity (使用重力):勾選后,物體將受到 Unity 全局重力設置的影響(默認向下)。
- Is Kinematic (是否運動學):
- 如果勾選,Rigidbody 將不再受物理引擎控制,你需要通過代碼(
Transform.position
或Transform.rotation
)手動控制它的位置和旋轉。運動學剛體通常用于門、電梯等受腳本控制的物體。 - 重要提示: 運動學剛體不會受到碰撞影響而移動或旋轉,但它仍然可以影響其他非運動學剛體,并且會觸發碰撞回調。
- 如果勾選,Rigidbody 將不再受物理引擎控制,你需要通過代碼(
- Collision Detection (碰撞檢測模式):
- Discrete (離散):默認模式,在每個物理步長(Fixed Update)只檢測一次碰撞。適用于大多數情況,性能開銷低,但高速移動的物體可能會“穿透”其他物體。
- Continuous (連續):適用于高速移動的物體,會進行更頻繁的檢測以防止穿透。性能開銷比 Discrete 高。
- Continuous Dynamic (連續動態):適用于高速移動且相互之間都需要進行連續碰撞檢測的 Rigidbody。性能開銷最高。
- Constraints (約束):可以凍結剛體的特定軸向上的位置或旋轉,例如,只允許物體在 X 軸上移動,或者不允許它旋轉。
常用操作:
Rigidbody.AddForce(Vector3 force, ForceMode mode = ForceMode.Force)
:給剛體施加一個力。ForceMode.Force
: 持續力,以物體的質量計算加速度。ForceMode.Impulse
: 瞬間沖量,不考慮時間,直接改變物體的速度。常用于爆炸或打擊效果。ForceMode.VelocityChange
: 瞬間速度變化,忽略質量。ForceMode.Acceleration
: 持續加速度,忽略質量。
Rigidbody.AddTorque(Vector3 torque, ForceMode mode = ForceMode.Force)
:給剛體施加一個扭矩,使其旋轉。Rigidbody.velocity
: 獲取或設置剛體的線性速度。Rigidbody.angularVelocity
: 獲取或設置剛體的角速度。
using UnityEngine;public class BallController : MonoBehaviour
{public float moveForce = 10f;public float jumpForce = 5f;private Rigidbody rb;void Start(){rb = GetComponent<Rigidbody>();}void FixedUpdate() // 物理計算應該在 FixedUpdate 中進行{// 施加持續力,模擬移動if (Input.GetKey(KeyCode.W)){rb.AddForce(Vector3.forward * moveForce, ForceMode.Force);}if (Input.GetKey(KeyCode.S)){rb.AddForce(Vector3.back * moveForce, ForceMode.Force);}// 施加瞬間沖量,模擬跳躍if (Input.GetKeyDown(KeyCode.Space)){rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);}}
}
2. Collider(碰撞體)組件:定義物體的形狀
Collider 組件定義了 GameObject 在物理世界中的形狀,用于檢測與其他物體的碰撞。沒有 Collider 的 Rigidbody 無法與其他物體發生物理交互(除了重力)。
常見碰撞體類型:
- Box Collider (盒碰撞體):最常用的碰撞體,適用于立方體、矩形等規則形狀。性能開銷低。
- Sphere Collider (球碰撞體):適用于球體或近似球體的物體。性能開銷低。
- Capsule Collider (膠囊碰撞體):適用于人物角色、圓柱體等。性能開銷低。
- Mesh Collider (網格碰撞體):
- 使用物體的網格數據作為碰撞形狀。
- 優點: 可以完美匹配復雜模型的形狀。
- 缺點: 性能開銷高,特別是對于高多邊形模型。
- Convex (凸包) 選項:勾選后,Mesh Collider 將創建一個凸包形狀作為碰撞體。凸包的性能遠高于非凸包,并且可以與其他 Mesh Collider 發生碰撞。非凸包 Mesh Collider 只能與 Box、Sphere、Capsule 等原始碰撞體碰撞,不能與其他非凸包 Mesh Collider 碰撞。
- 通常不建議用于移動的 Rigidbody,除非設置為 Convex。
- Terrain Collider (地形碰撞體):專門用于 Unity 地形系統,自動與地形的形狀匹配。
核心屬性:
- Is Trigger (是否觸發器):
- 如果勾選,這個 Collider 將不會產生物理碰撞響應(如反彈、滑動),而是僅僅檢測到與其他 Collider 的重疊。
- 觸發器常用于檢測區域進入/離開,例如,當玩家進入一個區域時觸發劇情或打開門。
- 兩個觸發器之間不會產生碰撞回調,除非其中一個至少帶有 Rigidbody。
- 一個觸發器和一個非觸發器 Collider 之間的交互會觸發回調。
- Material (物理材質):關聯一個 Physic Material(詳見下一節)。
最佳實踐: 盡量使用簡單的原始碰撞體(Box、Sphere、Capsule)組合來近似復雜模型的形狀,而不是直接使用 Mesh Collider,以獲得更好的性能。
3. Physic Material(物理材質):定義交互特性
Physic Material 是一種資源(Asset),用于定義碰撞體之間的摩擦力和彈性(彈跳)。你可以創建不同的物理材質并將其分配給 Collider 組件。
核心屬性:
- Dynamic Friction (動態摩擦):當物體相對運動時產生的摩擦力。
- Static Friction (靜態摩擦):當物體靜止時抵抗初始運動的摩擦力。通常應該略高于 Dynamic Friction。
- Bounciness (彈跳):物體的彈性,0 表示完全不彈跳,1 表示完全彈性碰撞。
- Friction Combine (摩擦組合模式):
- Average (平均):取兩個碰撞體物理材質的摩擦力平均值。
- Minimum (最小):取兩個碰撞體物理材質摩擦力的最小值。
- Maximum (最大):取兩個碰撞體物理材質摩擦力的最大值。
- Multiply (相乘):取兩個碰撞體物理材質摩擦力的乘積。
- Bounce Combine (彈跳組合模式):同 Friction Combine,但作用于彈跳。
創建和使用:
在 Project 窗口右鍵 -> Create -> Physic Material,然后調整其屬性,并將其拖拽到 Collider 組件的 “Material” 字段上。
4. 觸發器與碰撞回調:響應物理事件
當 Rigidbody 與 Collider 發生交互時,Unity 會調用特定的回調函數。理解這些回調函數是實現游戲邏輯的關鍵。
碰撞回調 (Collision Callbacks):
適用于兩個非觸發器 Collider(至少一個帶 Rigidbody)之間的物理碰撞。
OnCollisionEnter(Collision collision)
:當物體開始與其他物體碰撞時調用一次。collision
參數包含了碰撞的詳細信息,如碰撞點 (collision.contacts
)、碰撞法線 (collision.contacts[0].normal
)、對方的 GameObject (collision.gameObject
) 和 Rigidbody (collision.rigidbody
) 等。
OnCollisionStay(Collision collision)
:當物體持續與其他物體碰撞時,每物理幀調用一次。OnCollisionExit(Collision collision)
:當物體停止與其他物體碰撞時調用一次。
觸發器回調 (Trigger Callbacks):
適用于至少有一個 Collider 設置為 Is Trigger
的情況下,檢測到物體進入/離開/停留在區域內。
OnTriggerEnter(Collider other)
:當物體開始進入觸發器區域時調用一次。other
參數是進入或離開觸發器區域的 Collider。
OnTriggerStay(Collider other)
:當物體持續停留在觸發器區域內時,每物理幀調用一次。OnTriggerExit(Collider other)
:當物體離開觸發器區域時調用一次。
重要規則:
- 只有當一個 Collider 附加了 Rigidbody,或者它是一個 Kinematic Rigidbody 上的 Collider 時,它才能接收到碰撞/觸發器回調。
- 注意: 如果是靜態(不帶 Rigidbody)的 Collider 之間發生碰撞,雖然物理系統會處理它們之間的交互,但不會調用任何回調函數。
using UnityEngine;public class CollisionDetector : MonoBehaviour
{// 當發生碰撞時void OnCollisionEnter(Collision collision){Debug.Log("OnCollisionEnter: " + gameObject.name + " 撞到了 " + collision.gameObject.name);// 可以在這里獲取碰撞點、法線等信息foreach (ContactPoint contact in collision.contacts){Debug.Log("碰撞點: " + contact.point + ", 法線: " + contact.normal);}}// 當進入觸發器區域時void OnTriggerEnter(Collider other){Debug.Log("OnTriggerEnter: " + gameObject.name + " 進入了觸發器區域 " + other.gameObject.name);if (other.CompareTag("Collectible")) // 假設我們有一個Tag為"Collectible"的物體{Debug.Log("拾取了物品!");Destroy(other.gameObject); // 銷毀被拾取的物品}}
}
5. 射線檢測(Raycast)與形狀檢測:非碰撞交互
除了碰撞體之間的物理交互,Unity 也提供了用于檢測特定方向或形狀是否存在物體的 API,這在很多游戲邏輯中非常有用,例如射擊游戲中的子彈檢測、角色控制器中的地面檢測等。
射線檢測 (Raycast):
從一個點發射一條射線,檢測是否擊中物體。
Physics.Raycast(Vector3 origin, Vector3 direction, out RaycastHit hitInfo, float maxDistance)
:origin
: 射線的起點。direction
: 射線的方向。hitInfo
: 一個RaycastHit
結構體,用于存儲擊中物體的信息(如擊中點、法線、被擊中的 Collider 和 GameObject 等)。maxDistance
: 射線的最大檢測距離。
- 還可以指定
LayerMask
來過濾檢測的層級。
using UnityEngine;public class RaycastExample : MonoBehaviour
{public LayerMask hitLayer; // 設置一個層級,只檢測這個層級的物體void Update(){// 從攝像機向鼠標點擊位置發射射線if (Input.GetMouseButtonDown(0)){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit, 100f, hitLayer)) // 檢測最遠100米,只檢測hitLayer層的物體{Debug.Log("射線擊中了: " + hit.collider.gameObject.name + " 在位置: " + hit.point);// 可以在這里對被擊中的物體進行操作hit.collider.gameObject.GetComponent<Renderer>().material.color = Color.red;}else{Debug.Log("射線未擊中任何物體。");}}}
}
形狀檢測 (Shape Cast):
除了射線,你還可以發射一個球體、膠囊體或盒子來檢測是否與場景中的 Collider 發生重疊或碰撞。這比 Raycast 更適合檢測更大范圍的障礙物。
Physics.SphereCast(Vector3 origin, float radius, Vector3 direction, out RaycastHit hitInfo, float maxDistance, LayerMask layerMask)
:發射一個球體。Physics.BoxCast(Vector3 center, Vector3 halfExtents, Vector3 direction, out RaycastHit hitInfo, Quaternion orientation, float maxDistance, LayerMask layerMask)
:發射一個盒子。Physics.CapsuleCast(...)
:發射一個膠囊體。
這些方法與 Raycast
類似,只是將線替換成了對應的形狀,用于更精確或范圍更大的檢測。
總結
至此,你已經掌握了 Unity 物理系統的核心基礎:
- Rigidbody 是物體參與物理模擬的必備組件。
- Collider 定義了物體的碰撞形狀。
- Physic Material 決定了碰撞時的摩擦和彈跳特性。
- 碰撞回調和觸發器回調 讓你能夠響應物理事件并執行游戲邏輯。
- 射線檢測和形狀檢測 提供了在不發生物理交互的情況下查詢物理世界的能力。
熟練運用這些基礎功能,你就能在 Unity 中構建出豐富多樣的物理交互和游戲玩法。在下一篇文章中我們將進入更深層次的探索,了解如何利用高級特性實現復雜交互,并關注性能優化,讓你的物理模擬既強大又流暢
Unity物理系統由淺入深第一節:Unity 物理系統基礎與應用
Unity物理系統由淺入深第二節:物理系統高級特性與優化
Unity物理系統由淺入深第三節:物理引擎底層原理剖析
Unity物理系統由淺入深第四節:物理約束求解與穩定性