간단한 적 AI
20강. 간단한 적 AI
1. 이번 강의에서 해결할 문제
적이 매 Tick에서 플레이어 위치를 향해 SetActorLocation으로 이동해 벽을 통과하거나 프레임 비용이 늘어납니다. Navigation 이동과 일정 간격 판단을 사용합니다.
2. 학습 목표
3. 핵심 개념
이번 AI는 Behavior Tree 이전 단계입니다. EnemyBase는 ACharacter라 CharacterMovement를 재사용하고, AIController가 Navigation 경로를 따라 이동합니다. 의사결정은 0.25초 Timer, 실제 이동 보간은 엔진 Movement Component가 처리합니다.
적마다 Tick을 열어 거리 검사와 경로 요청을 매 프레임 하지 않습니다. 더 복잡한 상태, 시야, 팀 전략은 이후 게임 AI 과정에서 State Tree, Behavior Tree, EQS 등을 비교합니다.
4. 단계별 실습
파일 경로: Source/TopDownSurvival/Enemies/EnemyBase.h · AI 필드
protected:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
UPROPERTY(EditDefaultsOnly, Category = "AI", meta = (ClampMin = "0.05", Units = "s"))
float ThinkInterval = 0.25f;
UPROPERTY(EditDefaultsOnly, Category = "AI", meta = (ClampMin = "0.0", Units = "cm"))
float AttackRange = 140.0f;
UPROPERTY(EditDefaultsOnly, Category = "AI", meta = (ClampMin = "0.1", Units = "s"))
float AttackCooldown = 1.0f;
private:
UPROPERTY()
TObjectPtr<APawn> TargetPawn;
FTimerHandle ThinkTimerHandle;
double LastAttackTime = -1000.0;
void Think();
파일 경로: Source/TopDownSurvival/Enemies/EnemyBase.cpp · AI 구현
#include "AIController.h"
#include "Data/EnemyDataAsset.h"
#include "Kismet/GameplayStatics.h"
#include "TimerManager.h"
void AEnemyBase::BeginPlay()
{
Super::BeginPlay();
TargetPawn = UGameplayStatics::GetPlayerPawn(this, 0);
GetWorldTimerManager().SetTimer(
ThinkTimerHandle, this, &AEnemyBase::Think, ThinkInterval, true);
}
void AEnemyBase::Think()
{
if (!IsValid(TargetPawn) || HealthComponent->IsDead())
{
return;
}
AAIController* AI = Cast<AAIController>(GetController());
if (!AI)
{
return;
}
const float Distance = FVector::Dist2D(
GetActorLocation(), TargetPawn->GetActorLocation());
if (Distance > AttackRange)
{
AI->MoveToActor(TargetPawn, AttackRange * 0.8f);
return;
}
AI->StopMovement();
const double Now = GetWorld()->GetTimeSeconds();
if (Now - LastAttackTime >= AttackCooldown)
{
const float Damage = EnemyData ? EnemyData->AttackDamage : 10.0f;
UGameplayStatics::ApplyDamage(TargetPawn, Damage, AI, this, nullptr);
LastAttackTime = Now;
}
}
void AEnemyBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
GetWorldTimerManager().ClearTimer(ThinkTimerHandle);
Super::EndPlay(EndPlayReason);
}
Unreal Editor
- 레벨 바닥을 덮는 NavMeshBoundsVolume을 배치합니다.
- P 키로 Navigation 영역을 표시해 이동 가능한 영역을 확인합니다.
- BP_EnemyBase의 Auto Possess AI가 Placed in World or Spawned인지 확인합니다.
- 장애물을 피해 플레이어 근처까지 오는지 테스트합니다.
5. 코드가 동작하는 이유
Timer는 목표 유효성, 거리와 쿨다운만 평가합니다. MoveToActor는 AIController와 Navigation System에 경로 이동을 요청하고 CharacterMovement가 실제 이동을 처리합니다. 공격 범위에서는 StopMovement 후 World 시간으로 쿨다운을 검사합니다.
6. 자주 하는 실수와 해결법
7. 직접 실습
8. 이해 점검 질문 3개
9. 핵심 요약
간단한 적 AI 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.