UAbilityTask_ApplyRootMotionMoveToActorForce* UAbilityTask_ApplyRootMotionMoveToActorForce::ApplyRootMotionMoveToActorForce(UObject* WorldContextObject, FName TaskInstanceName, AActor* TargetActor, FVector TargetLocationOffset, ERootMotionMoveToActorTargetOffsetType OffsetAlignment, float Duration, UCurveFloat* TargetLerpSpeedHorizontal, UCurveFloat* TargetLerpSpeedVertical, bool bSetNewMovementMode, EMovementMode MovementMode, bool bRestrictSpeedToExpected, UCurveVector* PathOffsetCurve, UCurveFloat* TimeMappingCurve, ERootMotionFinishVelocityMode VelocityOnFinishMode, FVector SetVelocityOnFinish, bool bDisableDestinationReachedInterrupt) { auto MyTask = NewAbilityTask<UAbilityTask_ApplyRootMotionMoveToActorForce>(WorldContextObject, TaskInstanceName); MyTask->ForceName = TaskInstanceName; MyTask->TargetActor = TargetActor; MyTask->TargetLocationOffset = TargetLocationOffset; MyTask->OffsetAlignment = OffsetAlignment; MyTask->Duration = FMath::Max(Duration, KINDA_SMALL_NUMBER); // Avoid negative or divide-by-zero cases MyTask->bDisableDestinationReachedInterrupt = bDisableDestinationReachedInterrupt; MyTask->TargetLerpSpeedHorizontalCurve = TargetLerpSpeedHorizontal; MyTask->TargetLerpSpeedVerticalCurve = TargetLerpSpeedVertical; MyTask->bSetNewMovementMode = bSetNewMovementMode; MyTask->NewMovementMode = MovementMode; MyTask->bRestrictSpeedToExpected = bRestrictSpeedToExpected; MyTask->PathOffsetCurve = PathOffsetCurve; MyTask->TimeMappingCurve = TimeMappingCurve; MyTask->VelocityOnFinishMode = VelocityOnFinishMode; MyTask->SetVelocityOnFinish = SetVelocityOnFinish; if (MyTask->GetAvatarActor() != nullptr) { MyTask->StartLocation = MyTask->GetAvatarActor()->GetActorLocation(); } else { checkf(false, TEXT("UAbilityTask_ApplyRootMotionMoveToActorForce called without valid avatar actor to get start location from.")); MyTask->StartLocation = TargetActor ? TargetActor->GetActorLocation() : FVector(0.f); } MyTask->SharedInitAndApply(); return MyTask; }
void UAbilityTask_ApplyRootMotionJumpForce::TickTask(float DeltaTime) { if (bIsFinished) { return; } const float CurrentTime = GetWorld()->GetTimeSeconds(); if (bHasLanded && CurrentTime >= (StartTime+MinimumLandedTriggerTime)) { TriggerLanded(); return; } Super::TickTask(DeltaTime); AActor* MyActor = GetAvatarActor(); if (MyActor) { if (!bFinishOnLanded && CurrentTime >= EndTime) { // Task has finished Finish(); } } else { Finish(); } }
UAbilityTask_MoveToLocation* UAbilityTask_MoveToLocation::MoveToLocation(class UObject* WorldContextObject, FName TaskInstanceName, FVector Location, float Duration, UCurveFloat* OptionalInterpolationCurve) { auto MyObj = NewTask<UAbilityTask_MoveToLocation>(WorldContextObject, TaskInstanceName); if (MyObj->GetAvatarActor() != nullptr) { MyObj->StartLocation = MyObj->GetAvatarActor()->GetActorLocation(); } MyObj->TargetLocation = Location; MyObj->DurationOfMovement = FMath::Max(Duration, 0.001f); // Avoid negative or divide-by-zero cases MyObj->TimeMoveStarted = MyObj->GetWorld()->GetTimeSeconds(); MyObj->TimeMoveWillEnd = MyObj->TimeMoveStarted + MyObj->DurationOfMovement; MyObj->LerpCurve = OptionalInterpolationCurve; return MyObj; }
void UAbilityTask_WaitMovementModeChange::Activate() { ACharacter* Character = Cast<ACharacter>(GetAvatarActor()); if (Character) { Character->MovementModeChangedDelegate.AddDynamic(this, &UAbilityTask_WaitMovementModeChange::OnMovementModeChange); MyCharacter = Character; } }
void UAbilityTask_ApplyRootMotionJumpForce::Activate() { ACharacter* Character = Cast<ACharacter>(GetAvatarActor()); if (Character) { Character->LandedDelegate.AddDynamic(this, &UAbilityTask_ApplyRootMotionJumpForce::OnLandedCallback); } SetWaitingOnAvatar(); }
void UAbilityTask_ApplyRootMotionMoveToActorForce::TickTask(float DeltaTime) { if (bIsFinished) { return; } Super::TickTask(DeltaTime); AActor* MyActor = GetAvatarActor(); if (MyActor) { float CurrentTime = GetWorld()->GetTimeSeconds(); const bool bTimedOut = CurrentTime >= EndTime; // Update target location { const FVector PreviousTargetLocation = TargetLocation; if (UpdateTargetLocation(DeltaTime)) { SetRootMotionTargetLocation(TargetLocation); } else { // TargetLocation not updated - TargetActor not around anymore, continue on to last set TargetLocation } } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) // Draw debug if (DebugMoveToActorForce > 0) { DrawDebugSphere(GetWorld(), TargetLocation, 50.f, 10, FColor::Green, false, 15.f); } #endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) const float ReachedDestinationDistanceSqr = 50.f * 50.f; const bool bReachedDestination = FVector::DistSquared(TargetLocation, MyActor->GetActorLocation()) < ReachedDestinationDistanceSqr; if (bTimedOut || (bReachedDestination && !bDisableDestinationReachedInterrupt)) { // Task has finished bIsFinished = true; if (!bIsSimulating) { MyActor->ForceNetUpdate(); OnFinished.Broadcast(bReachedDestination, bTimedOut, TargetLocation); EndTask(); } } } else { bIsFinished = true; EndTask(); } }
//TODO: This is still an awful way to do this and we should scrap this task or do it right. void UAbilityTask_MoveToLocation::TickTask(float DeltaTime) { if (bIsFinished) { return; } Super::TickTask(DeltaTime); AActor* MyActor = GetAvatarActor(); if (MyActor) { ACharacter* MyCharacter = Cast<ACharacter>(MyActor); if (MyCharacter) { UCharacterMovementComponent* CharMoveComp = Cast<UCharacterMovementComponent>(MyCharacter->GetMovementComponent()); if (CharMoveComp) { CharMoveComp->SetMovementMode(MOVE_Custom, 0); } } float CurrentTime = GetWorld()->GetTimeSeconds(); if (CurrentTime >= TimeMoveWillEnd) { bIsFinished = true; // Teleport in attempt to find a valid collision spot MyActor->TeleportTo(TargetLocation, MyActor->GetActorRotation()); if (!bIsSimulating) { MyActor->ForceNetUpdate(); OnTargetLocationReached.Broadcast(); EndTask(); } } else { float MoveFraction = (CurrentTime - TimeMoveStarted) / DurationOfMovement; if (LerpCurve) { MoveFraction = LerpCurve->GetFloatValue(MoveFraction); } MyActor->SetActorLocation(FMath::Lerp<FVector, float>(StartLocation, TargetLocation, MoveFraction)); } } else { bIsFinished = true; EndTask(); } }
void UAbilityTask_ApplyRootMotionJumpForce::OnDestroy(bool AbilityIsEnding) { ACharacter* Character = Cast<ACharacter>(GetAvatarActor()); if (Character) { Character->LandedDelegate.RemoveDynamic(this, &UAbilityTask_ApplyRootMotionJumpForce::OnLandedCallback); } if (MovementComponent) { MovementComponent->RemoveRootMotionSourceByID(RootMotionSourceID); } Super::OnDestroy(AbilityIsEnding); }
UPrimitiveComponent* UAbilityTask_WaitOverlap::GetComponent() { // TEMP - we are just using root component's collision. A real system will need more data to specify which component to use UPrimitiveComponent * PrimComponent = nullptr; AActor* ActorOwner = GetAvatarActor(); if (ActorOwner) { PrimComponent = Cast<UPrimitiveComponent>(ActorOwner->GetRootComponent()); if (!PrimComponent) { PrimComponent = ActorOwner->FindComponentByClass<UPrimitiveComponent>(); } } return PrimComponent; }
void UAbilityTask_ApplyRootMotionJumpForce::Finish() { bIsFinished = true; if (!bIsSimulating) { AActor* MyActor = GetAvatarActor(); if (MyActor) { MyActor->ForceNetUpdate(); OnFinish.Broadcast(); } } EndTask(); }
void UAbilityTask_MoveToLocation::OnDestroy(bool AbilityIsEnding) { AActor* MyActor = GetAvatarActor(); if (MyActor) { ACharacter* MyCharacter = Cast<ACharacter>(MyActor); if (MyCharacter) { UCharacterMovementComponent* CharMoveComp = Cast<UCharacterMovementComponent>(MyCharacter->GetMovementComponent()); if (CharMoveComp && CharMoveComp->MovementMode == MOVE_Custom) { CharMoveComp->SetMovementMode(MOVE_Falling); } } } Super::OnDestroy(AbilityIsEnding); }
void UAbilityTask_ApplyRootMotionJumpForce::OnLandedCallback(const FHitResult& Hit) { bHasLanded = true; ACharacter* Character = Cast<ACharacter>(GetAvatarActor()); if (Character && Character->bClientUpdating) { // If in a move replay, we just mark that we landed so that next tick we trigger landed } else { // TriggerLanded immediately if we're past time allowed, otherwise it'll get caught next valid tick const float CurrentTime = GetWorld()->GetTimeSeconds(); if (CurrentTime >= (StartTime+MinimumLandedTriggerTime)) { TriggerLanded(); } } }