세키로 혹은 엘든링게임에 존재하는 적을 타게팅 하는 기능을 만들어보았습니다
Q를 눌러서 적을 타겟하고 다시 Q를 누르면 타게팅이 해제됩니다
Q의 타게팅 조건은 이와 같습니다
1. 화면안에 적이 있을것
2. 플레이어와 적과의 거리가 일정거리 이하일때
3. 만약 두개다 할당되는경우 거리와 스크린범위 안에 있을때의 가중치가 더 높은경우
(스크린비중 3할 거리비중 7할)
void AMainCharacter::C_LockOn::FindNearestTarget()
{
//실제 3d world 거리 가중치
if (validTargets.Num() == 0)
{
currentTarget = nullptr;
return;
}
validTargets.Sort([this](AActor& A, AActor& B)
{
return GetDistanceToTarget(&A) < GetDistanceToTarget(&B);
});
currentTarget = validTargets[0];
APlayerController* pc = Cast<APlayerController>(rockOnOwner->GetInstigatorController());
if (!pc)
{
currentTarget = nullptr;
return;
}
//화면중앙 계산 가중치 계산
int32 viewportX, viewportY;
pc->GetViewportSize(viewportX, viewportY);
FVector2D viewportSize(viewportX, viewportY);
FVector2D centerScreen = viewportSize * 0.5f;
//3d거리 7할 스크린 3할
const float weightScreen = 0.3f;
const float weightWorld = 0.7f;
float bestScore = -FLT_MAX;
AActor* bestTarget = validTargets[0];
for (AActor* target : validTargets)
{
if (!target)
continue;
//가까울수록 1에수렴
float worldDist = GetDistanceToTarget(target);
float normWorld = 1.f / (worldDist + 1.f);
FVector2D screenPos;
pc->ProjectWorldLocationToScreen(target->GetActorLocation(), screenPos);
float screenDist = FVector2D::Distance(screenPos, centerScreen);
float normScreen = 1.f - FMath::Clamp(screenDist / (viewportSize.X * 0.5f), 0.f, 1.f);
//가중치로 최종스코어 계산
// 최종 점수 계산
// normWorld : 3D 실제 거리 기준 점수 (가까울수록 1, 멀수록 0)
// weightWorld: 거리 점수 중요도 비율
// normScreen : 화면 중앙 근접 기준 점수 (중앙에 가까울수록 1, 멀수록 0)
// weightScreen: 화면 중심 중요도 비율
// 최종 score : 거리와 화면 중심 점수를 가중합한 최종 우선순위 점수
float score = normWorld * weightWorld + normScreen * weightScreen;
if (score > bestScore)
{
bestScore = score;
bestTarget = target;
}
}
currentTarget = bestTarget;
}
가중치가 더 높은쪽으로 먼저 타게팅이 되는 형식으로 구현하였습니다
타게팅의 시스템은 캐릭터 내에서 Class 구조체로 설계하였으며 타게팅이 되는 적은
모든 액터를 검사하는게 아닌 "락온 대상 후보가 될 수 있는 클래스들의 목록" 을 제작후
그 클래스들만 락온 대상으로 간주합니다
AMainCharacter::C_LockOn::C_LockOn(AActor* rOwner)
{
rockOnOwner = rOwner;
currentTarget = nullptr;
lockOnClass =
{
//추가예정
F_LOCKTARGETINFO(AEnemyBaseCharacter::StaticClass())
};
}
타게팅이 된 적에게 시점 카메라가 고정되며 고정된 적에게 이미지가 출력됩니다
FVector spineLoc = FVector::ZeroVector;
USkeletalMeshComponent* meshComp = currentTarget->FindComponentByClass<USkeletalMeshComponent>();
if (meshComp)
{
spineLoc = meshComp->GetSocketLocation(FName("spine_02"));
}
FVector2D screenPos;
if (UGameplayStatics::ProjectWorldToScreen(pc, spineLoc, screenPos))
{
if (!selfCharacter->lockOnWidgetInstance && selfCharacter->lockOnWidgetClass)
{
selfCharacter->lockOnWidgetInstance = CreateWidget<ULockOnWidget>(
selfCharacter->GetWorld(), selfCharacter->lockOnWidgetClass
);
}
if (selfCharacter->lockOnWidgetInstance)
{
selfCharacter->lockOnWidgetInstance->SetAlignmentInViewport(FVector2D(0.5f, 0.5f));
selfCharacter->lockOnWidgetInstance->SetPositionInViewport(screenPos, true);
}
ShowLockOnWidget(true);
}
else
{
ShowLockOnWidget(false);
}
결과는 이와 같습니다
q를 누르면 조건이 만족되면 타게팅되어 적에게 시점이 고정됩니다

'Unreal 프로젝트 다이어리 > 두번째 프로젝트' 카테고리의 다른 글
| Unreal - CSV 데이터 테이블 만들기 (0) | 2025.10.29 |
|---|---|
| Unreal - 파쿠르 방해물 탐색 (0) | 2025.10.29 |
| Unreal - 캐릭터 회전 (0) | 2025.10.19 |
| Unreal - Posture Progress / Hit Direction (0) | 2025.08.29 |
| Unreal - HitInterface 상호작용 (0) | 2025.08.23 |