This document is about: QUANTUM 2
SWITCH TO

DSL (게임 상태)

소개

Quantum은 컴포넌트 및 기타 런타임 게임 상태 데이터 유형을 자체 DSL(도메인별 언어)로 선언해야 합니다.

이러한 정의는 확장자가 .qtn인 텍스트 파일에 기록됩니다. Quantum 컴파일러는 이들을 AST로 구문 분석하고 각 유형에 대한 partial C# 구조체 정의를 생성합니다(필요한 경우 정의를 여러 파일로 분할할 수 있으며 컴파일러는 이에 따라 이들을 병합합니다).

DSL의 목표는 시뮬레이션에 대한 결정론적 예측/롤백 접근 방식을 지원하는 데 필요한 Quantum의 ECS 희소 세트 메모리 모델에 의해 부과되는 복잡한 메모리 정렬 요구 사항을 개발자로부터 추상화하는 것입니다.

또한 이 코드 생성 방식을 사용하면 유형 일련화(스냅샷, 게임 저장, 킬캠 리플레이에 사용됨), 체크섬 및 디버깅을 위한 프레임 데이터 인쇄/덤핑과 같은 기타 기능을 위해 "보일러 플레이트" 코드를 작성할 필요가 없습니다.

컴포넌트

컴포넌트는 엔티티에 붙일 수 있고 부착된 컴포넌트를 기반으로 활성 엔티티의 하위 집합만 반복하여 필터링하는 데 사용할 수 있는 특수 구조체입니다. 다음은 컴포넌트의 기본적인 정의 예제입니다.

C#

component Action
{
    FP Cooldown;
    FP Power;
}

이것들은 정규 C# 구조체로 바뀔 것입니다. 위의 컴포넌트로 레이블을 지정하면 적절한 코드 구조체(마커 인터페이스, ID 속성 등)가 생성됩니다.

Quantum은 사용자 지정 구성 요소 외에도 다음과 같은 몇 가지 사전 컴포넌트가 제공됩니다.

  • Transform2D/Transform3D: 고정 포인트(FP) 값을 사용하여 위치 및 회전합니다.
  • PhysicsCollider, PhysicsBody, PhysicsCallbacks, PhysicsJoints (2D/3D): Quantum의 상태 비저장 물리 엔진에서 사용됩니다.
  • PathFinderAgent, SteeringAgent, AvoidanceAgent, AvoidanceOBstacle: navmesh 기반 경로 찾기 및 이동

구조체

구조체는 DSL과 C#에 모두 정의될 수 있습니다.

DSL 정의

Quantum DSL은 정규 구조체(컴포넌트, 메모리 정렬 및 헬퍼 함수가 처리되는 것과 마찬가지로)의 정의도 허용합니다.

C#

struct ResourceItem
{
    FP Value;
    FP MaxValue;
    FP RegenRate;
}

구조체가 생성될 때 필드는 알파벳순으로 정렬됩니다. 특정 순서로 표시해야 하는 경우 C#에서 구조체를 정의해야 합니다(아래 섹션 참조).

이렇게 하면 DSL의 다른 모든 부분에서 "리소스" 구조체를 타입으로 사용할 수 있습니다(예: 컴포넌트 정의 내에서 사용).

C#

component Resources
{
    ResourceItem Health;
    ResourceItem Strength;
    ResourceItem Mana;
}

생성된 구조체는 partial이며 원하는 경우 C#에서 확장할 수 있습니다.

CSharp 정의

C#에서도 구조체를 정의할 수 있지만, 이 경우에는 구조체의 정렬된 메모리를 수동으로 정의해야 합니다.

C#

[StructLayout(LayoutKind.Explicit)]
public struct Foo {
  public const int SIZE = 12; // the size in bytes of all members in bytes.
  
  [FieldOffset(0)]
  public int A;
  
  [FieldOffset(4)]
  public int B;
  
  [FieldOffset(8)]
  public int C;
}

DSL에서 C# 정의 구조체(예: 컴포넌트 내부)를 사용할 경우 구조체 정의를 수동으로 가져와야 합니다.

import struct Foo(12);

주의: import 는 크기의 상수를 지원하지 않으므로 매번 정확한 숫자 값을 지정해야 합니다.

컴포넌트 vs. 구조체

