This document is about: QUANTUM 2
SWITCH TO

Shape Config

イントロ

shape configは、シェイプに関する情報を保持します。これを使用して、エディタで設定オプションを簡単に公開したり、コード内でのシェイプの初期化を合理化したりすることができます。
2D用と3D用にそれぞれ Shape2DConfigShape3DConfig があります。

現在のところ、ShapeConfigsは動的エンティティでの使用を対象としており、次のようなシェイプタイプに対応しています。

// 2D

  • ボックス
  • ポリゴン
  • エッジ
  • 化合物(これらすべての混合物)

// 3D

  • スフィア
  • ボックス
  • 化合物(スフィア、ボックス、またはその混合物)

前述のシェイプはすべて ShapeOverlapsPhysicsColliders に対応しています。

Exposing ShapeConfig to the Editor

カスタムアセットに Shape2DConfig または Shape3DConfig を含めると、エディタで自動的に公開されます。

C#

namespace Quantum
{
    public unsafe partial class WeaponSpec
    {
        public Shape3DConfig AttackShape;
        public LayerMask AttackLayers;
        public FP Damage;
        public FP KnockbackForce;
    }
}

上記のスニペットから得られるアセットは、以下のように、インスペクタ内のすべてのShapeConfigsオプションを公開します。

ShapeConfig Setting of the example asset as shown in the Unity Editor
Unityエディタに表示されているWeaponSpecの例のアセットのShapeConfig設定。

これは Entity Prototype スクリプトの Shape 2D/3D と呼ばれる PhysicsCollider のセクションで既に行ったことがあるかもしれない。

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

ShapeConfigを使用する場合は、その CreateShape メソッドを呼び出すだけです。これにより、ShapeConfigアセットに保持されている情報が自動的に処理され、適切なシェイプとそのパラメータがconfig内のデータで作成されます。

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 you actually add 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 you manually dispose it
    compoundShape.Compound.FreePersistent(f);

APIには、RemoveShapesGetShapesFreePersistentなどのメソッドも用意されています。これらのメソッドやその他のメソッドの詳細については、SDKのdocsフォルダ内のAPIドキュメントを確認してください。

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

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

C#

// Using the exising compoundShape from the example above.

var newCompoundShape = Shape2D.CreatePersistentCompound();
newCompoundShape.Compound.CopyFrom(f, ref oldCompoundShape);

新たな複合シェイプは新しいバッファも意味します。他の既存の複合シェイプと同様に、ディベロッパーはこのバッファを手動で解放する必要があります。

個別のシェイプにアクセス

Shapesを繰り返し使用する方法の例としては、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 = shapes + i;
        // do something with the shape
    }
}

複合型コライダー

複合型 コライダーとは、複合型のシェイプをした正規のコライダーのことです。

エディタで作成

エディタの Entity Component Physics Collider 2D/3DEntity Prototype スクリプトのそれぞれのセクションに複合型コライダーを作成するオプションがあります。

ShapeConfig for a Compound Collider in the Entity Prototype script as shown in the Unity Editor
Unity Editorの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