깃허브 주소
https://github.com/OneStone3647/ProjectT
PTTargetAimSystemComponent
PTTargetingSystemComponent에서 Target을 지정하기 위해 SweepMutliBuChannel에 Targeting Trace Channel에 블록되는 Target Collision Preset인 SphereComponent입니다.
Target으로 지정되면 LockOn 되었다는 것을 나타내는 Widget을 활성화합니다.
PTTargetingSystemComponent
일정 범위안에서 화면에 존재하는 PTTargeAimSystemComponent를 가진 캐릭터를 탐색하여 화면의 중앙에 가장 가까이 존재하는 캐릭터를 Target으로 지정하여 플레이어의 카메라를 Target을 향하도록 고정하는 ActorComponent입니다.
카메라의 좌우 조작으로 현재 Target으로 지정된 캐릭터를 기준으로 좌우에 존재하는 Target으로 지정할 수 있는 캐릭터를 좌측에 있는지 우측에 있는지 2개의 배열로 구분하여 저장합니다. 두 벡터 사이의 각이 작을수록 두 벡터의 내적 값이 크기 때문에 카메라의 조작에 해당하는 방향의 배열에 들어 있는 캐릭터들 중 내적이 가장 큰 캐릭터(Target을 기준으로 카메라를 조작하는 방향에 위치하는 Target에게 가장 가까운 캐릭터)를 Target으로 지정합니다.
만약 카메라 진행 방향에 Target으로 지정할 수 있는 캐릭터가 없는 경우 카메라 진행 방향의 반대 방향에 존재하는 Target으로 지정할 수 있는 캐릭터 중 내적이 가장 작은 캐릭터(Target으로부터 가장 멀리 있는 캐릭터)를 Target으로 지정합니다.
AActor* UPTTargetingSystemComponent::FindDirectionalTarget(EPTTargetDirection NewTargetDirection)
{
AActor* NewTarget = nullptr;
TArray<AActor*> TargetableActors = SearchTargetableActors();
const int32 CurrentTargetIndex = TargetableActors.Find(Target);
// 현재 Target이 TargetableActors 배열에 존재할 경우 배열에서 제거합니다.
if(CurrentTargetIndex != INDEX_NONE)
{
TargetableActors.Remove(Target);
}
// 현재 Target을 기준으로 좌우에 있는 Target을 탐색합니다.
TArray<AActor*> LeftTargetableActors;
TArray<AActor*> RightTargetableActors;
for(AActor* TargetableActor : TargetableActors)
{
APTDummyCharacter* TargetablePRAICharacter = Cast<APTDummyCharacter>(TargetableActor);
if(IsValid(TargetablePRAICharacter) == true && TargetablePRAICharacter->IsDead() == false)
{
switch(WhichSideOfTarget(TargetablePRAICharacter))
{
case EPTTargetDirection::TargetDirection_Left:
LeftTargetableActors.AddUnique(TargetablePRAICharacter);
break;
case EPTTargetDirection::TargetDirection_Right:
RightTargetableActors.AddUnique(TargetablePRAICharacter);
break;
default:
break;
}
}
}
// 두 벡터의 각이 클수록 두 벡터의 내각은 작습니다.
switch(NewTargetDirection)
{
case EPTTargetDirection::TargetDirection_Left:
if(LeftTargetableActors.Num() > 0)
{
// 왼쪽에서 내적이 가장 큰 Target
NewTarget = GetTargetByDotProduct(LeftTargetableActors, true);
}
else
{
// 오른쪽에서 내적이 가장 작은 Target
NewTarget = GetTargetByDotProduct(RightTargetableActors, false);
}
break;
case EPTTargetDirection::TargetDirection_Right:
if(RightTargetableActors.Num() > 0)
{
// 오른쪽에서 내적이 가장 큰 Target
NewTarget = GetTargetByDotProduct(RightTargetableActors, true);
}
else
{
// 왼쪽에서 내적이 가장 작은 Target
NewTarget = GetTargetByDotProduct(LeftTargetableActors, false);
}
break;
default:
break;
}
if(IsValid(NewTarget) == true)
{
return NewTarget;
}
return nullptr;
}
AActor* UPTTargetingSystemComponent::GetTargetByDotProduct(TArray<AActor*> TargetableActors, bool bIsLargestDot)
{
float DotProduct = 0.0f;
AActor* NewTarget = nullptr;
int32 ArrayIndex = 0;
if(TargetableActors.Num() == 0)
{
return nullptr;
}
for(AActor* TargetableActor : TargetableActors)
{
if(ArrayIndex == 0)
{
DotProduct = CalculateDotProductToTarget(TargetableActor);
NewTarget = TargetableActor;
}
else
{
if(bIsLargestDot)
{
if(CalculateDotProductToTarget(TargetableActor) > DotProduct)
{
DotProduct = CalculateDotProductToTarget(TargetableActor);
NewTarget = TargetableActor;
}
}
else
{
if(CalculateDotProductToTarget(TargetableActor) < DotProduct)
{
DotProduct = CalculateDotProductToTarget(TargetableActor);
NewTarget = TargetableActor;
}
}
}
ArrayIndex++;
}
return NewTarget;
}
LockOn중인 Target과 일정거리 멀어지게 되면 LockOn을 해제합니다.
LockOn중인 Target이 사망하게 되면 가장 가까운 곳에 있는 Target으로 지정이 가능한 캐릭터를 Target으로 지정하고 LockOn합니다.
'Project > T' 카테고리의 다른 글
[Project T] Unreal Targeting System / 언리얼 타겟팅 시스템 v1.2.0 (0) | 2022.08.10 |
---|---|
[Project T] Unreal Targeting System / 언리얼 타겟팅 시스템 v1.1.0 (0) | 2022.07.27 |
Unreal TargetLock System Prototype / 언리얼 타겟락 시스템 프로토타입 (0) | 2020.09.19 |