マテリアライゼーション
はじめに
Component Prototypeや Entity Prototypeからエンティティやコンポーネントのインスタンスを生成するプロセスは、マテリアライゼーション と呼ばれます。
マップアセットに組み込まれたシーンプロトタイプのマテリアライゼーションは、Frame.Create APIを使用してコードで作成されたインスタンスのマテリアライゼーションと同じルールと実行フローに従います。
プロトタイプ vs インスタンス
コンポーネントインスタンスとエンティティインスタンスは、ゲームの状態の一部であり、実行時に操作することができます。DSLで宣言されたコンポーネントは、対応するComponent Prototypesの生成に使用されます。コードで生成されたプロトタイプは、MyComponent_Prototypeという命名規則に従います。
Component PrototypesとEntity Prototypesはどちらもアセットです。これは、ゲームの状態の一部ではなく、実行時では不変であり、すべてのクライアントに対して常に同一でなければならないことを意味します。各 Component Prototype は ComponentPrototypeRef を持ち、これは Frame.FindPrototype<MyComponentName_Prototype>(MyComponentPrototypeRef) を使って、対応するアセットを見つけるのに使用できます。
コンポーネントプロトタイプ
Component Prototype を拡張して、マテリアライゼーションでは直接使用されないデータを含めることができます。これにより、例えば、特定のコンポーネントのインスタンス間でデータを共有したり、ゲームの状態をコンパクトに保つためにフレームから読み取り専用のデータを除外したりすることができます。
コードで生成されたComponent Prototypes は、簡単に拡張できる部分クラスです。
- MyComponentName_Prototype.csというC#ファイルを作成します。
- スクリプトの本体をQuantum.Prototypes名前空間に置く。
- ( Optional ) using Quantum.Inspector;を追加して,Manual \ ECSページのAttributesセクションで紹介されているインスペクタの属性にアクセスできるようにします.
これにより、Component Prototype アセットに追加データを追加したり、パーシャルの MaterializeUser() メソッドを実装して、カスタムの具現化ロジックを追加することができます。
例
以下の例では、Arcade Racing Template にあるVehicleコンポーネントのマテリアライゼーションを示します。
Vehicleコンポーネントは、主に実行時に計算される動的な値を保持します。これらは初期化することができないので、DSLのコンポーネント定義では、これらのパラメータにExcludeFromPrototype 属性を使用して、デザイナーがUnityエディタで操作できる Vehicle_Prototype アセットから除外しています。Nitroパラメータは、デザイナーが特定のVehicleをどのくらいのNitroで初期化するかを決めるために編集できる唯一の部分です。
C#
component Vehicle
{
    [ExcludeFromPrototype]
    ComponentPrototypeRef Prototype;
    [ExcludeFromPrototype]
    Byte Flags;
    [ExcludeFromPrototype]
    FP Speed;
    [ExcludeFromPrototype]
    FP ForwardSpeed;
    [ExcludeFromPrototype]
    FPVector3 EngineForce;
    [ExcludeFromPrototype]
    FP WheelTraction;
    [ExcludeFromPrototype]
    FPVector3 AvgNormal;
    [ExcludeFromPrototype]
    array<Wheel>[4] Wheels;
    FP Nitro;
}
Vehicle_Prototype アセットが拡張され、設計者にカスタマイズ可能な読み取り専用のパラメータを提供するようになりました。したがって、Vehicle_Prototype アセットは、特定の車両エンティティのプロトタイプ "type" のすべてのインスタンスの共有値を保持することができます。VehicleコンポーネントのPrototypeパラメータは、ComponentPrototypeRefというタイプで、コンポーネント固有のAssetRefに相当します。これを入力するには、パーシャルの MaterializeUser() メソッドを使用して、Vehicle_Prototype の参照を割り当てます。
C#
using Photon.Deterministic;
using Quantum.Inspector;
using System;
namespace Quantum.Prototypes
{
public unsafe partial class Vehicle_Prototype
{
    // PUBLIC METHODS
    [Header("Engine")]
    public FP EngineForwardForce = 130;
    public FP EngineBackwardForce = 120;
    public FPVector3 EngineForcePosition;
    public FP ApproximateMaxSpeed = 20;
    [Header("Hand Brake")]
    public FP HandBrakeStrength = 10;
    public FP HandBrakeTractionMultiplier = 1;
    [Header("Resistances")]
    public FP AirResistance = FP._0_02;
    public FP RollingResistance = FP._0_10 * 6;
    public FP DownForceFactor = 0;
    public FP TractionGripMultiplier = 10;
    public FP AirTractionDecreaseSpeed = FP._0_50;
    [Header("Axles")]
    public AxleSetup FrontAxle = new AxleSetup();
    public AxleSetup RearAxle = new AxleSetup();
    [Header("Nitro")]
    public FP MaxNitro = 100;
    public FP NitroForceMultiplier = 2;
    // PARTIAL METHODS
    partial void MaterializeUser(Frame frame, ref Vehicle result, in PrototypeMaterializationContext context)
    {
        result.Prototype = context.ComponentPrototypeRef;
    }
    [Serializable]
    public class AxleSetup
    {
        public FPVector3 PositionOffset;
        public FP Width = 1;
        public FP SpringForce = 120;
        public FP DampingForce = 175;
        public FP SuspensionLength = FP._0_10 * 6;
        public FP SuspensionOffset = -FP._0_25;
    }
}
}
Vehicle_Prototype のパラメータは、Vehicleコンポーネントが接続されているエンティティの動作に影響を与えるコンポーネントのインスタンスに見られる動的な値を計算するために必要な値を保持します。例えば、プレイヤーが追加の Nitro を拾った場合、Vehicle コンポーネントに保持されている値は、Vehicle_Prototype にある MaxNitro の値に固定されます。これにより、非同期化のペナルティによる制限が適用され、ゲームの状態がスリムに保たれます。
C#
namespace Quantum
{
    public unsafe partial struct Vehicle
    {
        public void AddNitro(Frame frame, EntityRef entity, FP amount)
        {
            var prototype = frame.FindPrototype<Vehicle_Prototype>(Prototype);
            Nitro = FPMath.Clamp(Nitro + amount, 0, prototype.MaxNitro);
        }
    }
}
マテリアライゼーションの順序
シーンプロトタイプを含むすべてのEntity Prototypeは、マテリアライゼーションによって、以下のステップを順に実行します。
- 空のエンティティが作成されます。
- Entity Prototypeに含まれる各- Component Prototypeに対して、以下の手順を実行します。- コンポーネントのインスタンスをスタック上に作成する。
- Component Prototypeがコンポーネントインスタンスに実体化される。
- ( Optional ) MaterializeUser()が呼び出されます。
- コンポーネントがエンティティに追加され、ISignalOnComponentAdded<MyComponent>シグナルが発生します。
 
