I have a UAbilityComponent
class which also handles setting the visual indicator and there will be subclasses that inherit from it (might be BP or C++). My reasoning was trying to keep my classes as modular as possible.
UInputAction* UAbilityComponent::GetSetDestinationInputAction() const
{
return SetDestinationInputAction;
}
void UAbilityComponent::SetSetDestinationInputAction(UInputAction* NewSetDestinationInputAction)
{
SetDestinationInputAction = NewSetDestinationInputAction;
}
// Run the timer to call OnDecision() to check whether the button has been clicked to place the indicator, or keeps moving indicator in certain range via mouse movement
void UAbilityComponent::SetTimerOnDecision()
{
if (GetWorld())
GetWorld()->GetTimerManager().SetTimer(DecisionTimerHandle, this, &UAbilityComponent::OnDecision, 0.35f, true, 0);
}
void UAbilityComponent::OnDecision()
{
if (SetDestinationInputAction == nullptr) {
if (GetWorld())
GetWorld()->GetTimerManager().ClearTimer(DecisionTimerHandle);
return;
}
bool Get_IA_Destination = true;
if (Get_IA_Destination)
{
if (GetWorld())
GetWorld()->GetTimerManager().ClearTimer(DecisionTimerHandle);
SetTargetPosition(GetPlayerCursorLocation());
}
else
{
SetIndicatorDecalAtLocation();
}
}
FVector UAbilityComponent::GetPlayerCursorLocation() const
{
FHitResult HitResult;
GetWorld()->GetFirstPlayerController()->GetHitResultUnderCursor(ECollisionChannel::ECC_Visibility, true, HitResult);
return HitResult.Location;
}
void UAbilityComponent::SetIndicatorDecalAtLocation()
{
if (GetOwner() == nullptr || IndicatorDecalComponent == nullptr)
return;
FVector PlayerCursorLocation = GetPlayerCursorLocation();
FVector PlayerCharacterLocation = GetOwner()->GetActorLocation();
if (FVector::Dist(PlayerCursorLocation, PlayerCharacterLocation) > GetAbilityRange())
{
FHitResult Hit;
FVector End = PlayerCharacterLocation + UKismetMathLibrary::FindLookAtRotation(PlayerCharacterLocation, PlayerCursorLocation).Vector() * GetAbilityRange();
const FCollisionQueryParams CollisionQueryParams;
const FCollisionResponseParams CollisionResponseParams;
GetWorld()->LineTraceSingleByChannel(Hit, PlayerCharacterLocation, End, ECollisionChannel::ECC_Visibility, CollisionQueryParams, CollisionResponseParams);
PlayerCursorLocation = Hit.Location;
}
GetIndicatorDecalComponent()->SetWorldLocation(PlayerCursorLocation);
}
However, there is one problem, I canât figure out how to grab whether the input action is triggered or not, or its value. UEnhancedInputComponent::GetBoundActionValue
is one option, Iâm pretty sure, but from what I understand, youâd have to use SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
to then cast UInputComponent
to UEnhancedInputComponent
.
But the problem is my ability component isnât a character, so Iâm not really sure what to do now? I can grab Get_IA_SetDestination
in my BP subclass. But Iâd prefer to have this functionality in the parent class since they all share this aspect anyways.
To give context, all of my input actions and my input mapping contexts have been made in BP, and my player controller is also BP (used the BP template then added on C++ classes). How Iâm handling this is that in my player controller BP, I have input actions that handle triggering the abilities (1, 2, 3, 4), then what happens is that the timer for OnDecision()
is set, and every . something seconds, it checks whether to see if IA_SetDestination
is clicked. IA_SetDestination
and the input actions that handle the triggering of the abilities are all in one IMC
also made in BP.
Thanks to anyone who answers.
Updated the code.