using System; using Unity.Collections; using Unity.Entities; using Unity.Mathematics; using Unity.CharacterController; public static class FirstPersonCharacterUtilities { public static quaternion GetCurrentWorldViewRotation(quaternion characterRotation, quaternion localCharacterViewRotation) { return math.mul(characterRotation, localCharacterViewRotation); } public static void GetCurrentWorldViewDirectionAndRotation( quaternion characterRotation, quaternion localCharacterViewRotation, out float3 worldCharacterViewDirection, out quaternion worldCharacterViewRotation) { worldCharacterViewRotation = GetCurrentWorldViewRotation(characterRotation, localCharacterViewRotation); worldCharacterViewDirection = math.mul(worldCharacterViewRotation, math.forward()); } public static void ComputeFinalRotationsFromTargetLookDirection( ref quaternion characterRotation, ref quaternion localCharacterViewRotation, ref float3 targetLookDirection, ref float viewPitchDegrees, float viewRollDegrees, float minViewPitchDegrees, float maxViewPitchDegrees, float3 characterUp) { // rotate character root to point at look direction on character up plane float3 newCharacterForward = math.normalizesafe(MathUtilities.ProjectOnPlane(targetLookDirection, characterUp)); characterRotation = quaternion.LookRotationSafe(newCharacterForward, characterUp); // calculate view pitch angles to look at target direction viewPitchDegrees = math.degrees(MathUtilities.AngleRadians(newCharacterForward, targetLookDirection)); if (math.dot(characterUp, targetLookDirection) < 0f) { viewPitchDegrees *= -1f; } viewPitchDegrees = math.clamp(viewPitchDegrees, minViewPitchDegrees, maxViewPitchDegrees); localCharacterViewRotation = CalculateLocalViewRotation(viewPitchDegrees, viewRollDegrees); } public static void ComputeFinalRotationsFromRotationDelta( ref float viewPitchDegrees, ref float characterRotationYDegrees, float3 characterTransformUp, float2 yawPitchDeltaDegrees, float viewRollDegrees, float minPitchDegrees, float maxPitchDegrees, out quaternion characterRotation, out float canceledPitchDegrees, out quaternion viewLocalRotation) { // Yaw characterRotationYDegrees += yawPitchDeltaDegrees.x; ComputeRotationFromYAngleAndUp(characterRotationYDegrees, characterTransformUp, out characterRotation); // Pitch viewPitchDegrees += yawPitchDeltaDegrees.y; float viewPitchAngleDegreesBeforeClamp = viewPitchDegrees; viewPitchDegrees = math.clamp(viewPitchDegrees, minPitchDegrees, maxPitchDegrees); canceledPitchDegrees = yawPitchDeltaDegrees.y - (viewPitchAngleDegreesBeforeClamp - viewPitchDegrees); viewLocalRotation = CalculateLocalViewRotation(viewPitchDegrees, viewRollDegrees); } public static void ComputeRotationFromYAngleAndUp( float characterRotationYDegrees, float3 characterTransformUp, out quaternion characterRotation) { characterRotation = math.mul(MathUtilities.CreateRotationWithUpPriority(characterTransformUp, math.forward()), quaternion.Euler(0f, math.radians(characterRotationYDegrees), 0f)); } public static void ComputeFinalRotationsFromRotationDelta( ref quaternion characterRotation, ref float viewPitchDegrees, float2 yawPitchDeltaDegrees, float viewRollDegrees, float minPitchDegrees, float maxPitchDegrees, out float canceledPitchDegrees, out quaternion viewLocalRotation) { // Yaw quaternion yawRotation = quaternion.Euler(math.up() * math.radians(yawPitchDeltaDegrees.x)); characterRotation = math.mul(characterRotation, yawRotation); // Pitch viewPitchDegrees += yawPitchDeltaDegrees.y; float viewPitchAngleDegreesBeforeClamp = viewPitchDegrees; viewPitchDegrees = math.clamp(viewPitchDegrees, minPitchDegrees, maxPitchDegrees); canceledPitchDegrees = yawPitchDeltaDegrees.y - (viewPitchAngleDegreesBeforeClamp - viewPitchDegrees); viewLocalRotation = CalculateLocalViewRotation(viewPitchDegrees, viewRollDegrees); } public static quaternion CalculateLocalViewRotation(float viewPitchDegrees, float viewRollDegrees) { // Pitch quaternion viewLocalRotation = quaternion.AxisAngle(-math.right(), math.radians(viewPitchDegrees)); // Roll viewLocalRotation = math.mul(viewLocalRotation, quaternion.AxisAngle(math.forward(), math.radians(viewRollDegrees))); return viewLocalRotation; } public static float3 ComputeTargetLookDirectionFromRotationAngles( ref float viewPitchDegrees, float minViewPitchDegrees, float maxViewPitchDegrees, float2 pitchYawDegrees, quaternion characterRotation) { // Yaw quaternion yawRotation = quaternion.Euler(math.up() * math.radians(pitchYawDegrees.x)); quaternion targetRotation = math.mul(characterRotation, yawRotation); // Pitch float tmpViewPitchAngleDegrees = viewPitchDegrees + pitchYawDegrees.y; tmpViewPitchAngleDegrees = math.clamp(tmpViewPitchAngleDegrees, minViewPitchDegrees, maxViewPitchDegrees); quaternion pitchRotation = quaternion.Euler(-math.right() * math.radians(tmpViewPitchAngleDegrees)); targetRotation = math.mul(targetRotation, pitchRotation); return math.mul(targetRotation, math.forward()); } }