Shape Config
はじめに
Shape Config
は、シェイプの情報を保持します。これによって、エディター上で設定オプションを簡単に表示したり、コードでのシェイプの初期化を効率化できます。
ShapeConfig
は2D/3Dの両方が存在し、それぞれShape2DConfig
/Shape3DConfig
になります。
現在、ShapeConfig
は動的エンティティでの使用を想定しています。対応するシェイプの種類は次の通りです。
// 2Dの場合
- Circle
- Box
- Polygon
- Edge
- Compound (複数のシェイプの組み合わせ)
// 3Dの場合
- Sphere
- Box
- Capsule
- Compound (複数のシェイプの組み合わせ)
上記すべてのシェイプは、ShapeOverlap
やPhysicsCollider
と互換性があります。
ShapeConfigをエディターに表示する
独自アセットにShape2DConfig
/Shape3DConfig
を含めると、自動的にエディター上に表示されいます。
C#
namespace Quantum
{
public unsafe partial class WeaponSpec
{
public Shape3DConfig AttackShape;
public LayerMask AttackLayers;
public FP Damage;
public FP KnockbackForce;
}
}
上記スニペットから生成されたアセットは、インスペクター上ですべてのShapeConfig
オプションが表示されます。

ShapeConfigからシェイプを作成/使用する
ShapeConfig
使用する際は、CreateShape
メソッドを呼び出します。これによって、ShapeConfig
アセットに保持されている情報が自動的に処理され、設定内のデータから適切なシェイプとパラメーターが作成されます。
C#
private static void Attack(in Frame frame, in EntityRef entity)
{
// 攻撃範囲にOverlapShapeを使用して、近接攻撃を実行する
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);
// ヒット対象を反復するゲームロジック
}
PhysicsCollider
のシェイプの初期化時にも、同様の処理を実行できます。
Compoundシェイプ
Compoundシェイプは、複数のシェイプで構成されるシェイプです。Compoundシェイプ作成に使用できるシェイプは、最初に紹介したリストに含まれるものになります。
PhysicsCollider
とShapeOverlap
は、Compoundシェイプと完全に互換性があります。
現在、Quantumは永続的Compoundシェイプを提供しています。つまり、ヒープ内の他のシェイプのバッファを指すシェイプです。このバッファは、手動で解放するまでフレーム間で永続します。
新しいCompoundシェイプの作成
Compoundシェイプは、CreateShape
メソッドを呼び出すだけでShapeConfig
から作成できます。または、Shape.CreatePersistentCompound
から手動で作成し、後でFreePersistent
を呼び出して解放します。以下はライフサイクルを管理する方法の例で、3Dシェイプにも同様に適用できます。
C#
// 永続的Compoundシェイプを作成する。実際にシェイプを追加するまでは、メモリ割り当ては発生しない。
var compoundShape = Shape2D.CreatePersistentCompound();
// Compoundシェイプにシェイプを追加する(shape1とshape2は任意のシェイプ)
compoundShape.Compound.AddShape(f, shape1);
compoundShape.Compound.AddShape(f, shape2);
(...) // ゲームロジック
// 手動で解放するまでこのCompoundシェイプは永続する
compoundShape.Compound.FreePersistent(f);
APIには、RemoveShapes
・GetShapes
・FreePresistent
などのメソッドも提供されています。これらメソッドの詳細情報は、SDKのdocs
フォルダー内のAPIドキュメントをご覧ください。
既存Compoundシェイプからのコピー
既存のCompoundシェイプをコピーして、新しいCompoundシェイプを作成することもできます。
C#
// 上記の例の既存Coumpoundシェイプを使用する
var newCompoundShape = Shape2D.CreatePersistentCompound();
newCompoundShape.Compound.CopyFrom(f, ref oldCompoundShape);
新しいCompoundシェイプを作成すると、新しいバッファも作成されます。このバッファは、他の永続的Compoundシェイプのように、開発者が手動で解放する必要があります。
個別のシェイプへのアクセス
シェイプを反復処理する例として、GetShapes
メソッドを使用してバッファのポインタを取得し、単純なfor
ループからCompoundシェイプに含まれるすべてのShape*
にアクセスする方法があります。
メソッドが返すcound
はメモリ内にシェイプのポインタが含まれる境界を表すため、それを超えないようにしてください。
C#
if (shape->Compound.GetShapes(frame, out Shape3D* shapesBuffer, out int count))
{
for (var i = 0; i < count; i++)
{
Shape3D* currentShape = shapesBuffer + i;
// シェイプで何かする
}
}
Compoundコライダー
Compoundコライダーは、Compoundシェイプを持つ通常のコライダーです。
エディター上で作成
エディター上では、Entity Component Physics Collider 2D/3D
やEntity Prototype
スクリプトから、Compoundコライダーを作成するオプションが表示されています。

