This document is about: QUANTUM 3
SWITCH TO

シェイプコンフィグ

はじめに

シェイプ設定は、シェイプに関する情報を保持します。これにより、エディタ内で設定オプションを簡単に公開し、コード内でのシェイプの初期化を効率化することができます。
シェイプ設定は、2D用のShape2DConfigと3D用のShape3DConfigの両方が存在します。

現在、シェイプ設定は動的エンティティとの使用を目的としており、それに対応するシェイプタイプは次の通りです:

// 2Dの場合

  • 円(Circle)
  • ボックス(Box)
  • ポリゴン(Polygon)
  • エッジ(Edge)
  • 複合(Compound、これらのいずれかの組み合わせ)

// 3Dの場合

  • スフィア(Sphere)
  • ボックス(Box)
  • カプセル(Capsule)
  • 複合(Compound、これらのいずれかの組み合わせ)

前述のすべてのシェイプは、ShapeOverlaps および PhysicsColliders と互換性があります。

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 Setting of the example asset as shown in the Unity Editor
Unityエディタに表示されるWeaponSpec例アセットのShapeConfig設定。

ShapeConfigからシェイプを作成/使用する

ShapeConfigを使用する際には、そのCreateShapeメソッドを呼び出します。これにより、ShapeConfigアセットに保持されている情報が自動的に処理され、設定内に見つかったデータを用いて適切なシェイプとそのパラメータが作成されます。

C#

private static void Attack(in Frame f, in EntityRef entity)
{
    // A melee attack performed by using an OverlapShape on the attack area.

    var transform = f.Unsafe.GetPointer<Transform3D>(entity);
    var weapon = f.Unsafe.GetPointer<Weapon>(entity);
    var weaponSpec = f.FindAsset<WeaponSpec>(weapon->WeaponSpec.Id);

    var hits = f.Physics3D.OverlapShape(
        transform->Position,
        transform->Rotation,
        weaponSpec.AttackShape.CreateShape(f),
        weaponSpec.AttackLayers);

    // Game logic iterating over the hits.
}

PhysicsColliderのシェイプを初期化する際にも、同様のことができます。

複合シェイプ

複合シェイプは、いくつかの他のシェイプで構成されるシェイプです。複合シェイプを作成するために使用できるシェイプは、はじめのセクションにリストされているものです。

PhysicsCollidersおよびShapeOverlapsは、複合シェイプと完全に互換性があります。

現在、Quantumは永続的な複合シェイプを提供しています。つまり、ヒープ内の他のシェイプへのバッファを指すシェイプです。このバッファは、手動で解放されるまでフレーム間で持続します。

新しい複合シェイプの作成

複合シェイプは、CreateShapeメソッドを呼び出すことでShapeConfigから簡単に作成することができます。または、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には、RemoveShapesGetShapes、およびFreePersistentなどのメソッドも用意されています。これらやその他のメソッドに関する詳細は、SDKのdocsフォルダー内のAPIドキュメントを参照してください。

既存の複合シェイプからのコピー

既存の複合シェイプをコピーすることで、新しい複合シェイプを作成することもできます。

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スクリプトの各セクションで、複合コライダーを作成するオプションを見つけることができます。

ShapeConfig for a Compound Collider in the Entity Prototype script as shown in the Unity Editor
UnityエディタでEntity Prototypeスクリプトを使用して、複合コライダー(スフィア + ボックス)を作成します。

複合シェイプを持つコライダープロトタイプを作成する際、メモリ管理はすでに処理されています。すなわち、コライダーは自動的にその複合シェイプを持ち、管理するため、手動で何かを解放する必要はありません。

コードでの作成

コード内でコライダーを作成する際は、単純に複合シェイプをそのCreate()ファクトリメソッドに渡します。前のセクションのコードスニペットで示したように、複合シェイプが作成された後は、次のように(...)を置き換えることでコライダーを作成できます:

C#

var collider = PhysicsCollider2D.Create(f, compoundShape);
f.Set(entity, collider);

上記のコードスニペットでは、collider.ShapecompoundShapeはヒープ内の異なるバッファを指しています。複合シェイプの使用が終了した場合—つまり、それがコライダーを作成するためだけに必要だった場合—その後に解放することが可能です。コライダーが破棄または削除されると、そのメモリ内のコピーは自動的に解放されます。

メモリに関する重要な注意事項

コライダーは、そのファクトリメソッド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.ShapesomeCompoundは同じバッファを指すことになります。複数の複合コライダーや複合シェイプが同じバッファを指している場合、一方が解放されてしまうと、他のコライダーやシェイプがそのバッファを参照できなくなってしまうため、危険です。

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内で返されます。

ネストされた複合シェイプ

ネストされた複合シェイプは物理エンジンによってサポートされていますが、2つの制限があります:

  • シェイプは、その階層内でヒープにある同じバッファへの参照を1つだけ保持できます。既に参照されているバッファを追加しようとすると、デバッグモードでエラーが発生します。これは、循環参照や無効なポインタが解放時に発生する問題を避けるためです。
  • ネストされた複合シェイプは、エディタではサポートされていません(警告メッセージが表示されます)。これは、Unityシリアライザの制限によるもので、シェイプ設定に対してより複雑な構造とドロワーが必要だからです。
Back to top