본문으로 건너뛰기
게임 수학 · 게임 AI 기초집LESSON 20

공격 AI

난이도초급
예상 시간55분
선수지식19강의 추적 AI

20강. 공격 AI

1. 이번 강의에서 해결할 문제

공격 Task가 반복 실행될 때 한 프레임에 여러 번 피해가 들어가고, 벽이나 공격 거리 밖에서도 공격합니다. 판단 조건과 공격 실행 안전장치를 양쪽 책임에 맞게 둡니다.

2. 학습 목표

3. 핵심 개념

공격 가능 조건은 “Target 유효 + 공격 거리 + 시야 확보 + 쿨다운 준비”입니다. AIController는 감지 정보로 조건을 판단하고 Character는 공격 애니메이션·Trace·Damage 실행과 쿨다운을 담당합니다.

Timer는 일정 시간 뒤 공격 준비 상태를 복구합니다. BT Task가 자주 재실행돼도 Character의 bAttackReady가 마지막 안전장치가 됩니다.

4. 단계별 실습

C++ · 파일 경로: Source/TopDownSurvival/AI/MathAIController.h · 공격 검사

MathAIController.h · 추가
public:
bool CanAttackTarget(AActor* Target) const;
MathAIController.cpp · 공격 조건
#include "AI/GameMathLibrary.h"

bool AMathAIController::CanAttackTarget(AActor* Target) const
{
const APawn* Enemy = GetPawn();
if (!Enemy || !IsValid(Target))
{
return false;
}

return UGameMathLibrary::IsWithinRange2D(
Enemy->GetActorLocation(),
Target->GetActorLocation(),
AttackDistance) &&
HasClearSight(Target);
}

C++ · 파일 경로: Source/TopDownSurvival/Enemies/MathAIEnemyCharacter.h · 공격

MathAIEnemyCharacter.h · 추가
public:
bool TryAttack(AActor* Target);

protected:
UPROPERTY(EditDefaultsOnly, Category = "AI|Combat")
float AttackDamage = 10.0f;

UPROPERTY(EditDefaultsOnly, Category = "AI|Combat")
float AttackCooldown = 1.2f;

private:
bool bAttackReady = true;
FTimerHandle AttackCooldownHandle;
void ResetAttackCooldown();

C++ · 파일 경로: Source/TopDownSurvival/Enemies/MathAIEnemyCharacter.cpp

MathAIEnemyCharacter.cpp · TryAttack
#include "Kismet/GameplayStatics.h"
#include "TimerManager.h"

bool AMathAIEnemyCharacter::TryAttack(AActor* Target)
{
if (!bAttackReady || !IsValid(Target))
{
return false;
}

bAttackReady = false;
UGameplayStatics::ApplyDamage(
Target, AttackDamage, GetController(), this, nullptr);

GetWorldTimerManager().SetTimer(
AttackCooldownHandle,
this,
&AMathAIEnemyCharacter::ResetAttackCooldown,
FMath::Max(0.1f, AttackCooldown),
false);
return true;
}

void AMathAIEnemyCharacter::ResetAttackCooldown()
{
bAttackReady = true;
}

실제 근접 판정을 강화하려면 10강 Line Trace 또는 Unreal C++ 과정의 Sphere Trace를 공격 순간에 사용해 Target이 실제로 맞았는지 다시 확인합니다.

C++ · 파일 경로: Source/TopDownSurvival/AI/Tasks/BTTask_AttackTarget.h

BTTask_AttackTarget.h
#pragma once

#include "CoreMinimal.h"
#include "BehaviorTree/BTTaskNode.h"
#include "BTTask_AttackTarget.generated.h"

UCLASS()
class TOPDOWNSURVIVAL_API UBTTask_AttackTarget : public UBTTaskNode
{
GENERATED_BODY()

protected:
virtual EBTNodeResult::Type ExecuteTask(
UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;

UPROPERTY(EditAnywhere, Category = "Blackboard")
FBlackboardKeySelector TargetActorKey;
};

C++ · 파일 경로: Source/TopDownSurvival/AI/Tasks/BTTask_AttackTarget.cpp

BTTask_AttackTarget.cpp · ExecuteTask
#include "AI/Tasks/BTTask_AttackTarget.h"

#include "AI/MathAIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Enemies/MathAIEnemyCharacter.h"

EBTNodeResult::Type UBTTask_AttackTarget::ExecuteTask(
UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
AMathAIController* Controller =
Cast<AMathAIController>(OwnerComp.GetAIOwner());
AMathAIEnemyCharacter* Enemy =
Controller ? Cast<AMathAIEnemyCharacter>(Controller->GetPawn()) : nullptr;
AActor* Target = Cast<AActor>(
OwnerComp.GetBlackboardComponent()->GetValueAsObject(TargetActorKey.SelectedKeyName));

if (!Controller || !Enemy || !Controller->CanAttackTarget(Target))
{
return EBTNodeResult::Failed;
}

return Enemy->TryAttack(Target)
? EBTNodeResult::Succeeded
: EBTNodeResult::Failed;
}

Attack Branch Decorator에 AIState == Attack을 두고 Observer Aborts를 Self로 설정합니다.

5. 코드와 수학·AI가 동작하는 이유

Controller가 최신 거리·시야 조건을 검증해 벽 뒤나 범위 밖 공격을 막고 Character가 쿨다운 상태를 소유합니다. Timer가 bAttackReady를 복구하므로 Task 호출 빈도와 실제 공격 빈도가 분리됩니다.

6. 자주 하는 실수와 해결법

7. 직접 실습

8. 이해 점검 질문 3개

9. 핵심 요약

MINI QUIZ

공격 AI 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“공격 AI” 작업 전 검토에서 채택해야 할 안전 기준은 무엇인가요?
  2. 문제 2“공격 AI”에서 ‘Task 실행마다 즉시 Damage’ 문제가 생겼습니다. 가장 알맞은 진단 또는 대응은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

20강. 공격 AI 미완료 상태