This document is about: QUANTUM 2
SWITCH TO

물질화

소개

컴포넌트 프로토타입 또는 엔티티 프로토타입에서 컴포넌트 또는 컴포넌트 인스턴스를 생성하는 프로세스가 물질화(Materialization) 입니다.

맵 에셋에 베이크 된 씬 프로토타입의 물질화는 Frame.Create API를 사용하여 코드 작성 인스턴스를 물질화하는 것과 동일한 규칙과 실행 흐름을 따릅니다.

프로토타입 vs 인스턴스

컴포넌트 인스턴스와 엔티티 인스턴스는 게임 상태의 일부입니다. 즉, 런타임에 조작할 수 있습니다. DSL에 선언된 컴포넌트는 해당하는 컴포넌트 프로토타입을 생성하는 데 사용됩니다. 코드 생성 프로토타입은 MyComponent_Prototype이라는 명명 규칙을 따릅니다.

컴포넌트 프로토타입엔티티 프로토타입은 둘 다 에셋 이며, 이는 게임 상태의 일부가 아니며 런타임에 변하지 않으며 모든 클라이언트에서 항상 동일해야 함을 의미합니다. 각 컴포넌트 프로토타입에는 ComponentPrototypeRef가 있으며, Frame.FindPrototype<MyComponentName_Prototype>(MyComponentPrototypeRef)을 사용하여 해당하는 에셋을 찾는 데 사용할 수 있습니다.

컴포넌트 프로토타입

컴포넌트 프로토타입은 구현에 직접 사용되지 않을 수 있는 데이터를 포함하도록 확장할 수 있습니다. 이를 통해 특정 컴포넌트의 인스턴스 간에 데이터를 공유하거나 프레임에서 읽기 전용 데이터를 제외하여 게임 상태를 슬림 하게 유지할 수 있습니다.

코드 생성 컴포넌트 프로토타입은 쉽게 확장할 수 있는 부분 클래스입니다.

  1. MyComponentName_Prototype.cs라는 C# 파일을 만듭니다.
  2. 스크립트 바디를 Quantum.Prototypes 네임스페이스로 넣습니다.
  3. ( 선택 ) 인스펙터 속성에 접근하기 위해 설명서 \ ECS속성 섹션에 설명되어 있는 using Quantum.Inspector;을 추가합니다.

그러면 컴포넌트 프로토타입 에셋에 추가 데이터를 추가하고 partial MaterializeUser() 메소드를 구현하여 사용자 정의 물질화 로직을 추가할 수 있습니다.

예제

다음 예는 아케이드 레이싱 템플릿에서 볼 수 있는 차량 컴포넌트의 물질화를 보여줍니다.

차량 컴포넌트는 주로 런타임에 계산된 동적 값을 보유합니다. 이러한 매개 변수는 초기화할 수 없으므로 DSL의 컴포넌트 정의는 해당 매개 변수에 대해 ExcludeFromPrototype 속성을 사용하여 에셋 설계자가 유니티 편집기에서 조작할 수 있는 Vehicle_Prototype에서 제외합니다. Nitro 매개 변수는 디자이너가 특정 Vehicle의 초기화 정도를 결정할 수 있도록 편집할 수 있는 부분일 뿐입니다.

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 매개 변수는 AssetRef에 해당하는 컴포넌트별 ComponentPrototypeRef 타입입니다. 이를 채우기 위해 partial 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);
        }
    }
}

물질화 순서

씬 프로토타입을 포함한 모든 엔티티 프로토타입의 물질화는 다음 순서로 실행됩니다:

  1. 빈 엔티티가 생성됩니다.
  2. 엔티티 프로토타입에 포함된 각 컴포넌트 프로토타입에 대해 다음을 수행합니다.
    1. 컴포넌트 인스턴스가 스택에 생성됩니다.
    2. 컴포넌트 프로토타입은 컴포넌트 인스턴스로 물질화됩니다.
    3. ( 선택 ) MaterializeUser() 가 호출됩니다.
    4. ISignalOnComponentAdded<MyComponent> 시그널을 트리거 하는 엔티티에 컴포넌트가 추가됩니다.
  3. 물질화된 각 엔티티에 대해 ISignalOnEntityPrototypeMaterialized가 실행됩니다.
    • 맵 / 씬 로드 : 시그널을 모든 씬 프로토타입을 물질화한 후 모든 엔티티와 엔티티 프로토타입 쌍에 대해 호출됩니다.
    • Frame.Create()으로 생성: 시그널을 프로토타입이 구체화된 후 즉시 호출됩니다.

컴포넌트 프로토타입의 구체화 단계는 기본 컴포넌트를 미리 정해진 순서대로 구체화합니다.

C#

Transform2D
Transform3D
Transform2DVertical
PhysicsCollider2D
PhysicsBody2D
PhysicsCollider3D
PhysicsBody3D
PhysicsJoints2D
PhysicsJoints3D
PhysicsCallbacks2D
PhysicsCallbacks3D
CharacterController2D
CharacterController3D
NavMeshPathfinder
NavMeshSteeringAgent
NavMeshAvoidanceAgent
NavMeshAvoidanceObstacle
View
MapEntityLink

모든 기본 컴포넌트가 구체화되면 사용자 정의 컴포넌트가 알파벳순으로 물질화됩니다.

C#

MyComponentAA
MyComponentBB
MyComponentCC
...
Back to top