This document is about: QUANTUM 3
SWITCH TO

Collider and Body Components

簡介

在 Quantum 2 中,碰撞和物理行為各自擁有獨立的組件。

  • 向實體添加 PhysicsCollider2D/PhysicsCollider3D 會將該實體轉換為動態障礙物或觸發器,可通過其變換進行移動。
  • 添加 PhysicsBody2D/PhysicsBody3D 可使實體由物理求解器控制。

需求

Transform2D/Transform3D、PhysicsCollider2D/PhysicsCollider3D 和 PhysicsBody2D/PhysicsBody3D 組件緊密相連。因此,某些組件的運行需要其他組件作為依據。完整的依賴列表如下:

需求 變換 物理碰撞體(PhysicsCollider) 物理體(PhysicsBody)
組件
變換
物理碰撞體(PhysicsCollider)
物理體(PhysicsBody)

這些依賴關係相互疊加,因此要啟用 PhysicsBody,必須按以下順序向實體添加組件:

  1. 變換(Transform)
  2. 物理碰撞體(PhysicsCollider)
  3. 物理體(PhysicsBody)

有關碰撞回調的詳細信息,請參閱此處

PhysicsBody 組件

向實體添加 PhysicsBody ECS 組件可使該實體被物理引擎考慮在內。注意: 使用 PhysicsBody 要求實體已具有 TransformPhysicsCollider

可以手動在代碼中創建和初始化組件,也可以通過 Unity 中的 QuantumEntityPrototype 組件進行。

C#

    var entity = f.Create();
    var transform = new Transform2D();
    var collider = PhysicsCollider2D.Create(f, Shape2D.CreateCircle(1));
    var body = PhysicsBody2D.CreateDynamic(1);

    f.Set(entity, transform);
    f.Set(entity, collider);
    f.Set(entity, body);

3D 物理也適用相同的規則:

C#

    var entity = f.Create();
    var transform = Transform3D.Create();

    var shape = Shape3D.CreateSphere(FP._1);

    var collider = PhysicsCollider3D.Create(shape);
    var body = PhysicsBody3D.CreateDynamic(FP._1);

    f.Set(entity, transform);
    f.Set(entity, collider);
    f.Set(entity, body);

如果使用 QuantumEntityPrototype 替代方法,組件將使用 Unity 檢查器中定義的值進行初始化。

Adjusting a Quantum Entity Prototype's Physics Properties via the Unity Editor
通過 Unity 編輯器調整實體原型的物理屬性。

動態物體支持的形狀

PhysicsCollider3D僅支持以下 Shape3D 用於動態實體:

  • 球體
  • 方塊
  • 圓柱體
  • 複合體(多個形狀的組合)

在編輯器中,您可以使用與 Unity 圓柱體相同的屬性(半徑和高度)來設置圓柱體形狀的屬性。但在內部,Quantum 將圓柱體定義為半徑和範圍,同時也有高度和直徑屬性。

PhysicsCollider2D僅支持以下Shape2D用於動態實體:

  • 圓形
  • 方塊
  • 多邊形
  • 邊緣
  • 圓柱體
  • 複合體(多個形狀的組合)

以下是一些可用的與圓柱體碰撞體相關的代碼片段:

C#

FP radius = FP._0_50;
FP extent = FP._1;
Shape2D shape = Shape2D.CreateCapsule(radius, extent);

// Draw the capsule
Draw.Capsule(FPVector2.Zero, shape.Capsule);
Draw.Capsule(FPVector2.Zero, extent, radius);

為清晰起見,下圖展示了 Quantum 和 Unity 的圓柱體碰撞體之間的語義差異。

Difference between Unity's capsules and Quantum's capsules
Unity 的圓柱體與 Quantum 的圓柱體之間的差異。

質心

質心(此後簡稱為 CoM)可以在 PhysicsBody 組件上設置。質心表示相對於 Transform 組件中指定位置的偏移量。改變質心的位置可以影響施加到 PhysicsBody 上的力。

Animated examples of how various CoM affect the same PhysicsBody
展示各種質心如何影響同一個 PhysicsBody 的動畫示例。

默認情況下,質心設置為 PhysicsCollider 形狀的質心。這由 PhysicsBody 配置抽屜中的Reset Center of Mass On Added來強制執行。

注意:要自定義質心位置,必須 取消選中Reset Center of Mass On Added標誌;否則,當 PhysicsBody 組件添加到實體時,質心將重置為碰撞體的質心。

