/// <summary> /// Rotates the camera according to the horizontal and vertical movement values. /// </summary> /// <param name="horizontalMovement">-1 to 1 value specifying the amount of horizontal movement.</param> /// <param name="verticalMovement">-1 to 1 value specifying the amount of vertical movement.</param> /// <param name="immediateUpdate">Should the camera be updated immediately?</param> /// <returns>The updated rotation.</returns> public override Quaternion Rotate(float horizontalMovement, float verticalMovement, bool immediateUpdate) { #if ULTIMATE_CHARACTER_CONTROLLER_VR if (m_VREnabled && immediateUpdate) { m_CharacterRotation = m_CharacterTransform.rotation; EventHandler.ExecuteEvent("OnTryRecenterTracking"); } #endif if (m_UpdateCharacterRotation) { // Rotate with the moving platform. if (m_CharacterLocomotion.Platform != null) { m_PlatformRotation = MathUtility.InverseTransformQuaternion(m_CharacterLocomotion.Platform.rotation, m_CharacterPlatformRotationOffset) * Quaternion.Inverse(MathUtility.InverseTransformQuaternion(m_CharacterLocomotion.Platform.rotation, m_CharacterRotation * Quaternion.Inverse(m_CharacterLocomotion.Platform.rotation))); if (!m_CharacterLocomotion.AlignToGravity) { // Only the local y rotation should affect the character's rotation. var localPlatformTorque = MathUtility.InverseTransformQuaternion(m_CharacterTransform.rotation, m_PlatformRotation).eulerAngles; localPlatformTorque.x = localPlatformTorque.z = 0; m_PlatformRotation = MathUtility.TransformQuaternion(m_CharacterTransform.rotation, Quaternion.Euler(localPlatformTorque)); } m_CharacterRotation *= m_PlatformRotation; } // Keep the same relative rotation with the character if the character changes their up direction. if (m_CharacterLocomotion.AlignToGravity && m_AlignToGravityRotationSpeed > 0) { var localRotation = MathUtility.InverseTransformQuaternion(m_CharacterTransform.rotation, m_CharacterRotation).eulerAngles; localRotation.x = localRotation.z = 0; m_CharacterRotation = Quaternion.Slerp(m_CharacterRotation, MathUtility.TransformQuaternion(m_CharacterTransform.rotation, Quaternion.Euler(localRotation)), m_AlignToGravityRotationSpeed); } } // Remember the offset so the delta can be compared the next update. if (m_CharacterLocomotion.Platform != null) { UpdatePlatformRotationOffset(m_CharacterLocomotion.Platform); } // Update the rotation. The pitch may have a limit. if (Mathf.Abs(m_MinPitchLimit - m_MaxPitchLimit) < 180) { m_Pitch = MathUtility.ClampAngle(m_Pitch, -verticalMovement, m_MinPitchLimit, m_MaxPitchLimit); } else { m_Pitch -= verticalMovement; } // Prevent the values from getting too large. m_Pitch = MathUtility.ClampInnerAngle(m_Pitch); m_Yaw = MathUtility.ClampInnerAngle(m_Yaw); // If aim assist has a target then the camera should look in the specified direction. if (m_AimAssist != null) { m_AimAssist.UpdateBreakForce(Mathf.Abs(horizontalMovement) + Mathf.Abs(verticalMovement)); if (m_AimAssist.HasTarget()) { var rotation = MathUtility.TransformQuaternion(m_CharacterRotation, Quaternion.Euler(m_Pitch, m_Yaw, 0)); var assistRotation = rotation * MathUtility.InverseTransformQuaternion(rotation, m_AimAssist.TargetRotation(rotation)); // Set the pitch and yaw so when the target is lost the view type won't snap back to the previous rotation value. var localAssistRotation = MathUtility.InverseTransformQuaternion(m_CharacterRotation, assistRotation).eulerAngles; m_Pitch = MathUtility.ClampInnerAngle(localAssistRotation.x); m_Yaw = MathUtility.ClampInnerAngle(localAssistRotation.y); } } // Return the rotation. return(MathUtility.TransformQuaternion(m_CharacterRotation, Quaternion.Euler(m_Pitch, m_Yaw, 0)) * Quaternion.LookRotation(m_ForwardAxis) * Quaternion.Euler(m_RotationSpring.Value) * Quaternion.Euler(m_SecondaryRotationSpring.Value)); }