쾌락없는 책임 (공부)/Unreal
[Unreal] 액터가 volume 안에 있는지 확인하기
허스크
2024. 4. 20. 10:16
반응형
개요
마을의 '영역'을 만들게 되면서 해당 영역에 Enter 하게 되면 플레이어가 해당 영역에 있다는걸 나타낼 예정입니다. 그런데 문제는 플레이어가 마을에서 스폰하게 되는 경우입니다. 이 경우에는 BeginPlay 시점에 Overlap 이벤트가 자동적으로 불리게 되지 않아 문제가 됩니다.
이를 해결하기 위해 BeginPlay 시점에 특정 액터가 안에 있음을 알게 하는 방법 2개를 알아보도록 하겠습니다.
bGenerateOverlapEventsDuringLevelStreaming
위 변수 딸깍이면 레벨이 로드되는 중에도 Overlap 이벤트를 발생시킬 수 있게 됩니다.

에디터에서 위 옵션을 체크하거나 생성자에서 true 로 설정해주면 됩니다.
void UPrimitiveComponent::BeginComponentOverlap(const FOverlapInfo& OtherOverlap, bool bDoNotifies)
{
// ...
const bool bComponentsAlreadyTouching = (IndexOfOverlapFast(OverlappingComponents, OtherOverlap) != INDEX_NONE);
if (!bComponentsAlreadyTouching)
{
UPrimitiveComponent* OtherComp = OtherOverlap.OverlapInfo.Component.Get();
if (CanComponentsGenerateOverlap(this, OtherComp))
{
//....
// 여기서 해당 옵션이 켜져 있는지를 검사
const bool bLevelStreamingOverlap = (bDoNotifies && MyActor->bGenerateOverlapEventsDuringLevelStreaming && MyActor->IsActorBeginningPlayFromLevelStreaming());
if (bDoNotifies && ((World && World->HasBegunPlay()) || bLevelStreamingOverlap))
{
// first execute component delegates
if (IsValid(this))
{
// 이곳에서 이벤트를 부르게 됩니다.
OnComponentBeginOverlap.Broadcast(this, OtherActor, OtherComp, OtherOverlap.GetBodyIndex(), OtherOverlap.bFromSweep, OtherOverlap.OverlapInfo);
}
위 변수의 사용처는 PrimitiveComponent 의 BeginComponentOverlap입니다.(End 역시 동일)
해당 옵션이 켜져 있다면 HasBegunPlay 상태가 아니라 하더라도 이벤트를 호출하게 되는것을 알 수 있습니다. 이러면 추가적인 로직 없이 변수 딸깍으로 설정할 수 있게 되는 것입니다.
AVolume::EncompassesPoint
만일 Overlap 이벤트가 너무 많은 비용을 차지할 것 같다면 해당 함수를 고려해볼 수 있습니다. 이 함수는 특정 3D 좌표의 점이 Volume 안에 있는지를 파악해주는 검사로
if(PlayerPawn != nullptr && EncompassesPoint(PlayerPawn->GetActorLocation()))
{
UE_LOG(LogTemp, Warning, TEXT("*** *** *** overlap player encompasses"));
}
위와 같은 방식으로 사용하면 됩니다.
bool AVolume::EncompassesPoint(FVector Point, float SphereRadius/*=0.f*/, float* OutDistanceToPoint) const
{
if (GetBrushComponent())
{
#if 1
FVector ClosestPoint;
float DistanceSqr;
if (GetBrushComponent()->GetSquaredDistanceToCollision(Point, DistanceSqr, ClosestPoint) == false)
{
if (OutDistanceToPoint)
{
*OutDistanceToPoint = -1.f;
}
return false;
}
#else
FBoxSphereBounds Bounds = GetBrushComponent()->CalcBounds(GetBrushComponent()->GetComponentTransform());
const float DistanceSqr = Bounds.GetBox().ComputeSquaredDistanceToPoint(Point);
#endif
if (OutDistanceToPoint)
{
*OutDistanceToPoint = FMath::Sqrt(DistanceSqr);
}
return DistanceSqr >= 0.f && DistanceSqr <= FMath::Square(SphereRadius);
}
else
{
UE_LOG(LogVolume, Log, TEXT("AVolume::EncompassesPoint : No BrushComponent"));
return false;
}
}
위 함수의 구현을 보면 BrushComponent를 기반으로 동작하는걸 알 수 있습니다.
- GetSquaredDistanceToCollision 에서 가장 가까운 거리를 구함
- 만일 return 이 false 라면 가장 가까운 거리가 발견되지 않은 것이라 return
- OutDistanceToPoint로 거리 계산
- 이후 검사 결과와 거리 안에 들어와 있는지를 검사
이를 통해 따로 Overlap 이벤트를 기대하지 않아도 검사가 가능하게 됩니다.
반응형