액터 배열과 정렬된 액터를 저장할 배열을 받은 뒤 이를 수정하는 함수를 구현해보려고 한다.
함수를 선언하자
UFUNCTION(BlueprintCallable)
static void GetClosestTargets(int32 MaxTargets, const TArray<AActor*>& Actors, TArray<AActor*>& OutClosestTargets, const FVector& Origin);
매개변수는 차례대로 최대 타겟 수, 비정렬된 액터 배열, 액터를 정렬 후 저장할 배열, 기준 위치이다.
이 함수에서의 핵심은 언리얼에서 자체적으로 제공해 주는 Algo 라이브러리를 이용할 것이라는 점이다. 물론 자체적으로 정렬 알고리즘을 만들어도 되겠지만 엔진에서 제공해주는 알고리즘은 일반적으로 가장 최적화된 알고리즘이기 때문에 따로 구현할 필요성이 낮다.
이제 함수를 구현하자. 가장 먼저 유효성 체크를 한다.
if (Actors.IsEmpty() || MaxTargets < 1) return;
다음은 특정 태그가 붙은 타겟을 다시 저장하는 부분인데, 만약 태그와 상관없이 모든 액터를 저장하고 싶으면 생략해도 된다.
여기서는 Enemy 타겟이 붙은 대상만 수집할 예정이다.
TArray<AActor*> SortedActors;
for (AActor* Actor : Actors)
{
if (Actor->ActorHasTag(FName("Enemy")))
{
SortedActors.AddUnique(Actor);
}
}
이제 언리얼에서 제공해 주는 Sort 함수를 이용해 배열을 정렬해 보자.
Algo::Sort(SortedActors, [Origin](const AActor* A, const AActor* B)
{
const float DistanceA = FVector::DistSquared(A->GetActorLocation(), Origin);
const float DistanceB = FVector::DistSquared(B->GetActorLocation(), Origin);
return DistanceA < DistanceB;
});
람다함수로 바인딩할 것이고 이때 원점이 저장되어 있는 Origin 매개변수를 캡처한다.
이제 원점과 A, B 액터의 거리를 구할 것인데 여기서의 핵심은 아래의 함수라고 할 수 있다.
FVector::DistSquared(A->GetActorLocation(), Origin);
DistSquared 함수는 두 지점 사이의 거리의 제곱값을 계산하는 함수이다. Dist 함수의 경우 정확한 거리를 알아내기 위하여 제곱근 계산을 하는데 (이는 백터 수학과 관련되어있다고 한다.) 이때 많은 비용이 든다. 하지만 단순히 거리 비교를 위해서는 이렇게 정확한 계산을 할 필요 없이 그저 상대적인 거리만 알면 된다. 그렇기 때문에 DistSquared 함수를 이용해서 거리를 비교하는 것이다.
거리 비교가 끝났으면 마지막으로 이를 배열에 저장하면 된다.
OutClosestTargets.Empty();
for (int32 i = 0; i < FMath::Min(MaxTargets, SortedActors.Num()); i++)
{
OutClosestTargets.AddUnique(SortedActors[i]);
}
전체 함수 구조는 아래와 같다.
void GetClosestTargets(int32 MaxTargets, const TArray<AActor*>& Actors,
TArray<AActor*>& OutClosestTargets, const FVector& Origin)
{
if (Actors.IsEmpty() || MaxTargets < 1) return;
TArray<AActor*> SortedActors;
for (AActor* Actor : Actors)
{
if (Actor->ActorHasTag(FName("Enemy")))
{
SortedActors.AddUnique(Actor);
}
}
Algo::Sort(SortedActors, [Origin](const AActor* A, const AActor* B)
{
const float DistanceA = FVector::DistSquared(A->GetActorLocation(), Origin);
const float DistanceB = FVector::DistSquared(B->GetActorLocation(), Origin);
return DistanceA < DistanceB;
});
OutClosestTargets.Empty();
for (int32 i = 0; i < FMath::Min(MaxTargets, SortedActors.Num()); i++)
{
OutClosestTargets.AddUnique(SortedActors[i]);
}
}
'게임프로그래밍 > 실습2' 카테고리의 다른 글
[실습2] MVVM 바인딩을 위한 FieldNotify 생성하기 (0) | 2025.01.11 |
---|---|
[실습2] 발사체 스프레드 코드 (0) | 2025.01.07 |
[실습2] 64. GAS 쿨다운 적용하기 (0) | 2025.01.01 |
[실습2] 63. 게임플레이어빌리티시스템 Cost 적용하기 (0) | 2025.01.01 |
[실습2] 62. 일정 범위 안에 있는 액터 배열에 담기 (0) | 2024.12.29 |