중요한 질문은 왜 그리고 언제 정규 구조체(결국 컴포넌트도 구조체임) 대신 컴포넌트를 사용해야 하는가입니다.

컴포넌트에는 다음과 같은 기능이 있는 특수 유형으로 변환하는 생성된 메타 데이터가 포함되어 있습니다.

  • 엔티티에 직접 붙일 수 있습니다.
  • 게임 상태를 통과할 때 엔티티를 필터링하는 데 사용됩니다(다음 장에서는 필터 API에 대해 살펴봅니다).

컴포넌트는 다른 구조체와 마찬가지로 포인터 또는 값 유형으로 매개변수에 접근, 사용 또는 전달할 수 있습니다.

동적 컬렉션

Quantum의 사용자 지정 할당기는 롤백 가능한 게임 상태의 일부로 블릿 가능한 컬렉션을 표시합니다. 컬렉션은 블리터블 유형(즉, 기본 및 DSL 정의 유형)만 지원합니다.

컬렉션을 관리하기 위해 프레임 API는 각각 3가지 메소드를 제공합니다.

  • Frame.AllocateXXX: 힙의 컬렉션에 공간을 할당
  • Frame.FreeXXX: 컬렉션의 메모리를 해제/할당 해제
  • Frame.ResolveXXX: 포인터를 확인하여 컬렉션에 접근

노트: 컬렉션을 해제한 후에는 default으로 설정하여 null로 해야합니다. 이것은 게임 상태의 직렬화가 제대로 작동하기 위해 필요합니다. 널화를 생략하면 비결정적 동작과 비동기화가 발생합니다. 컬렉션을 해제하고 해당 Ptrs를 수동으로 무효화하는 대신 해당 필드에 FreeOnComponentRemoved 특성을 사용할 수 있습니다.

중요한 노트

  • 여러 컴포넌트가 동일한 컬렉션 인스턴스를 참조할 수 있습니다.
  • 동적 컬렉션은 컴포넌트 및 구조체 내부의 참조로 저장됩니다. 따라서 초기화할 때 할당 해야 하며, 더 이상 필요하지 않을 때는 freed 해야 합니다. 집합이 컴포넌트의 일부인 경우 두 가지 옵션을 사용할 수 있습니다.
    • 대응 콜백 ISignalOnAdd<T>ISignalOnRemove<T>을 구현하고 여기에서 컬렉션을 할당/해제합니다. (이러한 특정 신호에 대한 자세한 내용은 매뉴얼의 ECS 섹션에 있는 컴포넌트 페이지를 참조하십시오)
    • [AllocateOnComponentAdded][FreeOnComponentRemoved] 속성을 사용하여 Quantum이 컴포넌트를 추가하고 제거할 때 각각 할당 및 할당 해제를 처리할 수 있습니다.
  • Quantum은 값이 없는 한 프로토타입에서 컬렉션을 사전 할당하지 않습니다. 컬렉션이 비어 있으면 메모리를 수동으로 할당해야 합니다.
  • 컬렉션의 free 를 두 번 이상 시도하면 오류가 발생하고 내부적으로 힙이 잘못된 상태가 됩니다.

리스트

동적 리스트는 list<T> MyList를 사용하여 DSL 내에서 정의할 수 있습니다.

component Targets {
  list<EntityRef> Enemies;
}

리스트를 다루는 기본 API 메소드는 다음과 같습니다::

  • Frame.AllocateList<T>()
  • Frame.FreeList(QListPtr<T> ptr)
  • Frame.ResolveList(QListPtr<T> ptr)

해결되면 Add, Remove, Contains, IndexOf, RemoveAt, [], 등과 같은 리스트의 모든 예상 API 메소드를 사용하여 목록을 반복하거나 조작할 수 있습니다.

위의 코드 조각에 정의된 Targets 유형의 컴포넌트에서 목록을 사용하려면 다음 시스템을 만들 수 있습니다.

C#

namespace Quantum
{
    public unsafe class HandleTargets : SystemMainThread, ISignalOnComponentAdded<Targets>, ISignalOnComponentRemoved<Targets>
    {
        public override void Update(Frame f) 
        {
            var targets = f.GetComponentIterator<Targets>();

            for (int i = 0; i < targets.Count; i++)
            {
                var target = targets[i];

                // To use a list, you must first resolve its pointer via the frame
                var list = frame.ResolveList(target.Enemies);

                // Do stuff
            }
        }

