지난 시간까지 만든 AI는 플레이어를 보면 쫓아오고, 놓치면 수색하는 단순한 '반응형 AI'였다. 이번에는 여기서 한 단계 더 나아가, 서비스(Service)를 활용해 AI가 스스로 상황을 분석하고 더 똑똑한 판단을 내리는 '전술적 AI'를 구현하는 과정을 정리했다. 핵심은 실시간으로 변하는 데이터를 블랙보드에 지속적으로 업데이트하고, 이를 바탕으로 행동 트리가 더 유연한 의사결정을 내리게 하는 것이다. 🧠
서비스 (Service)란?
서비스와 데코레이터의 협업 관계
DistanceToTarget 키에 쓴다(Write).DistanceToTarget 키를 읽고(Read), "값이 500보다 큰가?" 를 검사하여 조건이 맞으면 자식 노드를 실행시킨다.이 둘의 협업 덕분에 AI는 실시간으로 변화하는 전장 상황에 맞춰 유연하게 행동을 바꿀 수 있었다.
BB_Monster에 새로운 키를 추가했다.
DistanceToTarget (Type: Float): 플레이어와의 거리를 저장할 키.MyHealth (Type: Float): AI 자신의 현재 체력을 저장할 키.UBTService_UpdateTacticalInfo 라는 이름으로 새로운 C++ BT Service 클래스를 생성했다.
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/BTService.h"
#include "BTS_UpdateTacticalInfo.generated.h"
UCLASS()
class SPARTA_TPROJECT_02_API UBTS_UpdateTacticalInfo : public UBTService
{
GENERATED_BODY()
public:
UBTS_UpdateTacticalInfo();
protected:
// 서비스가 주기적으로 호출할 함수
virtual void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
private:
// 에디터에서 설정할 블랙보드 키 선택자
UPROPERTY(EditAnywhere, Category = "Blackboard")
FBlackboardKeySelector DistanceToTargetKey;
UPROPERTY(EditAnywhere, Category = "Blackboard")
FBlackboardKeySelector MyHealthKey;
};
#include "BTS_UpdateTacticalInfo.h"
#include "AIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "GameFramework/Character.h"
#include "AIMonsterBase.h" // AAIMonsterBase 헤더 포함
UBTS_UpdateTacticalInfo::UBTS_UpdateTacticalInfo()
{
NodeName = TEXT("Update Tactical Info");
Interval = 0.5f; // 0.5초마다 실행
RandomDeviation = 0.1f; // 실행 주기에 약간의 무작위성 부여
}
void UBTS_UpdateTacticalInfo::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);
AAIController* AIController = OwnerComp.GetAIOwner();
UBlackboardComponent* BlackboardComp = OwnerComp.GetBlackboardComponent();
if (AIController == nullptr || BlackboardComp == nullptr)
{
return;
}
// 1. AI 자신(Pawn)과 타겟 액터 가져오기
APawn* ControllingPawn = AIController->GetPawn();
if (ControllingPawn == nullptr) return;
AActor* TargetActor = Cast<AActor>(BlackboardComp->GetValueAsObject(TEXT("TargetActor")));
// 2. 타겟이 있을 경우, 거리 계산하여 블랙보드에 업데이트
if (TargetActor)
{
float Distance = FVector::Dist(ControllingPawn->GetActorLocation(), TargetActor->GetActorLocation());
BlackboardComp->SetValueAsFloat(DistanceToTargetKey.SelectedKeyName, Distance);
}
else
{
// 타겟이 없으면 키 값 초기화
BlackboardComp->ClearValue(DistanceToTargetKey.SelectedKeyName);
}
// 3. 자신의 체력 정보를 블랙보드에 업데이트
AAIMonsterBase* MyMonster = Cast<AAIMonsterBase>(ControllingPawn);
if (MyMonster)
{
BlackboardComp->SetValueAsFloat(MyHealthKey.SelectedKeyName, MyMonster->CurrentHealth);
}
}
새로 만든 서비스를 활용하여 행동 트리를 재구성했다. 전투 관련 로직을 담당하는 Selector 노드에 BTS_UpdateTacticalInfo 서비스를 추가했다.
[Selector] (여기에 'BTS_UpdateTacticalInfo' 서비스 추가)
├── [Sequence] (후퇴)
│ ├── [Decorator: Blackboard] MyHealth Is Less Than 30.0f
│ └── [Task: Find Safe Location & Move] // (안전한 곳으로 이동하는 태스크, 추후 구현)
│
├── [Sequence] (원거리 저격)
│ ├── [Decorator: Blackboard] DistanceToTarget Is Greater Than 1000.0f
│ └── [Task: Snipe Attack]
│
├── [Sequence] (일반 사격)
│ ├── [Decorator: Blackboard] DistanceToTarget Is Less Than 1000.0f
│ └── [Task: Normal Attack]
│
└── [추격/수색/순찰]
TargetActor가 설정되면), BTS_UpdateTacticalInfo 서비스가 활성화되어 0.5초마다 거리와 체력 정보를 블랙보드에 갱신한다. Selector는 이 최신 정보를 바탕으로 '후퇴', '저격', '일반 사격' 중 가장 우선순위가 높고 조건에 맞는 행동을 선택하게 된다.Observer Aborts 설정을 잊은 문제: 순찰하던 AI가 플레이어를 발견하고 추격을 시작했는데, 플레이어가 공격 범위에 들어와도 바로 공격하지 않고 추격을 마저 하려는 이상한 행동을 보였다. 확인해보니 공격 조건(거리가 가까운지)을 검사하는 데코레이터의 Observer Aborts 속성이 None으로 되어 있었다. 이 설정을 Lower Priority로 변경해주니, 추격(낮은 우선순위) 중에 공격(높은 우선순위) 조건이 만족되면 즉시 추격을 중단하고 공격을 시작했다. AI의 반응성을 결정하는 매우 중요한 설정이라는 것을 깨달았다.AIPerception은 기본적으로 다른 Pawn에 의해 시야가 가로막힌다. 이를 해결하기 위해 청각(Hearing) 감각을 추가로 설정했다. 플레이어가 총을 쏘거나 뛸 때 발생하는 소리(MakeNoise 함수 사용)를 AI가 감지하게 하여, 시야가 확보되지 않아도 소리가 난 위치로 일단 이동하도록 로직을 개선했다.| 개념 | 설명 | 비고 |
|---|---|---|
| 서비스 (Service) | BT의 특정 가지가 활성화된 동안, 주기적으로 로직을 실행하여 블랙보드 데이터를 갱신하는 노드. | AI의 '상황 분석가'. 행동을 직접 하진 않음. |
| 전술적 AI | 서비스가 분석한 데이터를 바탕으로, 데코레이터가 더 복잡한 조건(거리, 체력 등)을 판단하여 행동을 결정하는 AI. | 단순 반응형 AI보다 한 단계 높은 지능. |
| Observer Aborts | 데코레이터의 핵심 속성. Lower Priority로 설정 시, 하위 우선순위 작업 중에 상위 우선순위 조건이 만족되면 즉시 현재 작업을 중단하고 전환. | AI의 반응성에 결정적인 영향을 미침. |
| 다중 감각 활용 | 시각(Sight)만으로는 한계가 있을 때, 청각(Hearing) 등 다른 감각을 추가하여 AI의 인지 능력을 보완할 수 있음. | 좁은 공간이나 엄폐물이 많은 환경에서 특히 유용. |