This document is about: QUANTUM 1
SWITCH TO

Blackboard

Introduction

Blackboard는 Bot SDK 내에 포함되어 있는 다른 아주 유용한 툴입니다.
사용자 정의 데이터를 보유하는 데 사용할 수 있는 키/값 집합입니다.
이는 에이전트별로 가질 수 있는 액션 및 결정을 위한 읽기/쓰기 메모리와 같습니다.

Blackboard는 데이터 에셋을 사용하여 완전히 정의되므로 디자이너가 사용하기 쉽습니다.
따라서 Blackboard를 Unity 프로젝트에 저장하고 구성할 수 있습니다.

PS.: Blackboard 데이터 자산은 메모리 레이아웃 정의일 뿐입니다.
메모리 레이아웃이 같아야 하는 많은 Botts/Entities가 있는 경우 이러한 모든 항목이 동일한 Blackboard 에셋을 가리킬 수 있습니다.
그런 다음 각 bot는 레이아웃에 따라 자신의 고유의 메모리를 갖게 됩니다.

아주 간단한 예제

자, 맵에서 아이템들을 수집하는 캐릭터가 있다고 가정해 보겠습니다.
액션 및 결정에서 캐릭터가 특정 결정을 내리기 위해 이미 수집한 아이템들의 개수를 읽을 수 있습니다.
또한 캐릭터가 새 아이템을 수집하는 경우 아이템 수가 증가해야 합니다.
이를 위해 blackboard에 정수형의 ItemAmount라는 항목을 가질 수 있으며 액션 및 의사 결정 코드에 대해 관리할 수 있습니다.

blackboard가 엔티티 별로 사용되므로 다른 엔티티도 다른 엔티티의 blackboard에 포함된 데이터를 읽을 수 있습니다.

Blackboard 에셋 생성하기

유니티에서, Project 탭을 우 클릭하여 Create->Quantum->Assets->AIBlackboard 메뉴에서 새로운 Blackboard 에셋을 생성할 수 있습니다.
다음은 초기 에셋 상태입니다:

New Blackboard

이제 직접 항목을 만들고 유형과 이름을 설정하기만 하면 됩니다.

Blackboard entries

Blackboard에서 지원되는 형은 다음과 같습니다:

  1. Boolean;
  2. Byte;
  3. Integer;
  4. FP;
  5. Vector2;
  6. Vector3;
  7. Entity Ref.

Blackboard 사용하기

quantum_code 솔루션에서, 이미 엔티티에서 blackboard을 컴포넌트로 사용할 수 있습니다.

C#

entity Hero[8] {
    use Transform2D;
    use DynamicBody;
    use Prefab;
    use AIBlackboardComponent;
    ...
}

중요!

프로젝트에 실제로 Blackboard를 사용하기 전에 코드에 대해 필수 설정을 수행해야 합니다.
주어진 엔티티에서 blackboard를 반환하여 전체 blackboard 설정이 작동하도록 하는 방법이 있습니다.

하지만, 물론 각 게임마다 Blackboard를 사용하는 고유한 엔티티가 있고, 이는 게임마다 다릅니다.
따라서 게임에서 이 메소드를 구현해야 합니다.

매우 간단한 작업입니다: quantum_code 솔루션에서 Entity.Blackboard.cs라는 파일을 여십시오. 주석을 모두 해제하고 AIBlackboardComponent를 가지고 있는 "YourEntityType"을 자신의 엔티티 형으로 바꿉니다.
최종 결과는 다음과 같습니다:

C#

public unsafe partial struct Entity {
    public static AIBlackboardComponent* GetBlackboardComponent(Entity* entity) {
      switch (entity->_ref._type)
      {
        case EntityTypes.Hero:
          return &((Hero*)entity)->AIBlackboardComponent;
      }
      return null;
    }
  }

Blackboard 에셋 참조하기

AIBlackboardComponent에는 Unity에서 생성한 blackboard 데이터 에셋을 가리키는 Board라는 필드가 있습니다.
DB를 사용하거나 에셋 링크를 사용하여 참조할 수 있습니다.

C#

hero->AIBlackboardComponent.Board = playerData.BlackboardLink;
// Or
hero->AIBlackboardComponent.Board = DB.FindAllAssets<AIBlackboard>()[0];

이 정도면 개인 blackboard의 데이터를 이미 읽거나 쓸 수 있습니다.
하지만 읽기/쓰기 스니펫에 들어가기 전에 강조해야 할 또 다른 유용한 자료가 있습니다.

