
이제 단일 지점으로의 Patrol은 가능한 것을 볼 수 있다. 이제 한 Patrol Point에서 다른 Patrol Point로 이동할 수 있도록 구현해보자.
이를 위해 타켓포인트를 여러개 만들어주고 배열에 할당해주자

그리고 Tick함수에서 Target과의 거리를 측정해주는 함수가 작동할 수 있도록 Actor와의 지정해준 거리에 따라 bool값을 반환해주는 새로운 함수를 만들어주자.
Enemy.cpp
bool AEnemy::InTargetRange(AActor* Target, double Radius)
{
const double DistanceToTarget = (Target->GetActorLocation() - GetActorLocation()).Size();
return DistanceToTarget <= Radius;
}
이를 바탕으로 Tick함수에서 HealthBar 조건문도 변경해주고 PatrolTarget조건문도 만들어주자.
이때 PatrolRadius(멈출 거리)를 지정해주어야하는데 이 값이 double인데 moveTo에서는 이 반경보다 조금 더 이동하기 때문에 조금 더 거리를 지정해주어야한다.
Enemy.h
UPROPERTY(EditAnywhere)
double PatrolRadius = 200.f;
Enemy.cpp
void AEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (CombatTarget)
{
if (!InTargetRange(CombatTarget,CombatRadius))
{
CombatTarget = nullptr;
if (HealthBarWidget)
{
HealthBarWidget->SetVisibility(false);
Attributes->SetHealth(100.f);
}
}
}
if (PatrolTarget && EnemyController)
{
TArray<AActor*> ValidTargets;
for (AActor* Target : PatrolTargets)
{
if (Target != PatrolTarget)
{
ValidTargets.AddUnique(Target);
}
}
if (InTargetRange(PatrolTarget, PatrolRadius))
{
const int32 TargetSelection = FMath::RandRange(0, ValidTargets.Num() - 1);
PatrolTarget = ValidTargets[TargetSelection];
FAIMoveRequest MoveRequest;
MoveRequest.SetGoalActor(PatrolTarget);
//도착이라고 생각할 거리
MoveRequest.SetAcceptanceRadius(15.f);
EnemyController->MoveTo(MoveRequest);
}
}
}
이렇게 해주고 실행해주면 랜덤한 순찰포인트로 순찰하는 것을 볼 수 있다.


하지만 지금은 순찰 포인트로 이동하고 바로 다른 포인트로 이동하는데 이것을 조금 기다렸다가 다른 순찰포인트로 이동하도록 구현해보자.
이를 위해 FTimerHandle 구조체 변수를 선언해주자. 이 구조체 변수는 일정 시간이 지난후 호출될 콜백함수가 필요하기 때문에 함수도 같이 선언해주자.
Enemy.h
private:
FTimerHandle PatrolTimer;
void PatrolTimerFinished();
Enemy.cpp
void AEnemy::PatrolTimerFinished()
{
MoveToTarget(PatrolTarget);
}
이렇게 콜백함수를 만들어준 다음 기능별로 나눌 수 있는것은 나눠주자.
Enemy.cpp
bool AEnemy::InTargetRange(AActor* Target, double Radius)
{
if (Target == nullptr) return false;
const double DistanceToTarget = (Target->GetActorLocation() - GetActorLocation()).Size();
DRAW_SPHERE_SingleFrame(GetActorLocation());
DRAW_SPHERE_SingleFrame(Target->GetActorLocation());
return DistanceToTarget <= Radius;
}
void AEnemy::MoveToTarget(AActor* Target)
{
if (EnemyController == nullptr || Target == nullptr) return;
FAIMoveRequest MoveRequest;
MoveRequest.SetGoalActor(Target);
//도착이라고 생각할 거리
MoveRequest.SetAcceptanceRadius(15.f);
EnemyController->MoveTo(MoveRequest);
}
AActor* AEnemy::ChoosePatrolTarget()
{
TArray<AActor*> ValidTargets;
for (AActor* Target : PatrolTargets)
{
if (Target != PatrolTarget)
{
ValidTargets.AddUnique(Target);
}
}
if (ValidTargets.Num() > 0)
{
const int32 TargetSelection = FMath::RandRange(0, ValidTargets.Num() - 1);
return ValidTargets[TargetSelection];
}
return nullptr;
}
만약 타켓이 거리안에 있다면 5초를 대기한 다음 이동하게 해주자 이때 GetWorldTimerManager의 SetTimer 기능을 활용하면 된다.
Enemy.cpp
void AEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (InTargetRange(PatrolTarget, PatrolRadius))
{
PatrolTarget = ChoosePatrolTarget();
GetWorldTimerManager().SetTimer(PatrolTimer, this, &AEnemy::PatrolTimerFinished, 5.f);
}
}
이렇게 해주면 5초를 대기한 다음 다음 순찰포인트로 이동한다.

'게임공부 > Unreal Engine' 카테고리의 다른 글
[Unreal Engine][C++]26. Patrol2 (0) | 2025.02.10 |
---|---|
[Unreal Engine][C++]24. Enemey Behavior2 (0) | 2025.02.05 |
[Unreal Engine][C++]23. Enemey Behavior (0) | 2025.01.27 |
[Unreal Engine][C++]22. Death (1) | 2025.01.26 |
[Unreal Engine][C++]21. Damage (1) | 2025.01.21 |