Defaults Flags in the PhysicsBody Config
在 Unity 編輯器中查看的 PhysicsBody 配置中的默認標誌。

上述配置通常用於表現為均勻密度物體(即密度均勻的物體)的實體。但是,質心和碰撞體偏移是單獨配置的。組合情況如下表所示。

PhysicsCollider 偏移 PhysicsBody CoM Reset Center of Mass On Added 標誌 結果位置
默認位置 = 0, 0, 0
自定義值 = 不同於默認位置的任何位置
默認位置 默認位置 開 / 關 碰撞體質心和質心位置都等於變換位置。
自定義值 默認位置 碰撞體質心相對於變換位置偏移,質心等於碰撞體質心位置。
自定義值 默認位置 碰撞體質心相對於變換位置偏移
質心等於變換位置。
自定義值 自定義位置 碰撞體質心相對於變換位置偏移
質心等於碰撞體質心位置。
自定義值 自定義位置 碰撞體質心相對於變換位置偏移
質心相對於變換位置偏移

複合碰撞體的質心

複合形狀的質心是所有形狀元素的質心基於其面積(2D)或體積(3D)的加權平均值的組合。

要點

總之,關於質心配置的主要要點如下。

  1. PhysicsCollider 偏移和 PhysicsBody 質心位置彼此不同。
  2. 默認情況下,PhysicsBody 配置具有Reset Center of Mass On AddedReset Inertia on Added標誌。
  3. 要設置自定義質心,請取消選中 PhysicsBody 配置中的Reset Center of Mass On Added標誌。
  4. 如果 PhysicsBody 配置上的Reset Center of Mass On Added標誌被選中,則質心在添加到實體時將自動設置為 PhysicsCollider 質心,無論編輯器中指定的質心位置如何。

施加外力

PhysicsBody API 允許手動向物體施加外力。

C#

// This is the 3D API, the 2D one is identical.

public void AddTorque(FPVector3 amount)
public void AddAngularImpulse(FPVector3 amount)

public void AddForce(FPVector3 amount, FPVector3? relativePoint = null)
public void AddLinearImpulse(FPVector3 amount, FPVector3? relativePoint = null)
// relativePoint is a vector from the body's center of mass to the point where the force is being applied, both in world space.
// If a relativePoint is provided, the resulting Torque is computed and applied.

public void AddForceAtPosition(FPVector3 force, FPVector3 position, Transform3D* transform)
public void AddImpulseAtPosition(FPVector3 force, FPVector3 position, Transform3D* transform)
// Applies the force/impulse at the position specified while taking into account the CoM.

可以通過施加以下力來影響 PhysicsBody 的角動量和線動量:

  • 力(forces);或
  • 衝量(impulses)。

雖然它們相似,但有一個關鍵區別: 是在一段時間內施加的,而 衝量 是即時的。可以這樣理解它們:

  • 力 = 每幀時間(deltatime)的力
  • 衝量 = 每幀的力

注意: 在 Quantum 中,幀時間是固定的,取決於 Simulation Config 資產中設置的模擬速率。

無論模擬速率如何,衝量 都會產生相同的效果。但是, 取決於模擬速率 —— 這意味著在模擬速率為 30 時向物體施加 1 的力向量,當將模擬速率提高到 60 時,幀時間將減半,因此積分力也將減半。

一般來說,當需要進行即時的瞬間變化時,建議使用 衝量;而當需要持續、逐漸地或在較長時間內施加時,則應使用

初始化組件

要將 PhysicsBody 初始化為動態或運動學物體,請使用相應的創建函數。這些方法可通過 PhysicsBody2DPhysicsBody3D 類訪問,例如:

  • PhysicsBody3D.CreateDynamic
  • PhysicsBody3D.CreateKinematic

形狀配置(ShapeConfigs)

要通過數據驅動設計初始化 PhysicsCollider 和 PhysicsBody,請使用 ShapeConfig 類型(Shape2DConfig 和 Shape3DConfig)。這些結構體可以作為屬性添加到任何 Quantum 數據資產中,可從 Unity 編輯(用於形狀、大小等)。

C#

// data asset containing a shape config property
partial class CharacterSpec {
  // this will be edited from Unity
  public Shape2DConfig Shape2D;
  public Shape3DConfig Shape3D;
  public FP Mass;
}

初始化物體時,我們使用形狀配置而不是直接使用形狀:

