몬스터 AI가 특정 목표물(창고)을 향해 이동하는 구조를 설계할 때, 가장 중요한 것은 책임의 분리.
Warehouse Actor를 향해 이동.BehaviorTree의 MoveTo 노드를 사용.MoveTo는 단순히 이동만 담당하며, 이동 목표는 실행 전 이미 Blackboard에 세팅되어 있어야함.Warehouse Actor를 월드에 배치합니다.DefaultWarehouseActor를 스폰된 몬스터에게 전달OnPossess 시점에 Monster의 목표 정보를 Blackboard 키값으로 기록Blackboard에 저장된 WarehouseActor 키를 바탕으로 MoveTo를 실행몬스터가 스폰되는 즉시 목표 지점을 알 수 있도록 데이터를 주입
// Spawner.h
UPROPERTY(EditAnywhere, Category = "Warehouse")
AActor* DefaultWarehouseActor = nullptr;
// Spawner.cpp
APotatoMonster* Monster = GetWorld()->SpawnActor<APotatoMonster>(...);
if (Monster && DefaultWarehouseActor)
{
// 스폰 직후 몬스터 멤버 변수에 목표 주입
Monster->WarehouseActor = DefaultWarehouseActor;
}
컨트롤러는 몬스터를 조종(Possess)하기 시작할 때, 몬스터가 가진 정보를 Blackboard로 복사
C++
// MonsterAIController.cpp
void AMonsterAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
AMonster* Monster = Cast<AMonster>(InPawn);
if (Monster && BlackboardComp)
{
if (Monster->WarehouseActor)
{
// Blackboard 키 세팅
BlackboardComp->SetValueAsObject(FName("WarehouseActor"), Monster->WarehouseActor);
}
else
{
// 목표가 없을 경우 클리어 (MoveTo 실행 방지)
BlackboardComp->ClearValue(FName("WarehouseActor"));
}
}
}
Blackboard: WarehouseActor라는 이름의 Object 타입 키를 생성하고, Base Class를 Actor로 설정
Behavior Tree: MoveTo 노드의 Blackboard Key를 WarehouseActor로 지정
Target이 없으면(Null) MoveTo 노드가 실행되지 않으므로 안정성이 확보
🔹 명확한 역할 분담
Spawner: "누가 어디로 가야 하는가"를 결정 (전략적 주입)
AIController: "주어진 정보를 지능 시스템에 전달" (중계)
Behavior Tree: "주어진 정보를 바탕으로 행동" (실행)
🔹 확장 시나리오
GameState 도입: Spawner가 일일이 주입하지 않고, GameState에 캐싱된 Warehouse를 AI가 가져오는 방식으로 변경 가능
게임 종료 처리: Warehouse 파괴 시 관련 이벤트를 발생시켜 모든 AI의 로직을 즉시 중단(Blackboard Key Clear)
사전 주입: 목표는 런타임 검색이 아닌 스폰 시점의 주입으로 확정한다.
단순화: AIController는 검색 로직 없이 Blackboard 전달자 역할만 수행한다.
안정성: 유효한 목표가 있을 때만 MoveTo가 작동하도록 설계하여 런타임 에러를 방지한다.
GetAllActorsOfClass 같은 무거운 월드 탐색을 제거하고 직접 참조(Reference)를 활용해 성능 안정성을 확보합니다.시스템은 "무엇을, 언제, 어떻게"라는 질문에 따라 데이터를 계층화합니다.
웨이브 전체의 리듬을 관리합니다. (1 웨이브 = 1 행)
Round, WaveId, PreDelay, SpawnInterval특정 웨이브에 등장할 몬스터들을 정의합니다. (1 웨이브 = 다수 행)
WaveId, Rank (Normal/Elite/Boss), Type (EMonsterType), Count, Delay몬스터의 외형적 종류에 따른 기본 스탯을 정의합니다.
BaseHP, BaseAttackDamage, MoveSpeedMultiplier, ProjectileClass, OverrideBehaviorTree몬스터의 등급(Normal, Elite, Boss)에 따른 스탯 배율을 정의합니다.
HpMultiplierMin/Max, StructureDamageMultiplier, SpecialCooldownMultiplier몬스터가 가질 수 있는 특수 로직의 단일 진실 소스(Single Source of Truth)입니다.
SkillLogic (Split/Charge/AoE/Poison 등)Trigger (OnCooldown/OnDeath/OnNearTarget)TelegraphTime, Radius, DamageMultiplier, VFXSpawner는 에디터 디테일 패널에서 필요한 모든 에셋을 참조하며, 런타임에 이들을 조합합니다.
DefaultWarehouseActor (직접 지정)TMap<EMonsterType, TSubclassOf<APotatoMonster>> MonsterClassByType테이블에 복잡한 BP 경로를 넣는 대신, 열거형(Enum)을 키값으로 클래스를 매핑합니다.
| Key (Type) | Value (Blueprint Class) |
| :--- | :--- |
| Slime | BP_Monster_Slime |
| Mimic | BP_Monster_Mimic |
| Skeleton | BP_Monster_Skeleton |
| Mushroom | BP_Monster_MushroomAngry |
📌 핵심: 타입이 늘어나면
TMap에 한 줄 추가하고 테이블에 해당 타입을 적기만 하면 즉시 스폰이 가능해집니다.
TMap에서 관리하므로 런타임 에러 대응이 쉽습니다.SpecialSkillPresetTable 덕분에 특정 몬스터에게 새로운 스킬을 부여할 때 데이터 수정만으로 가능합니다.