        public void OnAdded(Frame f, EntityRef entity, Targets* component)
        {
            // allocating a new List (returns the blittable reference type - QListPtr)
            component->Enemies = f.AllocateList<EntityRef>();
        }
        
        public void OnRemoved(Frame f, EntityRef entity, Targets* component)
        {
            // A component HAS TO de-allocate all collection it owns from the frame data, otherwise it will lead to a memory leak.
            // receives the list QListPtr reference.
            f.FreeList(component->Enemies);
            
            // All dynamic collections a component points to HAVE TO be nullified in a component's OnRemoved
            // EVEN IF is only referencing an external one!
            // This is to prevent serialization issues that otherwise lead to a desynchronisation.
            component->Enemies = default;
        }
    }
}

딕셔너리

딕셔너리는 dictionary<key, value> MyDictionary와 같이 DSL 에서 선언할 수 있습니다.

C#

component Hazard{
    dictionary<EntityRef, Int32> DamageDealt;
}

딕셔너리를 다루는 기본 API 메소드는 다음과 같습니다:

  • Frame.AllocateDictionary<K,V>()
  • Frame.FreeDictionary(QDictionaryPtr<K,V> ptr)
  • Frame.ResolveDictionary(QDictionaryPtr<K,V> ptr)

다른 동적 컬렉션과 마찬가지로 프레임 데이터에서 할당 취소하고 사전을 더 이상 사용하지 않으면 무효화할 뿐만 아니라 사용하기 전에 할당해야 합니다. 위의 목록에 대한 절에 제공된 예를 참조하십시오.

HashSet

HashSets은 hash_set<T> MyHashSet와 같이 DSL에서 선언할 수 있습니다.

C#

component Nodes{
    hash_set<FP> ProcessedNodes;
}

이러한 해시 세트를 다루는 기본 API 메소드는 다음과 같습니다:

  • Frame.AllocateHashSet(QHashSetPtr<T> ptr, int capacity = 8)
  • Frame.FreeHashSet(QHashSetPtr<T> ptr)
  • Frame.ResolveHashSet(QHashSetPtr<T> ptr)

다른 동적 컬렉션과 마찬가지로 프레임 데이터에서 할당 취소하고 해시 세트가 더 이상 사용되지 않으면 무효화해야 합니다. 위의 목록에 대한 절에 제공된 예를 참조하십시오.

Unions, Enums 및 Bitsets

C와 유사한 유니온 및 이넘도 생성할 수 있습니다. 아래 예제는 일부 상호 배타적인 데이터 유형/값을 조합으로 겹쳐서 데이터 메모리를 절약하는 방법을 보여줍니다:

C#

struct DataA
{
    FPVector2 Something;
    FP Anything;
}

struct DataB
{
    FPVector3 SomethingElse;
    Int32 AnythingElse;
}

union Data
{
    DataA A;
    DataB B;
}

생성된 유형 Data 에는 유니언 유형이 채워진 것을 알 수 있는 미분자 속성도 포함됩니다. 유니온 하위 유형 중 하나를 "터칭"하면 이 속성이 적절한 값으로 설정됩니다.

비트셋을 사용하여 원하는 목적을 위해 고정 크기 메모리 블록을 선언할 수 있습니다(예: 포그 오브 워, 픽셀 퍼펙트 게임 메카닉을 위한 그리드 유사 구조 등).

C#

struct FOWData
{
    bitset[256] Map;
}

입력

Quantum에서 클라이언트 간에 교환되는 런타임 입력은 DSL에서도 선언됩니다. 다음은 게임의 입력으로 간단한 이동 벡터를 정의하는 예입니다:

C#

input
{
    FPVector2 Movement;
}

버튼과 같은 입력의 경우 Quantum은 상태 변화를 안전하게 계산할 수 있으므로(다음 장 - 시스템에서 다루게 됨) 특수 유형 "버튼"을 사용해야 합니다:

C#

input
{
    FPVector2 Movement;
    button Fire;
}

버튼은 네트워크 프로토콜의 단일 비트만 사용하기 때문에 예측/롤백 게임에 이상적인 유형인 경우가 많습니다.

입력 구조는 매 틱마다 폴링 되어 서버로 전송됩니다(온라인 플레이 시). 서버는 전체 틱 세트(모든 플레이어의 입력)에 대한 입력 확인을 일괄 처리하고 전송하는 역할을 합니다. 이러한 이유로 이 구조체는 가능한 한 최소 크기로 유지되어야 합니다.