Blackboard 컴포넌트 메모리 초기화하기

blackboard에 저장된 서로 다른 데이터의 유형과 양이 정적 컨텍스트(예: 코드 생성)에서 생성되지 않기 때문에 각 컴포넌트의 메모리는 UserData(다른 모든 엔티티/구성 요소와 마찬가지로 게임 상태에 저장되는 것과 반대로)로 프레임에 저장해야 합니다.

각 Blackboard 컴포넌트는 엔티티가 생성된 후 Frame.CreateBlackboardMemory()을 한 번 호출하여 메모리를 예약해야 합니다. 나중에 Frame.DestroyBlackboardMemory()를 호출하여 이 엔티티가 소멸되기 전에 반드시 메모리를 해제해 주어야 합니다. "Failed to allocate memory" 메시지가 표시되면 blackboard 메모리를 해제하는 것을 잊었을 가능성이 높습니다.

C#

var hero = f.CreateHero();

// Call CreateBlackboardMemory before further configuration of the blackboard component.
f.CreateBlackboardMemory(&hero->AIBlackboardComponent);

// Continue the initialization.
var data = f.GetPlayerData(player);
if (data.BlackboardInitializer.Instance != null) {
    AIBlackboardInitializer.InitializeBlackboard(f, &hero->AIBlackboardComponent, data.BlackboardInitializer.Instance, null );
}

// Call DestroyBlackboardMemory before destroying the hero
f.DestroyBlackboardMemory(&hero->AIBlackboardComponent);
f.DestroyHero(hero);

Blackboard 초기화 에셋

이 에셋은 blackboard의 초기화를 돕기 위한 것입니다.
이것은 blackboard의 항목을 반영하며 각 항목에 대해 초기화 중에 blackboard에 적용할 기본값을 정의할 수 있습니다.

Blackboard Initializer 자산을 생성하려면 프로젝트 탭에서 마우스 오른쪽 버튼으로 클릭하고 Create->Quantum->Assets->AIBlackboardInitializer 를 선택합니다.
이렇게 하면 초기 상태가 될 것입니다.

Blackboard Initializer Default

그런 다음 이 에셋으로 초기화할 blackboard 에셋을 선택해야 합니다.
그러면, blackboard의 항목이 초기화 자산에 표시될 것 입니다.
그런 다음 해당 항목에 대한 초기 값을 정의하려면 필드 추가 버튼을 클릭할 수 있습니다.
다음과 같습니다:

Blackboard Default Entry

이제 시뮬레이션 코드에서 초기화 에셋에서 AIBlackboardComponent를 초기화하도록 선택할 수 있습니다.
다음은 여기에 필요한 코드입니다:

C#

AIBlackboardInitializer.InitializeBlackboard(f, &guy->AIBlackboardComponent, data.BlackboardInitializer.Instance, null);

data.BlackboardInitializer는 일부 BlackboardInitializer 대한 에셋 링크일 뿐이라는 것에 주의하세요.
DB.FindAsset<AIBlackboardInitializer>("Guid"); 를 사용하여 불러올 수 있습니다.

PS.: 원하는 경우 Blackboard 초기화 에셋을 기반으로 Blackboard 컴포넌트를 초기화하기 위한 샘플 코드가 있는 Bot SDK 샘플을 볼 수 있습니다.

엔티티를 다시 만들 때 Blackboard를 다시 초기화하기.

일부 엔티티를 파괴한 다음 같은 엔티티를 다시 만든다면, 일부 리스폰 기간 동안과 같이 해당 엔티티의 blackboard에는 이미 이전 라이프 사이클과 관련된 값이 들어 있습니다.

따라서 생성된 엔티티에 대해 Blackboard 데이터를 다시 초기화하여 이전 데이터가 사용되지 않도록 하는 것이 좋습니다.
이러한 상황에서 BlackboardInitializer 자산은 매우 유용합니다.
스폰 된 모든 엔티티에 AIBlackboardInitializer.InitializeBlackboard() 를 실행하면 됩니다.

Blackboard에 읽고 쓰기

blackboard 엔티티에 데이터를 읽고/쓰기 위해서

C#

var bb = Entity.GetBlackboardComponent(e);

// To read
var value = bb->Board.GetValue("someKey");

// To write
bb->Board.Set("someKey", value, frame, bb);

