Exemple #1
0
        /// <summary>
        /// Simulates rotating the agent towards the specified direction and returns the new rotation.
        ///
        /// Note that this only calculates a new rotation, it does not change the actual rotation of the agent.
        ///
        /// See: <see cref="orientation"/>
        /// See: <see cref="movementPlane"/>
        /// </summary>
        /// <param name="direction">Direction in the movement plane to rotate towards.</param>
        /// <param name="maxDegreesMainAxis">Maximum number of degrees to rotate this frame around the character's main axis. This is rotating left and right as a character normally does.</param>
        /// <param name="maxDegreesOffAxis">Maximum number of degrees to rotate this frame around other axes. This is used to ensure the character's up direction is correct.
        ///         It is only used for non-planar worlds where the up direction changes depending on the position of the character.
        ///      More precisely a faster code path which ignores this parameter is used whenever the current #movementPlane is exactly the XZ or XY plane.
        ///         This must be at least as large as maxDegreesMainAxis.</param>
        protected Quaternion SimulateRotationTowards(Vector2 direction, float maxDegreesMainAxis, float maxDegreesOffAxis = float.PositiveInfinity)
        {
            Quaternion targetRotation;

            if (movementPlane.isXY || movementPlane.isXZ)
            {
                if (direction == Vector2.zero)
                {
                    return(simulatedRotation);
                }

                // Common fast path.
                // A standard XY or XZ movement plane indicates that the character is moving in a normal planar world.
                // We will use a much faster code path for this case since we don't have to deal with changing the 'up' direction of the character all the time.
                // This code path mostly works for non-planar worlds too, but it will fail in some cases.
                // In particular it will not be able to adjust the up direction of the character while it is standing still (because then a zero maxDegreesMainAxis is usually passed).
                // That case may be important, especially when the character has just been spawned and does not have a destination yet.
                targetRotation    = Quaternion.LookRotation(movementPlane.ToWorld(direction, 0), movementPlane.ToWorld(Vector2.zero, 1));
                maxDegreesOffAxis = maxDegreesMainAxis;
            }
            else
            {
                // Decompose the rotation into two parts: a rotation around the main axis of the character, and a rotation around the other axes.
                // Then limit the rotation speed along those two components separately.
                var forwardInPlane = movementPlane.ToPlane(rotation * (orientation == OrientationMode.YAxisForward ? Vector3.up : Vector3.forward));

                // Can happen if the character is perpendicular to the plane
                if (forwardInPlane == Vector2.zero)
                {
                    forwardInPlane = Vector2.right;
                }

                var rotationVectorAroundMainAxis = VectorMath.ComplexMultiplyConjugate(direction, forwardInPlane);

                // Note: If the direction is zero, then angle will also be zero since atan2(0,0) = 0
                var angle = Mathf.Atan2(rotationVectorAroundMainAxis.y, rotationVectorAroundMainAxis.x) * Mathf.Rad2Deg;
                var rotationAroundMainAxis = Quaternion.AngleAxis(-Mathf.Min(Mathf.Abs(angle), maxDegreesMainAxis) * Mathf.Sign(angle), Vector3.up);

                targetRotation = Quaternion.LookRotation(movementPlane.ToWorld(forwardInPlane, 0), movementPlane.ToWorld(Vector2.zero, 1));
                targetRotation = targetRotation * rotationAroundMainAxis;
            }

            // This causes the character to only rotate around the Z axis
            if (orientation == OrientationMode.YAxisForward)
            {
                targetRotation *= Quaternion.Euler(90, 0, 0);
            }
            return(Quaternion.RotateTowards(simulatedRotation, targetRotation, maxDegreesOffAxis));
        }