#8 타게팅 시스템 구현
Coding/Devlog

#8 타게팅 시스템 구현

레이트레이스

타겟을 찾는 방식을 아래와 같이 단순화했다.

  • 타게팅 버튼을 누르면 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