C#

// instantiating a player entity from the Frame object
var playerPrototype = f.FindAsset<EntityPrototype>(PLAYER_PROTOTYPE_PATH);
var playerEntity = playerPrototype.Container.CreateEntity(f);

var playerSpec = f.FindAsset<CharacterSpec>("PlayerSpec");

var transform = Transform2D.Create();
var collider = PhysicsCollider2D.Create(playerSpec.Shape2D.CreateShape(f));
var body = PhysicsBody2D.CreateKinematic(playerSpec.Mass);

// or the 3D equivalent:
var transform = Transform3D.Create();
var collider = PhysicsCollider3D.Create(playerSpec.Shape3D.CreateShape())
var body = PhysicsBody3D.CreateKinematic(playerSpec.Mass);

// Set the component data
f.Set(playerEntity, transform);
f.Set(playerEntity, collider);
f.Set(playerEntity, body);

啟用物理回調

實體可以有一組與之關聯的物理回調。這些可以通過代碼或在 Quantum Entity PrototypePhysicsCollider 組件中啟用。

Setting Physics Callbacks via the Entity Prototype's Physics Properties in the Unity Editor
通過 Quantum 實體原型的物理屬性設置物理回調。

有關如何在代碼中設置物理回調以及如何 實現 相應的 信號,請參閱物理手冊中的回調部分。

運動學(Kinematic)

物理實體有 4 種不同的運動學樣行為方式:

  1. 有一個 PhysicsCollider 組件。在這種情況下,實體沒有 PhysicsBody 組件;即沒有質量、阻力、力 / 扭矩積分等。可以隨意操縱實體變換,但是,當與動態物體碰撞時,碰撞衝量的求解就好像該實體是靜止的(線性和角速度為零)。

  2. 禁用 PhysicsBody 組件。當將 PhysicsBody 上的 IsEnabled 屬性設置為 false 時,物理引擎將以與要點 1 相同的方式處理該實體 —— 即視為僅有碰撞體組件。不積分力或速度。這適用於物體 臨時 表現為靜止實體,並在稍後重新啟用時保留其配置(質量、阻力係數等)的情況。

  3. PhysicsBody 組件 上的 IsKinematic 屬性 設置true。在這種情況下,物理引擎不會影響 PhysicsBody 本身,但物體的線速度和角速度在解決碰撞時仍會影響 其他物體。使用此設置來控制實體移動,而不是讓物理引擎來控制,要知道可能需要手動移動實體和控制其物體的速度,同時仍讓其他動態物體對其做出反應。

  4. 使用 CreateKinematic 初始化 PhysicsBody。如果物體在整個生命周期內預期表現為運動學的,只需將其創建為運動學物體。這將使 PhysicsBody 從一開始就像要點 3 中那樣運行。如果物體最終需要變為動態的,請使用 CreateDynamic 方法創建一個新的物體,並設置 IsKinematic = true。隨時可以無縫地將 IsKinematic 設置為 true/false 以及將 PhysiscBody 組件重新初始化為動態 / 運動學。

PhysicsCollider 組件

禁用 / 啟用組件

PhysicsCollider 組件配備了 Enabled 屬性。當將此屬性設置為 false 時,帶有 PhysicsCollider 的實體將在 PhysicsSystem 中被忽略。

由於 PhysicsBody 需要一個 活動的 PhysicsCollider,因此它也將被有效地禁用。

在運行時更改形狀

可以在初始化後更改 PhysicsCollider 的形狀。

C#

var collider = f.Get<PhysicsCollider3D>(entity);
collider.Shape = myNewShape;
f.Set(entity, collider);

首次添加 PhysicsBody 時,它會根據 PhysicsCollider 的形狀計算慣性和質心。因此,建議在更改碰撞體形狀後調用 ResetInertiaResetCenterOfMass

C#

// following the snippet above

var body = f.Get<PhysicsBody3D>(entity);
body.ResetCenterOfMass(f, entity); // Needs to be called first
body.ResetInertia(f, entity); // Needs to be called second
f.Set(entity, body);
調用順序很重要!**必須** 先調用`ResetCenterOfMass()`,然後再調用 `ResetInertia()`。

特別是當舊形狀和 / 或新形狀存在以下任何一種情況時,需要調用ResetCenterOfMass

  • 形狀有位置偏移
  • 形狀是複合形狀
  • 質心有偏移
Back to top