결정론적 커맨드(챕터 참조)는 Quantum의 또 다른 입력 경로이며 임의의 데이터와 크기를 가질 수 있으므로 "이 아이템 구입", "어디로 원격 이동" 등과 같은 특수 유형의 입력에 이상적입니다.

시스템에 의해 입력이 소비되고 유니티에서 Quantum으로 주입되는 방식을 이해하려면 다음 장을 참조하십시오.

시그널

시그널은 분리된 시스템 간 통신 API(게시자/가입자 API의 일종)로 사용되는 함수 서명입니다. 이렇게 하면 간단한 시그널이 정의됩니다(특수 유형 entity_ref 에 표시되며, 이 장 끝에 나열됩니다):

C#

signal ApplyDamage(FP damage, entity_ref entity);

그러면 다음과 같은 인터페이스가 생성됩니다(모든 시스템에서 구현할 수 있음):

C#

public interface ISignalOnDamage
{
    public void OnDamage(Frame f, FP damage, EntityRef entity);
}

신호는 Quantum DSL에서 포인터를 직접 선언할 수 있는 유일한 개념이므로 참조에 의한 데이터 전달을 사용하여 구체적인 구현에서 원본 데이터를 직접 수정할 수 있습니다:

C#

signal OnDamageBefore(FP Damage, Resources* resources);

이렇게 하면 컴포넌트 참조 유형 대신 컴포넌트 포인터를 전달할 수 있습니다.

이벤트

이벤트는 시뮬레이션 내부에서 발생하는 내용을 렌더링 엔진에 전달하는 세밀한 솔루션입니다(게임 상태의 일부를 수정/업데이트하는 데 사용해서는 안 됩니다). "event" 키워드를 사용하여 이름과 데이터를 정의합니다.

C#

event TriggerSound
{
    FPVector2 Position;
    FP Volume;
}

이벤트에 상속을 사용할 수 있습니다(선택적으로 일부 이벤트는 추상적으로 표시될 수 있으므로 직접 트리거되지 않도록 차단하고 구체적인 하위 클래스만 허용):

C#

abstract event TriggerSound
{
    FPVector2 Position;
    Int32 SoundID; // this would be better handled with unity-side asset linking extensions, but this is out of the scope of this chapter
}

event TriggerShot : TriggerSound
{    
    FP Power;
}

서버에서 입력 데이터가 확인될 때만 특정 이벤트가 (통합으로) 발송되도록 하려면(롤백으로 인한 거짓 긍정을 방지함) synced키워드를 사용하십시오:

C#

synced event TriggerDeathSound : TriggerSound
{    
}

원치 않는 중복 디스패치를 방지하기 위해 Quantum은 모든 이벤트 유형에 대한 해시코드 함수를 자동으로 생성합니다(이벤트 데이터를 소스로 사용). 경우에 따라 개발자는 이벤트 인스턴스를 고유하게 만드는 키 후보 데이터가 무엇인지 엄격하게 제어해야 할 수 있습니다. 예를 들어, 위치가 약간 변경되어 동일한 이벤트의 두 인스턴스가 서로 다른 두 이벤트로 잘못 해석되는 경우가 있습니다. 이를 방지하기 위해 해시 함수가 "nothashed" 키워드를 사용하여 일부 이벤트 데이터를 무시하도록 강제할 수 있습니다.

C#

abstract event TriggerSound
{
    nothashed FPVector2 Position;
    Int32 SoundID;
}

이벤트에 player_ref 파라미터가 포함된 경우 localremote 키워드를 적용하여 이벤트를 필터링할 수 있습니다.

C#

event KilledOtherPlayer {
  local  player_ref Killer;
  remote player_ref Killed;
}

이 이벤트가 유니티 측에서 발송되면 먼저 player_ref 변수가 앞에 있는 키워드와 일치하는지 여부를 확인합니다. 위의 예에서 이는 Killer 가 로컬 플레이어 이고 Killed 플레이어가 원격 플레이어인 경우에만 유니티에서 이벤트가 발생함을 의미합니다. 두 조건 중 어느 하나라도 의도되지 않으면 유니티에서 이벤트가 억제됩니다.

