0. 개요

마우스로 가리킨 대상이 적 or 적이 아닌 액터일 때의 행동을 다르게 하도록 타겟팅 상태를 정의한다.

 

 

1. 타겟팅 상태(Targeting Status)

적이 아닌 대상으로 하이라이팅하는 기술은 구현했으나, 해당 대상을 클릭하면 여전히 왼쪽 클릭에 해당하는 어빌리티가 실행되고 있다.

이를 타겟팅 상태를 도입하여 해결할 것이다.

 

 

(1) AuraPlayerController에 ETargetingStatus 열거형 선언

enum ETargetingStatus
{
	TargetingEnemy,
	TargetingNonEnemy,
	None,
};

적, 적이 아닌 대상, 타겟팅 안 함의 상태를 갖는 열거형을 선언한다.

 

 

(2) 기존의 bTargeting 불리언을 대체하는 TargetingStatus

	/* 클릭으로 이동 */
	FVector CachedDestination = FVector::ZeroVector;
	float FollowTime = 0.f;
	float ShortPressThresold = 0.5f;
	bool bAutoRunning = false;
	ETargetingStatus TargetingStatus = None;

 

 

(3) CursorTrace 함수 수정

이제 ThisActor와 LastActor를 액터 포인터로 사용할 것이다.

void AAuraPlayerController::CursorTrace()
{
    // 입력 상태 태그 확인
    if (GetASC() && GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_CursorTrace))
    {
        // 하이라이트 해제
        if (LastActor)
            IHighlightInterface::Execute_HighlightActor(LastActor);

        if (ThisActor)
            IHighlightInterface::Execute_UnHighlightActor(ThisActor);

        LastActor = nullptr;
        ThisActor = nullptr;

        return;
    }
    if (LastActor != ThisActor)
    {
        if (LastActor)
            IHighlightInterface::Execute_UnHighlightActor(LastActor);

        if (ThisActor)
            IHighlightInterface::Execute_HighlightActor(ThisActor);
    }

 

 

(3-1) 액터가 유효하고 하이라이트 인터페이스를 구현했는지 확인하는 함수

void AAuraPlayerController::HighlightActor(AActor* InActor)
{
    if (IsValid(InActor) && InActor->Implements<UHighlightInterface>())
    {
        IHighlightInterface::Execute_HighlightActor(InActor);
    }
}

void AAuraPlayerController::UnHighlightActor(AActor* InActor)
{
    if (IsValid(InActor) && InActor->Implements<UHighlightInterface>())
    {
        IHighlightInterface::Execute_UnHighlightActor(InActor);
    }
}

액터가 유효하고 하이라이트 인터페이스를 구현했다면, 대상의 외곽선을 그리거나 지우는 함수들이다.

 

 

(3-2) CursorTrace 리펙토링

void AAuraPlayerController::CursorTrace()
{
    // 입력 상태 태그 확인
    if (GetASC() && GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_CursorTrace))
    {
        UnHighlightActor(LastActor);
        UnHighlightActor(ThisActor);
        if (IsValid(ThisActor) && ThisActor->Implements<UHighlightInterface>())
        {
            LastActor = nullptr;
            ThisActor = nullptr;
            return;
        }
    }

    // 트레이스 채널, 단순 충돌 확인, 반환되는 FHitResult 구조체의 주소
    ECollisionChannel TraceChannel = IsValid(MagicCircle) ? ECC_ExcludePlayers : ECollisionChannel::ECC_Visibility;

    GetHitResultUnderCursor(TraceChannel, false, CursorHit);

    if (!CursorHit.bBlockingHit)
        return;

    // 데칼 표시 중 리턴
    if (IsValid(MagicCircle))
    {
        LastActor = nullptr;
        ThisActor = nullptr;
        return;
    }

    LastActor = ThisActor;
    // 마우스 커서와 충돌한 액터 꺼내오기
    if (IsValid(CursorHit.GetActor()) && CursorHit.GetActor()->Implements<UHighlightInterface>())
    {
        ThisActor = CursorHit.GetActor();
    }
    else
    {
        ThisActor = nullptr;
    }

    if (LastActor != ThisActor)
    {
        UnHighlightActor(LastActor);
        HighlightActor(ThisActor);
    }
}

 

 

(3-3) 어빌리티 입력 함수들 수정

기존의 bTargeting 변수를 사용했던 함수들을 수정하여 타겟팅 상태에 따라 작동하도록 변경한다.

 

(3-3-1) 어빌리티 입력 누름

void AAuraPlayerController::AbilityInputTagPressed(FGameplayTag InputTag)
{
    // 입력 상태 태그 확인
    if (GetASC() && GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_InputPressed))
    {
        return;
    }

    if (InputTag.MatchesTagExact(FAuraGameplayTags::Get().InputTag_LMB))
    {
        // ThisActor에 따라 타겟팅 상태 전환
        TargetingStatus = ThisActor->Implements<UEnemyInterface>() ? TargetingEnemy : TargetingNonEnemy;
        bAutoRunning = false;
    }

 

 

(3-3-2) 어빌리티 입력 뗌

void AAuraPlayerController::AbilityInputTagReleased(FGameplayTag InputTag)
{
    // 입력 상태 태그 확인
    if (GetASC() && GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_InputReleased))
    {
        return;
    }
    // 타겟이 없고 쉬프트키가 눌리지 않았다면
    if (TargetingStatus != TargetingEnemy && !bShiftKeyDown)
    {
        // 경계값보다 짧게 눌렀으면 목적지로 길 찾기 시작
        FollowTime = 0.f;
        TargetingStatus = None;
    }
}

 

 

(3-3-3) 어빌리티 입력 누르고 있음

void AAuraPlayerController::AbilityInputTagHeld(FGameplayTag InputTag)
{
    // 입력 상태 태그 확인
    // 타겟
    if (TargetingStatus == TargetingEnemy || bShiftKeyDown)
    {

 


- 열거형의 값을 알기 어려운 경우 열거형 클래스를 활용한다.

enum class ETargetingStatus : uint8
{
	TargetingEnemy,
	TargetingNonEnemy,
	None
};

타겟팅 상태를 열거형이 아닌 열거형 클래스로 지정하면, if 체크 시 더 편하게 사용할 수 있다.

    // 타겟
    if (TargetingStatus == ETargetingStatus::TargetingEnemy || bShiftKeyDown)
    {

 

2. 디버그

(1) 바닥을 클릭하면 이동하지 않고 공격함

void AAuraPlayerController::AbilityInputTagPressed(FGameplayTag InputTag)
{
    // 입력 상태 태그 확인
    if (GetASC() && GetASC()->HasMatchingGameplayTag(FAuraGameplayTags::Get().Player_Block_InputPressed))
    {
        return;
    }

    if (InputTag.MatchesTagExact(FAuraGameplayTags::Get().InputTag_LMB))
    {
        if (IsValid(ThisActor))
        {
            // ThisActor에 따라 타겟팅 상태 전환
            TargetingStatus = ThisActor->Implements<UEnemyInterface>() ? ETargetingStatus::TargetingEnemy : ETargetingStatus::TargetingNonEnemy;
            bAutoRunning = false;
        }
        else
        {
            TargetingStatus = ETargetingStatus::None;
        }
    }

타겟팅 상태를 수정한다.