Shape Config
簡介
形狀配置(Shape Config)存儲有關形狀的信息。它可用於在編輯器中輕鬆公開配置選項,並簡化代碼中的形狀初始化過程。
形狀配置同時存在於 2D 和 3D 中,分別為Shape2DConfig和Shape3DConfig。
目前,形狀配置主要用於動態實體,因此它支持的形狀類型如下:
// 在 2D 中
- 圓形(Circle)
- 方塊(Box)
- 多邊形(Polygon)
- 邊緣(Edge)
- 複合形狀(Compound,由上述任何形狀組合而成)
// 在 3D 中
- 球體(Sphere)
- 方塊(Box)
- 膠囊體(Capsule)
- 複合形狀(Compound,由上述任何形狀組合而成)
上述所有形狀均與 ShapeOverlaps 和 PhysicsColliders 兼容。
向編輯器公開形狀配置
在自定義資產中包含Shape2DConfig或Shape3DConfig,會自動在編輯器中將其公開。
C#
namespace Quantum
{
public unsafe partial class WeaponSpec
{
public Shape3DConfig AttackShape;
public LayerMask AttackLayers;
public FP Damage;
public FP KnockbackForce;
}
}
上述代碼片段生成的資產將在檢查器中顯示所有形狀配置選項,如下所示:
從形狀配置創建 / 使用形狀
使用形狀配置時,調用其CreateShape方法。這將自動處理形狀配置資產中存儲的信息,創建合適的形狀及其參數,並填充配置中的數據。
C#
private static void Attack(in Frame frame, in EntityRef entity)
{
// A melee attack performed by using an OverlapShape on the attack area.
var transform = frame.Unsafe.GetPointer<Transform3D>(entity);
var weapon = frame.Unsafe.GetPointer<Weapon>(entity);
var weaponSpec = frame.FindAsset<WeaponSpec>(weapon->WeaponSpec.Id);
var hits = frame.Physics3D.OverlapShape(
transform->Position,
transform->Rotation,
weaponSpec.AttackShape.CreateShape(frame),
weaponSpec.AttackLayers);
// Game logic iterating over the hits.
}
初始化物理碰撞體的形狀時,也可以使用相同的方法。
複合形狀
複合形狀是由多個其他形狀組成的形狀。可用於創建複合形狀的形狀是簡介部分列出的那些形狀。
物理碰撞體和形狀重疊檢測完全兼容複合形狀。
目前,Quantum 提供持久化的複合形狀,即指向堆中其他形狀緩衝區的形狀。該緩衝區將在幀之間持久存在,直到手動釋放。
創建新的複合形狀
可以通過調用形狀配置的CreateShape方法從形狀配置創建複合形狀,或者通過Shape.CreatePersistentCompound手動創建,稍後調用FreePersistent釋放。以下是如何管理生命周期的示例,同樣適用於 3D 形狀:
C#
// creating a persistent compound. This does not allocate memory until actually adding shapes
var compoundShape = Shape2D.CreatePersistentCompound();
// adding shapes to a compound (shape1 and 2 can be of any type)
compoundShape.Compound.AddShape(f, shape1);
compoundShape.Compound.AddShape(f, shape2);
(...) // Game logic
// this compound persists until it is manually disposed
compoundShape.Compound.FreePersistent(f);
API 還提供諸如RemoveShapes、GetShapes和FreePersistent等方法;有關這些方法和其他方法的更多信息,請查看 SDK 的docs文件夾中的 API 文檔。
從現有複合形狀復制(CopyFrom)
您也可以通過復制現有的複合形狀來創建新的複合形狀。
C#
// Using the exising compoundShape from the example above.
var newCompoundShape = Shape2D.CreatePersistentCompound();
newCompoundShape.Compound.CopyFrom(f, ref oldCompoundShape);
創建新的複合形狀也意味著創建新的緩衝區。開發者需要像釋放任何其他持久化複合形狀一樣手動釋放它。
訪問單個形狀
迭代形狀的示例是使用GetShapes方法獲取指針緩衝區,然後使用簡單的for循環,其中整數索引可用於訪問複合形狀中包含的所有Shape*。
不要超過該方法返回的count,因為它是內存中形狀指針所在的邊界。
C#
if (shape->Compound.GetShapes(frame, out Shape3D* shapesBuffer, out int count))
{
for (var i = 0; i < count; i++)
{
Shape3D* currentShape = shapesBuffer + i;
// do something with the shape
}
}
複合碰撞體
複合 碰撞體是具有複合類型形狀的常規碰撞體。
在編輯器中創建
在編輯器中,在Entity Component Physics Collider 2D/3D和Entity Prototype腳本的相應部分中找到創建複合碰撞體的選項。
創建具有複合形狀的碰撞體原型時,內存管理已自動處理,即碰撞體將擁有並管理其複合形狀,無需手動釋放任何資源。
在代碼中創建
在代碼中創建碰撞體時,只需將複合形狀傳遞到其Create()工廠方法中。按照上一節中的代碼片段創建複合形狀後,可以通過以下方式替換(...)來創建碰撞體:
C#
var collider = PhysicsCollider2D.Create(f, compoundShape);
f.Set(entity, collider);
在上面提供的代碼片段中,collider.Shape和compoundShape指向堆中的不同緩衝區。當不再需要複合形狀時(即僅用於創建碰撞體),可以在之後立即釋放它。碰撞體在被銷毀 / 移除時會釋放其內存中的副本。
有關內存的重要注意事項
碰撞體僅在作為其工廠方法Create()的一部分使用時,才會創建複合形狀緩衝區的副本。
C#
var compoundShape = Shape2D.CreatePersistentCompound();
compoundShape.Compound.AddShape(f, shape1);
compoundShape.Compound.AddShape(f, shape2);
// collider1 and collider2 each create a copy of the compoundShape buffer.
// collider1 and collider2 will each dispose of their copy on destroy/remove.
var collider1 = PhysicsCollider2D.Create(f, compoundShape);
f.Set(entity1, collider1);
var collider2 = PhysicsCollider2D.Create(f, compoundShape);
f.Set(entity2, collider2);
// Here we dispose of the compoundShape's buffer as it is no longer needed
compoundShape.Compound.FreePersistent(f);
相反,如果需要創建具有常規形狀的碰撞體,然後設置其collider.Shape = someCompound,則不會創建緩衝區的副本,即collider.Shape和someCompound將指向同一個緩衝區。如果有多個複合碰撞體和 / 或複合形狀指向同一個緩衝區,這樣做可能會有危險。如果其中一個釋放了它,將實際上中斷其他對緩衝區的引用。
C#
var compoundShape = Shape2D.CreatePersistentCompound();
compoundShape.Compound.AddShape(f, shape1);
compoundShape.Compound.AddShape(f, shape2);
var collider1 = PhysicsCollider2D.Create(f, default(Shape2D));
collider1.Shape = compoundShape;
f.Set(entity1, collider1);
var collider2 = PhysicsCollider2D.Create(f, Shape2D.CreateCircle(1));
collider2.Shape = compoundShape;
f.Set(entity2, collider2);
// collider1.Shape, collider2.Shape and compoundShape all point to the same buffer
// dispose of compoundShape here will break collider1 and collider2
compoundShape.Compound.FreePersistent(f);
但是,如果謹慎操作,這會將形狀及其內存管理分配給相關的碰撞體,從而通過將責任移交給碰撞體(碰撞體在銷毀 / 移除時會釋放它)來簡化內存管理。
C#
var compoundShape = Shape2D.CreatePersistentCompound();
compoundShape.Compound.AddShape(f, shape1);
compoundShape.Compound.AddShape(f, shape2);
var collider1 = PhysicsCollider2D.Create(f, Shape2D.CreateCircle(1));
collider1.Shape = compoundShape;
f.Set(entity1, collider1);
// In this instance we do not need to dispose of the compoundShape buffer because
// collider1 already points to it and will take care of it on destroy/remove.
複合形狀查詢
複合形狀查詢完全支持廣域查詢和常規查詢。其行為和性能影響與執行多個查詢相同,不同之處在於結果將返回到同一個 HitCollection 中;
嵌套複合形狀
物理引擎支持嵌套複合形狀,但有兩個限制:
- 一個形狀在其層次結構中只能持有對堆中同一緩衝區的一個引用。在調試模式下,添加已被引用的緩衝區將拋出錯誤。這是為了避免循環引用問題和釋放時的無效指針。
- 編輯器不支持嵌套複合形狀(將顯示警告消息)。這是由於 Unity 序列化器的限制,它需要更複雜的結構和形狀配置的繪製器。