Quantum 2.1에서는 clientserver 키워드를 사용하여 이벤트를 추가로 필터링할 수 있습니다. 이벤트가 client로 표시되면 클라이언트 빌드에서만 트리거되지만, server 키워드는 서버 플러그인에서만 이벤트가 트리거됩니다. 주의: 사용자 지정 플러그인을 사용하여 서버 측 시뮬레이션을 실행하는 경우에만 해당됩니다.

Quantum(시스템)에서 이벤트가 트리거되고 유니티 콜백(Bootstrap Unity Project)으로 디스패치/확인/취소되는 방법에 대해서도 다음 장을 참조하십시오.

글로벌

DSL에서 전역으로 접근할 수 있는 변수를 정의할 수 있습니다. global 범위를 사용하여 모든 .qtn 파일에 글로벌을 선언할 수 있습니다.

C#

global {
    // Any type that is valid in the DSL can also be used.
    FP MyGlobalValue;
}

DSL 정의의 모든 것과 마찬가지로 글로벌 변수는 상태의 일부이며 예측 롤백 시스템과 완벽하게 호환됩니다.

글로벌 범위에 선언된 변수는 프레임 API를 통해 사용할 수 있습니다. 프레임에 접근할 수 있는 모든 위치에서 접근(읽기/쓰기)할 수 있습니다. ECS 섹션의 Systems 문서를 참조하십시오.

주의: 전역 변수의 대안으로 싱글톤 컴포넌트가 있습니다. 자세한 내용은 매뉴얼의 ECS 섹션에 있는 컴포넌트 페이지를 참조하십시오.

특수 타입

Quantum에는 복잡한 개념(엔티티 참조, 플레이어 인덱스 등)을 추상화하거나 관리되지 않는 코드의 일반적인 실수로부터 보호하는 데 사용되는 몇 가지 특수 타입이 있습니다. 다음과 같은 특수 타입을 다른 데이터 유형(컴포넌트, 이벤트, 시그널 등) 내부에서 사용할 수 있습니다.

  • player_ref: 런타임 플레이어 인덱스를 나타냅니다(Int32로 캐스팅되거나 Int32에서 캐스팅됨). 컴포넌트에 정의되어 있는 경우, Quantum의 플레이어 인덱스 기반 입력과 함께 연결된 엔티티를 제어하는 플레이어를 저장하는 데 사용할 수 있습니다.
  • entity_ref: 퀀텀의 각 프레임/틱 데이터가 별도의 메모리 영역/블록에 상주하기 때문에(퀀텀은 롤백을 지원하기 위해 몇 개의 복사본을 보관함), 프레임 간에 포인터를 캐시할 수 없습니다(유니티 스크립트에서도 마찬가지). 엔티티 ref는 엔터티의 인덱스 및 버전 속성을 추상화합니다(개발자가 이전 ref를 사용하여 제거되거나 재사용된 엔티티 슬롯을 통해 사용되지 않는 데이터에 실수로 접근하지 않도록 보호).
  • asset_ref<AssetType>: Quantum 에셋 데이터베이스의 데이터 에셋 인스턴스에 대한 롤백 가능한 참조입니다(데이터 에셋 장을 참조하십시오).
  • list<T>, dictionary<K,T>: 동적 컬렉션 참조(퀀텀의 프레임 힙에 저장)입니다. 블리터블 타입(기본 + DSL 정의 유형)만 지원합니다.
  • array<Type>[size]: 고정 크기 "배열"은 데이터 컬렉션을 나타냅니다. 일반 C# 배열은 힙에 할당된 개체 참조(속성 등이 있음)이며, 이는 Quantum의 메모리 요구 사항을 위반하므로 특수 배열 타입은 게임 상태 내에서 롤백 가능한 데이터 수집을 유지하기 위해 포인터 기반 단순 API를 생성합니다.

에셋에 대한 노트

에셋은 개발자가 인덱스된 데이터베이스 내에서 불변 인스턴스로 끝나는 데이터 기반 컨테이너(상속, 다형 메서드 등)를 정의할 수 있는 Quantum의 특수 기능입니다. "asset" 키워드는 (기존) 클래스를 게임 상태 내에서 참조를 할당할 수 있는 데이터 에셋으로 할당하는 데 사용됩니다(기능 및 제한에 대한 자세한 내용은 데이터 에셋 장을 참조하십시오).

C#

