Download

Gameplay Ability and SetControlRotation

I use FGameplayAbilityTargetData_SingleTargetHit and pass in hit results from the GetHitResultUnderCursor. Then in the ability, I use the hit result data to SetControlRotation on the character then play a montage. However, the montage plays first and then the rotation happens



FHitResult Hit;
if(GetHitResultUnderCursor(ECC_Visibility, false, Hit))
{ ACharacter* Character = GetCharacter();

FGameplayAbilityTargetData_SingleTargetHit *HitData = new FGameplayAbilityTargetData_SingleTargetHit(Hit);
FGameplayAbilityTargetDataHandle Data(HitData);

FGameplayEventData Payload;
Payload.Instigator = Character;
Payload.Target = Character;
Payload.TargetData = Data;

const FGameplayTag Tag = FGameplayTag::RequestGameplayTag(FName("GameplayEvent.Trigger.Attack"));
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(Character, Tag, Payload);
 }




const FVector_NetQuantize Location = TriggerEventData->TargetData.Get(0)->GetHitResult()->Location;

FRotator Rotation = UKismetMathLibrary::FindLookAtRotation(GetActorInfo().OwnerActor->GetActorLocation(), Location);
Rotation.Roll = 0.0f;
Rotation.Pitch = 0.0f;

ACharacter* Character = Cast<ACharacter>(GetActorInfo().OwnerActor);
Character->GetController()->SetControlRotation(Rotation);


UAbilityTask_PlayMontageWaitEvent* Task = UAbilityTask_PlayMontageWaitEvent::PlayMontageAndWaitForEvent(this, NAME_None, MontageToPlay, FGameplayTagContainer(), 1.0f, NAME_None, true, 1.0f);
Task->OnBlendOut.AddDynamic(this, &UGameplayAbility_Attack::OnCompleted);
Task->OnCompleted.AddDynamic(this, &UGameplayAbility_Attack::OnCompleted);
Task->OnInterrupted.AddDynamic(this, &UGameplayAbility_Attack::OnCancelled);
Task->OnCancelled.AddDynamic(this, &UGameplayAbility_Attack::OnCancelled);
 Task->ReadyForActivation();


I’m afraid to put any artificial delay because I want the montage(an attacking animation) to play instantly the player rotates.

So I’m a dummy. I forgot SetControlRotation uses rotation over time with the CharacterMovementComponent rotation rate. So I calculated the time for rotation speed and used a delay timer.



const FRotator CurrentRotation = Actor->GetActorRotation();
const float Distance = CurrentRotation.GetManhattanDistance(NewRotation);
const float Velocity = Character->GetCharacterMovement()->RotationRate.Yaw;
float Time = Distance / Velocity;

Time *= FMath::Abs(1 - MontageToPlay->BlendIn.GetBlendTime());

UAbilityTask_WaitDelay* WaitDelay = UAbilityTask_WaitDelay::WaitDelay(this, Time);