레이트레이스
타겟을 찾는 방식을 아래와 같이 단순화했다.
- 타게팅 버튼을 누르면 120도에 걸쳐 원뿔 모양으로 레이를 쏜다. 그 중 가장 가까운 타겟을 찾아 락온타겟으로 레퍼런스를 저장한다.
- 만약 타겟이 이미 있으면 타게팅을 그만한다.
언리얼에서는 Raytrace가 KismetSystemLibrary에 모여있다. 그냥 레이를 쓰면 운이 안좋으면 레이에 안맞을수도 있어서 Sphere모양으로 쏘게끔 했다.
void AMainCharacter::LockTarget()
{
if (bHasLockTarget == false)
{
// 120도의 부채꼴 모양으로 레이트레이싱을 실행한다.
FVector CameraForwardVector = GetFollowCamera()->GetForwardVector().RotateAngleAxis(15.f, FVector::LeftVector);
FVector LeftEndVector = CameraForwardVector.RotateAngleAxis(-60.f, FVector::UpVector);
TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypeToLock;
ObjectTypeToLock.Add(EObjectTypeQuery::ObjectTypeQuery3);
FCollisionQueryParams QueryParams(NAME_None);
TArray<AActor*> ActorsToNotTargeting;
ActorsToNotTargeting.Add(this);
FVector StartPoint = GetFollowCamera()->GetComponentLocation();
FHitResult HitResult;
float ClosestDist = TargetingRange;
AActor* ClosestHitActor = nullptr;
for (int i = 0; i < 120; i += 5)
{
FVector Direction = LeftEndVector.RotateAngleAxis(i, FVector::UpVector);
FVector EndPoint = StartPoint + Direction * TargetingRange;
bool bIsHit = UKismetSystemLibrary::SphereTraceSingleForObjects(
GetWorld(), StartPoint, EndPoint, 200.f,
ObjectTypeToLock, false, ActorsToNotTargeting, EDrawDebugTrace::ForDuration,
HitResult, true,
FLinearColor::Red, FLinearColor::Green, 2.f);
if (bIsHit && HitResult.Distance < ClosestDist)
{
ClosestDist = HitResult.Distance;
ClosestHitActor = HitResult.Actor.Get();
}
}
if (ClosestHitActor)
{
bHasLockTarget = true;
LockedOnTarget = ClosestHitActor;
}
}
else
{
bHasLockTarget = false;
LockedOnTarget = nullptr;
}
}
카메라 고정
카메라를 고정하는 코드는 좀더 복잡하다. 핵심은 카메라에서 타겟을 보기위한 Rotation을 구하고 이를 카메라 로테이션으로 바로 적용하는 것이다. 해당 함수는 Tick()에 있어서 타게팅 중이면 매 프레임마다 실행된다.
void AMainCharacter::LookAtTarget (float DeltaSeconds) const
{
FVector LockedOnLocation = LockedOnTarget->GetActorLocation();
LockedOnLocation.Z -= 150.f;
const FRotator LookAtRotation = UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), LockedOnLocation);
const FRotator InterpRotation = UKismetMathLibrary::RInterpTo(GetController()->GetControlRotation(), LookAtRotation, DeltaSeconds, 10.f);
GetController()->SetControlRotation(FRotator(InterpRotation.Pitch, InterpRotation.Yaw,GetController()->GetControlRotation().Roll));
}
결과
다음 목표
- strafe movement
'Coding > Devlog' 카테고리의 다른 글
#10 lock on일 때, strafe movement 구현 (0) | 2022.03.07 |
---|---|
#9 스프린트 계획 (0) | 2022.03.07 |
#7 기본 모드일 때, 회피 구현 (0) | 2022.03.03 |
#6 메인 캐릭터와 적 캐릭터의 죽음 구현 (0) | 2022.03.02 |
#5 플레이어 약공격 / 강공격 구현 (0) | 2022.03.01 |