asset CharacterData; // the CharacterData class is partially defined in a normal C# file by the developer

다음 구조체는 위의 몇 가지 유효한 타입의 예를 보여줍니다(때로는 이전에 정의된 유형 참조):

C#

struct SpecialData
{
    player_ref Player;
    entity_ref Character;
    entity_ref AnotherEntity;
    asset_ref<CharacterData> CharacterData;
    array<FP>[10] TenNumbers;
}

사용가능한 타입

DSL에서 작업할 때 다양한 타입을 사용할 수 있습니다. 일부는 파서에 의해 미리 가져오고 다른 일부는 수동으로 가져와야 합니다.

기본값

Quantum의 DSL 파서에는 게임 상태 정의에 사용할 수 있는 미리 가져온 교차 플랫폼 결정론적 유형의 목록이 있습니다.

  • Boolean / bool - 내부적으로 동일한 작업(Get/Set, 비교 등)을 수행하는 QBoolean으로 래핑됩니다.
  • Byte
  • SByte
  • UInt16 / Int16
  • UInt32 / Int32
  • UInt64 / Int64
  • FP
  • FPVector2
  • FPVector3
  • FPMatrix
  • FPQuaternion
  • PlayerRef / player_ref in the DSL
  • EntityRef / entity_ref in the DSL
  • LayerMask
  • NullableFP / FP? in the DSL
  • NullableFPVector2 / FPVector2? in the DSL
  • NullableFPVector3 / FPVector3? in the DSL
  • QString is for UTF-16 (aka Unicode in .NET)
  • QStringUtf8 is always UTF-8
  • Hit
  • Hit3D
  • Shape2D
  • Shape3D
  • Joint, DistanceJoint, SpringJoint and HingeJoint

Qstrings에 대한 노트: N은 부기에 사용된 2바이트를 뺀 바이트 단위의 총 문자열 크기를 나타냅니다. 즉, QString<64>은 최대 바이트 길이가 62바이트인 문자열에 64바이트, 즉 최대 31개의 UTF-16 캐릭터를 사용합니다.

수동 불러오기

이전 섹션에 나열되지 않은 타입이 필요한 경우 QTN 파일에서 사용할 때 수동으로 가져와야 합니다.

Quantum 외부의 Namespaces / Types

다른 네임스페이스에 정의된 유형을 가져오려면 다음 구문을 사용하십시오:

C#

import MyInterface;
또는
import MyNameSpace.Utils;

열거형의 구문은 다음과 같습니다:

C#

import enum MyEnum(underlying_type);

// This syntax is identical for Quantum specific enums
import enum Shape3DType(byte);

기본 제공 퀀텀 유형 및 사용자 지정 유형

Quantum 기본 제공 유형 또는 사용자 지정 유형을 가져올 때 구조체 크기는 해당 C# 선언에 미리 정의되어 있습니다. 따라서 몇 가지 안전 조치를 추가하는 것이 중요합니다.

C#

namespace Quantum {
  [StructLayout(LayoutKind.Explicit)]
  public struct Foo {
    public const int SIZE = sizeof(Int32) * 2;
    [FieldOffset(0)]
    public Int32 A;
    [FieldOffset(sizeof(Int32))]
    public Int32 B;
  }
}

C#

#define FOO_SIZE 8 // Define a constant value with the known size of the struct
import struct Foo(8);

구조체의 예상 크기를 실제 크기와 동일하게 유지하려면 시스템 중 하나에 아래와 같이 Assert를 추가하는 것이 좋습니다.

C#

public unsafe class MyStructSizeCheckingSystem : SystemMainThread{    
    public override void OnInit(Frame f)
    {
        Assert.Check(Constants.FOO_SIZE == Foo.SIZE);
    }
}

업그레이드 중에 기본 제공 구조체의 크기가 변경되면 이 Assert를 사용하여 DSL의 값을 업데이트할 수 있습니다.

속성

Quantum은 인스펙터에 매개 변수를 표시하는 몇 가지 속성을 지원합니다.

속성 파라미터 설명
DrawIf string fieldName
long value
CompareOperator compare
HideType hide
조건이 true로 평가되는 경우에만 속성을 표시합니다.

*fieldName* = 평가할 속성의 이름
*value* = 비교에 사용되는 값
*compare* = 수행되는 비교 연산 `Equal, NotEqual, Less, LessOrEqual, GreaterOrEqual 또는 Greater`.
*hide* = 평가 값이 "False" `Hide or ReadOnly`일때의 필드의 행동.

