bool UHoatCameraModifierFocusTargetActor::ProcessViewRotation(class AActor* ViewTarget, float DeltaTime, FRotator& OutViewRotation, FRotator& OutDeltaRot) { Super::ProcessViewRotation(ViewTarget, DeltaTime, OutViewRotation, OutDeltaRot); // Check if we're selecting a target. if (!IsValid(ViewTarget)) { return false; } ITargetingActorInterface* targetingActor = Cast<ITargetingActorInterface>(ViewTarget); if (!targetingActor) { return false; } if (!targetingActor->IsSelectingTarget()) { return false; } // Check if there's a selected target. AActor* currentTarget = targetingActor->GetCurrentTarget(); if (IsValid(currentTarget)) { if (currentTarget != LastTarget) { // We have selected a new target. Compute desired rotation. FVector cameraLocation = CameraOwner->GetCameraLocation(); FVector targetLocation = currentTarget->GetActorLocation(); // Get rotation delta from current camera rotation to look-at rotation for the target. // As the camera position might change depending on its rotation (e.g. for spring arms), // we just compute this once per target and store the result. // Otherwise, for very close targets, we risk rotating the camera back and forth as its position changes. DesiredRotation = UKismetMathLibrary::FindLookAtRotation(cameraLocation, targetLocation); LastTarget = currentTarget; } FRotator currentRotation = OutViewRotation; if (SnapSpeed <= 0) { // Snap immediately. OutViewRotation = DesiredRotation; } else { FRotator towardsDesired = DesiredRotation - currentRotation; FRotator towardsDesiredNormalized = towardsDesired.GetNormalized(); if (towardsDesiredNormalized.IsNearlyZero()) { // Prevent overshooting. OutViewRotation = DesiredRotation; } else { // Apply rotation speed. FRotator deltaRot = towardsDesiredNormalized * SnapSpeed * DeltaTime; OutDeltaRot += deltaRot; } } } else { LastTarget = nullptr; // No target selected. Smoothly apply player input. FVector2D targetSelectionInput = targetingActor->GetCurrentTargetSelectionInput(); FRotator deltaRot; deltaRot.Yaw = targetSelectionInput.X * RotationSpeed * DeltaTime; deltaRot.Pitch = -targetSelectionInput.Y * RotationSpeed * DeltaTime; deltaRot.Roll = 0.0f; OutDeltaRot += deltaRot; } // Prevent further camera modifiers from being applied. return true; }
void UArchVisCharMovementComponent::PhysWalking(float DeltaTime, int32 Iterations) { // let character do its thing for translation Super::PhysWalking(DeltaTime, Iterations); // // now we will handle rotation // // update yaw if (CurrentRotInput.Yaw == 0) { // decelerate to 0 if (CurrentRotationalVelocity.Yaw > 0.f) { CurrentRotationalVelocity.Yaw -= RotationalDeceleration.Yaw * DeltaTime; CurrentRotationalVelocity.Yaw = FMath::Max(CurrentRotationalVelocity.Yaw, 0.f); // don't go below 0 because that would be re-accelerating the other way } else { CurrentRotationalVelocity.Yaw += RotationalDeceleration.Yaw * DeltaTime; CurrentRotationalVelocity.Yaw = FMath::Min(CurrentRotationalVelocity.Yaw, 0.f); // don't go above 0 because that would be re-accelerating the other way } } else { // accelerate in desired direction // clamp delta so it won't take us outside the acceptable speed range // note that if we're already out of that range, we won't clamp back float const MaxYawVelMag = FMath::Min(1.f, FMath::Abs(CurrentRotInput.Yaw)) * MaxRotationalVelocity.Yaw; float const MaxDeltaYawVel = FMath::Max(0.f, MaxYawVelMag - CurrentRotationalVelocity.Yaw); float const MinDeltaYawVel = FMath::Min(0.f, -(CurrentRotationalVelocity.Yaw + MaxYawVelMag)); float const DeltaYaw = FMath::Clamp(CurrentRotInput.Yaw * RotationalAcceleration.Yaw * DeltaTime, MinDeltaYawVel, MaxDeltaYawVel); CurrentRotationalVelocity.Yaw += DeltaYaw; } // update pitch if (CurrentRotInput.Pitch == 0) { // decelerate to 0 if (CurrentRotationalVelocity.Pitch > 0.f) { CurrentRotationalVelocity.Pitch -= RotationalDeceleration.Pitch * DeltaTime; CurrentRotationalVelocity.Pitch = FMath::Max(CurrentRotationalVelocity.Pitch, 0.f); // don't go below 0 because that would be reaccelerating the other way } else { CurrentRotationalVelocity.Pitch += RotationalDeceleration.Pitch * DeltaTime; CurrentRotationalVelocity.Pitch = FMath::Min(CurrentRotationalVelocity.Pitch, 0.f); // don't go above 0 because that would be reaccelerating the other way } } else { float const MaxPitchVelMag = FMath::Min(1.f, FMath::Abs(CurrentRotInput.Pitch)) * MaxRotationalVelocity.Pitch; float const MaxDeltaPitchVel = FMath::Max(0.f, MaxPitchVelMag - CurrentRotationalVelocity.Pitch); float const MinDeltaPitchVel = FMath::Min(0.f, -(CurrentRotationalVelocity.Pitch + MaxPitchVelMag)); float const DeltaPitch = FMath::Clamp(CurrentRotInput.Pitch * RotationalAcceleration.Pitch * DeltaTime, MinDeltaPitchVel, MaxDeltaPitchVel); CurrentRotationalVelocity.Pitch += DeltaPitch; } // apply rotation FRotator RotDelta = CurrentRotationalVelocity * DeltaTime; if (!RotDelta.IsNearlyZero()) { FRotator const CurrentComponentRot = UpdatedComponent->GetComponentRotation(); // enforce pitch limits float const CurrentPitch = CurrentComponentRot.Pitch; float const MinDeltaPitch = MinPitch - CurrentPitch; float const MaxDeltaPitch = MaxPitch - CurrentPitch; float const OldPitch = RotDelta.Pitch; RotDelta.Pitch = FMath::Clamp(RotDelta.Pitch, MinDeltaPitch, MaxDeltaPitch); if (OldPitch != RotDelta.Pitch) { // if we got clamped, zero the pitch velocity CurrentRotationalVelocity.Pitch = 0.f; } FRotator const NewRot = CurrentComponentRot + RotDelta; FHitResult Hit(1.f); SafeMoveUpdatedComponent(FVector::ZeroVector, NewRot, false, Hit); } // consume input CurrentRotInput = FRotator::ZeroRotator; }