Unreal Project
Dodge
갠소롱
2025. 4. 16. 07:36
🎮 Unreal Engine: 캐릭터 회피(Dodge) 방향을 캐릭터 기준으로 처리하는 방법
게임에서 회피(Dodge)를 구현할 때, 단순히 입력 방향대로 움직이게 하면 자연스럽지 않을 수 있다.
특히, 카메라 기준 이동이 적용된 게임에서는 입력 방향과 캐릭터가 실제로 바라보는 방향이 다를 수 있기 때문이다.
이번 글에서는 Unreal Engine에서 "카메라 기준 입력 방향"을 이용해 캐릭터 기준 회피 방향을 판단하는 방식을 자세히 정리한다.
🧠 문제 상황 정리
- 카메라는 정면을 보고 있다.
- 플레이어는
D
키를 눌러 캐릭터를 오른쪽으로 이동시킨다. - 이때 캐릭터는 오른쪽을 바라보며 이동한다.
이 상태에서 대시(Dodge) 키를 누르면?
- 단순히
D
키(오른쪽 입력) 기준으로 판단하면, 캐릭터는 자신의 오른쪽(=카메라 기준 뒤쪽)으로 대시하게 된다. - 하지만 실제로는 캐릭터가 이미 오른쪽을 바라보고 있으므로, 캐릭터 기준 정면으로 대시하는 것이 더 자연스럽다.
🎯 즉, 입력은 "오른쪽"이지만, 캐릭터는 이미 그쪽을 "앞"으로 인식하고 있어야 한다!
🎥 기본 개념 정리
🎮 입력 벡터 (MovementVector
)
플레이어가 누르고 있는 방향키 (WASD 등)의 값이다.
보통 X = 좌우
, Y = 전후
로 구성되어 있으며, 카메라 기준으로 해석된다.
🎥 카메라 기준 방향
const FRotator YawRotation(0, ControlRot.Yaw, 0);
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
ControlRot.Yaw
는 카메라의 바라보는 방향(Yaw).ForwardDirection
: 카메라 기준 앞RightDirection
: 카메라 기준 오른쪽
🎯 카메라 기준 입력 → 대시 방향으로 변환
FVector DodgeDirection = ForwardDirection * MovementVector.Y + RightDirection * MovementVector.X;
이 계산을 통해, 플레이어 입력과 카메라 방향을 조합한 정확한 대시 벡터를 얻는다.
입력 | 이동 방향 |
---|---|
W | 앞 (Y=+1) |
D | 오른쪽 (X=+1) |
W + D | 앞 + 오른쪽 (대각선) |
🧭 캐릭터 기준 방향 판단
👉 캐릭터 기준 방향 벡터
FVector CharForward = ControlledCharacter->GetActorForwardVector();
FVector CharRight = ControlledCharacter->GetActorRightVector();
👉 Dot Product (내적)을 이용한 비교
float ForwardDot = FVector::DotProduct(DodgeDirNormalized, CharForward);
float RightDot = FVector::DotProduct(DodgeDirNormalized, CharRight);
DotProduct
값은 두 벡터가 얼마나 비슷한 방향인지 나타낸다.
입력 방향 | 캐릭터 방향 | Dot 결과 | 의미 |
---|---|---|---|
정면 | 정면 | 1 | 앞 |
정면 | 오른쪽 | 0 | 옆 |
정면 | 뒤 | -1 | 뒤 |
📦 최종 로직 요약
if (FMath::Abs(ForwardDot) > FMath::Abs(RightDot))
{
DirectionTagStr = ForwardDot > 0 ? TEXT("FW") : TEXT("BW");
}
else
{
DirectionTagStr = RightDot > 0 ? TEXT("R") : TEXT("L");
}
ForwardDot
가 더 크면: 앞/뒤 방향 대시RightDot
가 더 크면: 좌/우 방향 대시
✅ 전체 코드 예시
void AMyPlayerController::Dodge()
{
AMyCharacter* ControlledCharacter = Cast(GetPawn());
if (!IsValid(ControlledCharacter)) return;
FVector DodgeDirection = ControlledCharacter->GetActorForwardVector();
FRotator ControlRot = GetControlRotation();
FString DirectionTagStr = TEXT("None");
if (MovementVector.SizeSquared() > 0)
{
const FRotator YawRotation(0, ControlRot.Yaw, 0);
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
DodgeDirection = ForwardDirection * MovementVector.Y + RightDirection * MovementVector.X;
FVector DodgeDirNormalized = DodgeDirection.GetSafeNormal();
float ForwardDot = FVector::DotProduct(DodgeDirNormalized, ControlledCharacter->GetActorForwardVector());
float RightDot = FVector::DotProduct(DodgeDirNormalized, ControlledCharacter->GetActorRightVector());
if (FMath::Abs(ForwardDot) > FMath::Abs(RightDot))
{
DirectionTagStr = ForwardDot > 0 ? TEXT("FW") : TEXT("BW");
}
else
{
DirectionTagStr = RightDot > 0 ? TEXT("R") : TEXT("L");
}
}
else
{
DirectionTagStr = TEXT("FW");
}
FString FullTagName = FString::Printf(TEXT("Player.Utilities.Dodge.%s"), *DirectionTagStr);
FGameplayTag DodgeTag = FGameplayTag::RequestGameplayTag(FName(*FullTagName));
FGameplayTagContainer TagContainer;
TagContainer.AddTag(DodgeTag);
if (AbilitySystemComponent)
{
AbilitySystemComponent->TryActivateAbilitiesByTag(TagContainer);
}
}
📝 마무리
이처럼 카메라 기준 입력을 캐릭터 기준 방향으로 변환하면, 훨씬 더 직관적이고 자연스러운 회피 시스템을 만들 수 있다. 🎯