비교, 숨김에 대한 상세 정보는 아래를 참고하세요.
Header string header 속성 위에 헤더를 추가

*header* = 표시할 헤더 텍스트
HideInInspector - 필드를 직렬화하고 유니티 인스펙터에서 다음 속성을 숨김
Layer - **int** 타입에만 적용 가능.
필드 상의 EditorGUI.LayerField 호출.
선택 string enabledPropertyPath 속성의 표시를 켜거나 끌 수 있습니다.
*enabledPropertyPath* = 토글을 평가하기 위해 사용되는 *bool* 경로.
Space - 속성 위에 공백을 추가
Tooltip string tooltip 속성 위에 마우스가 위치해있을 때 도구 설명을 표시합니다.

*tooltip* = 표시할 팁.
ArrayLength (2.1 부터)
FixedArray (2.0 에서)
CSharp에서만
int length
--------
int minLength
int maxLength
*length*를 사용하면 배열 크기를 정의할 수 있습니다.
------
*minLength* 및 *maxLength*를 사용하면 인스펙터에서 크기 범위를 정의할 수 있습니다.
인스펙터에서 최종 크기를 설정할 수 있습니다.
(*minLength* 및 *maxLength* 포함)
ExcludeFromPrototype - 컴포넌트 및 컴포넌트 필드 모두에 적용할 수 있습니다.
------
- 필드: 컴포넌트에 대해 생성된 프로토타입에서 필드를 제외합니다.
- 컴포넌트: 이 컴포넌ㄴ트에 대한 프로토타입이 생성되지 않습니다.
PreserveInPrototype - 타입에 추가하여 프로토타입에서 사용할 수 있는 것으로 표시하고 프로토타입 클래스가 방출되지 않도록 합니다.
필드에 추가되면 특정 필드에만 영향을 미칩니다. 유니티 측에서 `_Prototype` 유형을 사용할 필요가 없으므로 간단한 `[Serializable]` 구조체에 유용합니다.
AllocateOnComponentAdded - 동적 컬렉션에 적용할 수 있습니다.
이렇게 하면 컬렉션을 보유하고 있는 컴포넌트가 엔티티에 추가될 때 아직 할당되지 않은 컬렉션에 대해 메모리가 할당됩니다.
FreeOnComponentRemoved - 동적 집합 및 Ptrs에 적용할 수 있습니다.
이렇게 하면 관련 메모리 할당이 해제되고 컴포넌트가 제거될 때 필드에 저장된 Ptr이 무효화됩니다.
------
중요: 이 속성을 상호 참조된 컬렉션과 함께 사용하지 마십시오. 이 속성은 특정 필드에 있는 Ptr만 무효화되며 다른 속성은 잘못된 메모리를 가리킵니다.
*속성*은 별도로 지정하지 않는 한 C# 및 qtn 파일에서 모두 사용할 수 있지만 구문상 차이가 있습니다.

CSharp에서 사

C# 파일에서 속성은 다른 특성처럼 사용하고 연결할 수 있습니다.

C#

// Multiple single attributes
[Header("Example Array")][Tooltip("min = 1\nmax = 20")] public FP[] TestArray = new FP[20];

// Multiple concatenated attributes
[Header("Example Array"), Tooltip("min = 1\nmax = 20")] public FP[] TestArray = new FP[20];

qtn에서 사용

qtn 파일에서 단일 속성의 사용은 C#에서와 동일하게 유지됩니다.

C#

[Header("Example Array")] array<FP>[20] TestArray;

여러 속성을 결합할 때는 이 결합되어야 합니다.

C#

[Header("Example Array"), Tooltip("min = 1\nmax = 20")] array<FP>[20] TestArray;

컴파일러 옵션

현재 Quantum의 DSL 파일 내에서 사용할 수 있는 컴파일러 옵션은 다음과 같습니다:

C#

// pre defining max number of players (default is 6, absolute max is 64)
#pragma max_players 16

// numeric constants (useable inside the DSL by MY_NUMBER and useable in code by Constants.MY_NUMBER)
#define MY_NUMBER 10

// overriding the base class name for the generated constants (default is "Constants")
#pragma constants_class_name MyFancyConstants
Back to top