- ISignalOnEntityPrototypeMaterializedはマテリアライズされた各エンティティに対して呼び出されます。- マップ/シーンの読み込み:すべてのシーンプロトタイプがマテリアライズされた後、すべてのエンティティとEntity Prototypeのペアに対してシグナルが呼び出されます。
- Frame.Create()で作成された場合:プロトタイプがマテリアライズされた直後にシグナルが発生します。
 
- マップ/シーンの読み込み:すべてのシーンプロトタイプがマテリアライズされた後、すべてのエンティティと
Component Prototype マテリアライゼーション手順では、デフォルトのコンポーネントをあらかじめ決められた順序で具体化します。
C#
Transform2D
Transform3D
Transform2DVertical
PhysicsCollider2D
PhysicsBody2D
PhysicsCollider3D
PhysicsBody3D
PhysicsJoints2D
PhysicsJoints3D
PhysicsCallbacks2D
PhysicsCallbacks3D
CharacterController2D
CharacterController3D
NavMeshPathfinder
NavMeshSteeringAgent
NavMeshAvoidanceAgent
NavMeshAvoidanceObstacle
View
MapEntityLink
デフォルトのコンポーネントがすべてマテリアライズされると、ユーザー定義のコンポーネントがアルファベット順に実体化されます。
C#
MyComponentAA
MyComponentBB
MyComponentCC
...