PS.: 버전 1.0 RC2 이상의 Bot SDK에는 Blackboard에 읽기/쓰기를 하는 몇 가지 샘플 액션/결정이 이미 포함되어 있습니다.
quantum_code 솔루션에서는 BotSDK/Samples 폴더로 이동하여 IncreaseBlackboardInt.cs, SetBlackboardInt.cs 그리고 HFSM.CheckBlackboardInt.cs파일을 확인해보세요.

Visual Editor의 Blackboard

Visual Editor에는 Blackboard용 하위 메뉴가 이미 제공됩니다.
이름은 Blackboard Variable이며 왼쪽 패널에서 액세스할 수 있습니다:

Blackboard Visual Editor Empty

새로운 blackboard 변수 생성을 하려면 + 버튼을 누릅니다.
신규 항목을 생성/편집할 때는 다음 사항을 정의해 주어야 합니다:

  • 변수 이름, 이 키는 내부적으로 일부 변수의 값을 검색하기 위해 blackboard 에셋의 키로 사용됩니다.
  • 변수의 , 드롭다운 메뉴에서 선택할 수 있습니다.
  • HasDefault 확인란, 설정 시 이 변수가 기본값으로 초기화되는지를 알리는 데 사용됩니다.
  • 사용되는 Default 값.
Blackboard Visual Editor Creating Entry

여러 유형의 항목이 있을 수 있으며 모든 유형의 항목이 기본값을 가질 필요는 없습니다:

Blackboard Visual Editor Many Entries

이제 프로젝트를 컴파일할 때마다 Assets/Resources/DB/CircuitExport/Blackboard_Assets 폴더에 두 개의 추가 데이터 에셋이 자동으로 생성됩니다.:

  • 컴파일된 HFSM에서 정의한 항목인 Blackboard 에셋;
  • 그리고 Blackboard 초기화 자산으로 항목과 기본값이 컴파일된 HFSM에 의해 정의되는 항목
Blackboard Assets

Blackboard 노드

변수를 손으로 그래프에 끌어다 놓으면 Blackboard 노드를 만들 수 있습니다. 이러한 노드에는 항상 이라는 두 개의 아웃바운드 슬롯이 있습니다.

Blackboard Assets

슬롯은 AIBlackboardValueKey 형의 필드에 연결될 때 사용되고, get/set을 하기 위한 변수의 키를 알려줄 때 하드 코딩된 문자열을 바꿀 때 사용될 수 있습니다. 물론 하드코딩된 키를 제거함으로써 코드의 안정성을 높일 수 있습니다. 전과 후의 get과 set을 분석하도록 하겠습니다.:

C#

var bb = Entity.GetBlackboardComponent(e);

// -- BEFORE --
// To read
var value = bb->Board.GetValue("someKey");

// To write
bb->Board.Set("someKey", value, frame, bb);


// -- AFTER --
public AIBlackboardValueKey PickupsKey;
// To read
var value = bb->Board.GetValue(PickupsKey.Key);

// To write
bb->Board.Set(PickupsKey.Key, value, frame, bb);

이 새 필드를 선언했으므로 Visual Editor로 이동하여 Blackboard 노드의 Key 슬롯에 연결할 수 있습니다. 예를 들어 다음과 같습니다:

Blackboard Assets

키 슬롯을 이와 같이 사용하는 것 외에 슬롯을 연결하여 동일한 유형의 필드를 정의할 수도 있습니다. 왼쪽 패널에 정의된 기본 값은 에셋에 베이크될 값입니다.

Blackboard Assets

Blackboard 및 해당 노드를 사용해야 하는 경우

런타임에 변경될 수 있는 엔티티당 데이터를 저장하려는 경우 언제든지 사용합니다. 변경되지 않는 값을 정의해야 하는 경우 대신 상수 패널을 사용하는 것이 좋습니다.

Blackboard의 프레임 메소드

Blackboard는 프레임의 부분적인 메소드:InitUser, FreeUser, AllocUserCopyFromUser를 구현합니다.

게임에 이미 이러한 메소드가 구현되어 있으면 충돌이 발생합니다.
이를 방지하기 위해서 컴파일러 심볼 USE_BLACKBOARD_FRAME_METHODS 를 설정할 수 있습니다.
이렇게 하면 Blackboard에서 부분 메소드를 구현할 수 없습니다.
각 메소드는 대체 메소드가 있습니다.
대체 메소드: InitBlackboard, FreeBlackboard, AllocBlackboard, CopyFromUserBlackboard, SerializeBlackboard 그리고 DeserializeBlackboard.

이러한 모든 방법이 프레임의 등가 메소드로 계속 호출되는지 확인하기만 하면 됩니다.

Back to top