본문으로 건너뛰기
게임 수학 · 게임 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 미완료 상태