Compoundシェイプを持つコライダーのプロトタイプを作成する場合は、自動的にメモリ管理が行われます。つまり、コライダーは自身が持つCompoundシェイプを管理するため、手動でメモリを解放する必要はありません。
コードで作成
コードからコライダーを作成する場合は、単純にCompoundシェイプをCreate
ファクトリーメソッドに渡します。前セクションのコードスニペットのようにCompoundシェイプを作成した後は、(...)
を次のように置き換えてコライダーを作成できます。
C#
var collider = PhysicsCollider2D.Create(f, compoundShape);
f.Set(entity, collider);
上記のコードスニペットでは、collider.Shape
とcompoundShape
はヒープ内の異なるバッファを指しています。コライダーを作成するためだけにCompoundシェイプを使用していた場合は、その直後に解放することが可能です。コライダーが破棄/削除されると、メモリ内のコピーは解放されます。
メモリに関する重要な備考
ファクトリーメソッドCreate()
の一部として使用されたコライダーは、Compoundシェイプのバッファのコピーのみを作成します。
C#
var compoundShape = Shape2D.CreatePersistentCompound();
compoundShape.Compound.AddShape(f, shape1);
compoundShape.Compound.AddShape(f, shape2);
// collider1とcollider2は、それぞれcoumpoundShepeバッファのコピーを作成する
// collider1とcollider2は、それぞれ破棄/削除時に自身のコピーを解放する
var collider1 = PhysicsCollider2D.Create(f, compoundShape);
f.Set(entity1, collider1);
var collider2 = PhysicsCollider2D.Create(f, compoundShape);
f.Set(entity2, collider2);
// 不要になったcompoundShapeのバッファは、ここで解放する
compoundShape.Compound.FreePersistent(f);
対照的に、通常のシェイプのコライダーを作成した後にcollider.Shape = someCompound
を設定する場合は、バッファのコピーは作成されません。つまり、collider.Shape
とsomeCompound
は同じバッファを指すことになります。複数のCompoundコライダーやCompoundシェイプが同じバッファを指している場合、一方が解放されると、他方のバッファの参照が事実上壊れてしまうため、非常に危険です。
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とcompoundShapeは、すべて同じバッファを指す
// ここでcompoundShapeを解放すると、collider1と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);
// compoundShepeのバッファはcollider1によって参照されていて、
// 自動的に破棄/削除されるため、手動で解放する必要はない
Compoundシェイプクエリ
Compoundシェイプクエリは、ブロードフェーズクエリと通常のクエリの両方を完全にサポートしています。動作やパフォーマンスは、複数のクエリを実行する場合と同様ですが、結果は同じHitCollection
で返されます。
Compoundシェイプの入れ子
Compoundシェイプの入れ子は、物理エンジンでサポートされていますが、2つの制限があります。
- シェイプは階層内において、ヒープ内の同じバッファの参照を1つだけ保持できます。既に参照されているバッファを追加すると、デバッグモードではエラーが発生します。これは解放時に、循環参照や無効なポインタが発生する問題を避けるためです。
- Compoundシェイプの入れ子は、エディター上ではサポートされていません(警告メッセージが表示されます)。これはUnityのシリアライザーの制限によるもので、
ShapeConfig
でより複雑な構造とドロワーが必要になるためです。