기존엔 우클릭 시 어깨 너머로 확대시키던 로직이었는데, 1인칭으로 시점 변환하도록 만들어보고 싶어서 구현해봤다. 현재는 카메라 보간이 적용되지 않은 상태다.
fpsCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("fpsCamera"));
fpsCamera->SetupAttachment(GetMesh(), FName("head"));
fpsCamera->bUsePawnControlRotation = true; // 1인칭이 되면 카메라 따라 캐릭터가 회전해야 함
fpsCamera->SetRelativeRotation(FRotator{ 0.f, 90.f, -90.f });
fpsCamera->SetRelativeLocation(FVector{ 3.f, 12.f, 0.f });
우선 위처럼 fpsCamera를 선언하고, 캐릭터 Mesh의 Bone 중 head라는 이름을 가진 소켓에 붙인 뒤 위치를 조금 조정해줬다.
그럼 이렇게 잘 붙는다.
void AMainCharacter::Aim()
{
if (bAiming)
StopAiming();
else
Aiming();
}
void AMainCharacter::Aiming()
{
if (!HUD->bIsInventoryVisible)
{
bAiming = true;
bUseControllerRotationYaw = true;
GetCharacterMovement()->MaxWalkSpeed = PlayerStatComponent->GetAimingWalkSpeed();
fpsCamera->Activate();
tpsCamera->Deactivate();
InterpolateCameraRotation(tpsCamera, fpsCamera);
}
}
void AMainCharacter::StopAiming()
{
bAiming = false;
if (!bWeaponEquip)
bUseControllerRotationYaw = false;
GetCharacterMovement()->MaxWalkSpeed = PlayerStatComponent->GetWalkSpeed();
tpsCamera->Activate();
fpsCamera->Deactivate();
InterpolateCameraRotation(fpsCamera, tpsCamera);
}
그 다음 우클릭 시 Aim()을 실행하도록 할당, 현 상태에 따라 Aiming()과 StopAiming()을 번갈아 실행한다.
가장 아래 InterpoalteCameraRotation이 이번 글 주인공인 카메라 보간이다.
void AMainCharacter::InterpolateCameraRotation(UCameraComponent* FromCamera, UCameraComponent* ToCamera)
{
FVector TraceStart{ FVector::ZeroVector };
FVector TraceEnd{ FVector::ZeroVector };
float Distance = 1000.f;
TraceStart = FromCamera->GetComponentLocation();
TraceEnd = { TraceStart + (FromCamera->GetComponentRotation().Vector() * Distance) };
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(this);
FHitResult TraceHit;
if (GetWorld()->LineTraceSingleByChannel(TraceHit, TraceStart, TraceEnd, ECC_Visibility, QueryParams))
{
// 스칼라곱을 이용한 카메라 보간 정도 구하기
FVector Direction = (TraceHit.ImpactPoint - ToCamera->GetComponentLocation());
FRotator NewRotation = Direction.Rotation();
Controller->SetControlRotation(NewRotation);
}
else
{
// 카메라 보간 필요 없는 경우
return;
}
}
LineTrace로 현재 바라보고 있는 위치의 Vector값을 구하고, 스칼라곱을 이용해 Rotation을 구해준다.
V = B - A 이므로, TraceHit.ImpactPoint - ToCamera->GetComponentLocation() 라는 식이 나온다.
최종적으로 V에서 Rotation을 얻어내 Controller의 Rotation을 조정해준다.
3인칭으로 돌아올 때 유격이 있다. 캐릭터를 움직여 측면이나 후면을 바라보게 한 뒤 1인칭으로 전환할 때도 유격이 존재한다.
이유는 정확히 모르겠지만 Camera로 얻은 Rotation과 Controller가 필요로 하는 Rotation이 살짝 달라서 그런 게 아닌가 추측해본다.
그래도 이 정도의 유격이라면 실제 게임이라 가정했을 때 플레이에 큰 지장은 없을 것 같다.
사실 TimelineCurve를 이용해 자연스럽게 전환되는 걸 만들어보려고 했는데, 방법을 찾지 못 해 이런 식의 전환으로 구현했다. 공부가 더 필요할 듯 싶다.