Esempio n. 1
0
        /// <summary>
        /// Determines if we'll treat input as if we're strafing
        /// </summary>
        protected void SimulateStrafeInput()
        {
            // Direction we need to travel in
            Vector3 lDirection = mWaypointVector;

            lDirection.y = lDirection.y - _PathHeight;
            lDirection.Normalize();

            // Determine our view
            Vector3 lVerticalDirection = Vector3.Project(lDirection, _Transform.up);
            Vector3 lLateralDirection  = (lDirection - lVerticalDirection).normalized;

            mInputFromAvatarAngle = Vector3Ext.SignedAngle(_Transform.forward, lLateralDirection);

            // Determine our movement
            if (mTargetDistance > _StopDistance)
            {
                // Calculate our own slowing
                float lRelativeMoveSpeed = 1f;
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    float lSlowPercent = (mTargetDistance - _StopDistance) / (_SlowDistance - _StopDistance);
                    lRelativeMoveSpeed = ((1f - _SlowFactor) * lSlowPercent) + _SlowFactor;
                }

                // TRT 4/5/2016: Force the slow distance as an absolute value
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    lRelativeMoveSpeed = _SlowFactor;
                }

                lLateralDirection = _Transform.InverseTransformDirection(lLateralDirection);
                mMovementX        = lLateralDirection.x * lRelativeMoveSpeed;
                mMovementY        = lLateralDirection.z * lRelativeMoveSpeed;
            }

            // Grab extra input information if we can
            if (mMotionController._CameraTransform == null)
            {
                mInputFromCameraAngle = mInputFromAvatarAngle;
            }
            else
            {
                Vector3 lInputForward = new Vector3(mMovementX, 0f, mMovementY);

                // We do the inverse tilt so we calculate the rotation in "natural up" space vs. "actor up" space.
                Quaternion lInvTilt = QuaternionExt.FromToRotation(_Transform.up, Vector3.up);

                // Camera forward in "natural up"
                Vector3 lCameraForward = lInvTilt * mMotionController._CameraTransform.forward;

                // Create a quaternion that gets us from our world-forward to our camera direction.
                Quaternion lToCamera = Quaternion.LookRotation(lCameraForward, lInvTilt * _Transform.up);

                // Transform joystick from world space to camera space. Now the input is relative
                // to how the camera is facing.
                Vector3 lMoveDirection = lToCamera * lInputForward;
                mInputFromCameraAngle = NumberHelper.GetHorizontalAngle(lCameraForward, lMoveDirection);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Calculate how much to move an rotate by
        /// </summary>
        /// <param name="rMove"></param>
        /// <param name="rRotate"></param>
        protected virtual void CalculateMove(Vector3 rWaypoint, ref Vector3 rMove, ref Quaternion rRotate)
        {
            float lDeltaTime = TimeManager.SmoothedDeltaTime;

            // Direction we need to travel in
            Vector3 lDirection = rWaypoint - transform.position;

            lDirection.y = lDirection.y - _PathHeight;
            lDirection.Normalize();

            // Determine our rotation
            Vector3 lVerticalDirection = Vector3.Project(lDirection, transform.up);
            Vector3 lLateralDirection  = lDirection - lVerticalDirection;

            float lYawAngle = Vector3Ext.SignedAngle(transform.forward, lLateralDirection);

            if (_RotationSpeed == 0f)
            {
                rRotate = Quaternion.AngleAxis(lYawAngle, transform.up);
            }
            else
            {
                rRotate = Quaternion.AngleAxis(Mathf.Sign(lYawAngle) * Mathf.Min(Mathf.Abs(lYawAngle), _RotationSpeed * lDeltaTime), transform.up);
            }

            // Determine the movement
            if (_UseNavMeshPosition)
            {
                rMove = mNavMeshAgent.nextPosition - transform.position;
            }
            // In this case, we'll calculate movement ourselves
            else
            {
                // Grab the base movement speed
                float lMoveSpeed = mRootMotionMovement.magnitude / lDeltaTime;
                if (lMoveSpeed == 0f)
                {
                    lMoveSpeed = _MovementSpeed;
                }

                // Calculate our own slowing
                float lRelativeMoveSpeed = 1f;
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    float lSlowPercent = (mTargetDistance - _StopDistance) / (_SlowDistance - _StopDistance);
                    lRelativeMoveSpeed = ((1f - _SlowFactor) * lSlowPercent) + _SlowFactor;
                }

                // TRT 4/5/2016: Force the slow distance as an absolute value
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    lMoveSpeed         = _SlowFactor;
                    lRelativeMoveSpeed = 1f;
                }

                // Set the final velocity based on the future rotation
                Quaternion lFutureRotation = transform.rotation * rRotate;
                rMove = lFutureRotation.Forward() * (lMoveSpeed * lRelativeMoveSpeed * lDeltaTime);
            }
        }
        /// <summary>
        /// Allow the joint to render it's own GUI. This GUI is used
        /// for displaying and manipulating the joint itself.
        /// </summary>
        /// <returns>Reports if the object's value was changed</returns>
        public override bool OnInspectorManipulatorGUI(IKBoneModifier rModifier)
        {
#if UNITY_EDITOR
            // Determine if the swing is changing
            if (mBone != null)
            {
                Vector3 lSwing    = rModifier.Swing.eulerAngles;
                Vector3 lNewSwing = InspectorHelper.Vector3Fields("Swing", "Euler angles to swing the bone.", lSwing, true, true, false);
                if (lNewSwing != lSwing)
                {
                    // Grab the amount that was just rotated by based on the current rotation.
                    // We do this so the change is relative to the current swing rotation
                    Vector3 lDeltaRotations = lNewSwing - lSwing;
                    rModifier.Swing = rModifier.Swing * Quaternion.Euler(lDeltaRotations);

                    rModifier.IsDirty = true;
                }

                // Determine if the twist is changing
                //float lTwist = mBone.Twist.eulerAngles.y;
                float lTwist    = Vector3Ext.SignedAngle(Vector3.up, rModifier.Twist * Vector3.up, Vector3.forward);
                float lNewTwist = EditorGUILayout.FloatField("Twist", lTwist);
                if (_AllowTwist && lNewTwist != lTwist)
                {
                    rModifier.Twist   = Quaternion.AngleAxis(lNewTwist, Vector3.forward);
                    rModifier.IsDirty = true;
                }

                // Reset the values if needed
                if (GUILayout.Button("reset rotation", EditorStyles.miniButton))
                {
                    rModifier.Swing   = Quaternion.identity;
                    rModifier.Twist   = (_AllowTwist ? Quaternion.identity : mBone._Twist);
                    rModifier.IsDirty = true;

                    mBone._Transform.localRotation = mBone._BindRotation;
                }

                if (rModifier.IsDirty)
                {
                    // Before we go to far, see if we are within the joint limits. If not,
                    // we need to go back to a good position.
                    bool lIsInLimits = ApplyLimits(ref rModifier.Swing, ref rModifier.Twist);
                    if (lIsInLimits || QuaternionExt.IsEqual(rModifier.Swing, Quaternion.identity))
                    {
                        mLastSwing = rModifier.Swing;
                        mLastTwist = rModifier.Twist;
                    }
                    else
                    {
                        rModifier.Swing = mLastSwing;
                        rModifier.Twist = mLastTwist;
                    }
                }
            }
#endif

            return(rModifier.IsDirty);
        }
        // ************************************** EDITOR SUPPORT **************************************

        /// <summary>
        /// Allow the constraint to render it's own GUI
        /// </summary>
        /// <returns>Reports if the object's value was changed</returns>
        public override bool OnInspectorConstraintGUI(bool rIsSelected)
        {
            bool lIsDirty = false;

#if UNITY_EDITOR
            GUILayout.Space(5);

            // Determine if the swing is changing
            if (mBone != null)
            {
                Vector3 lSwing    = _Swing.eulerAngles;
                Vector3 lNewSwing = InspectorHelper.Vector3Fields("Swing", "Euler angles to swing the bone.", lSwing, true, true, false);
                if (lNewSwing != lSwing)
                {
                    lIsDirty = true;

                    // Grab the amount that was just rotated by based on the current rotation.
                    // We do this so the change is relative to the current swing rotation
                    Vector3 lDeltaRotations = lNewSwing - lSwing;
                    _Swing = _Swing * Quaternion.Euler(lDeltaRotations);
                }

                // Determine if the twist is changing
                float lTwist    = Vector3Ext.SignedAngle(Vector3.up, _Twist * Vector3.up, Vector3.forward);
                float lNewTwist = EditorGUILayout.FloatField("Twist", lTwist);
                if (lNewTwist != lTwist)
                {
                    lIsDirty = true;
                    _Twist   = Quaternion.AngleAxis(lNewTwist, Vector3.forward);
                }

                // Reset the values if needed
                if (GUILayout.Button("reset rotation", EditorStyles.miniButton))
                {
                    _Swing   = Quaternion.identity;
                    _Twist   = Quaternion.identity;
                    lIsDirty = true;
                }

                if (lIsDirty)
                {
                    mBone.SetLocalRotation(_Swing, _Twist, 1f);
                }
            }
#endif

            return(lIsDirty);
        }
        /// <summary>
        /// This function renders out the handles that allow us to edit the twist limits. It
        /// isn't actually meant to change the twist itself
        /// </summary>
        /// <param name="rBone"></param>
        /// <param name="rMinAngle"></param>
        /// <param name="rMaxAngle"></param>
        /// <returns></returns>
        public static bool JointTwistLimitsHandle(BoneControllerBone rBone, ref float rMinAngle, ref float rMaxAngle)
        {
            bool lIsDirty = false;

#if UNITY_EDITOR

            Vector3 lWorldPosition = rBone._Transform.position;
            Quaternion lWorldSwingRotation = rBone.WorldBindRotation * rBone._Swing;

            Color lGUIColor = GUI.color;
            Color lHandleColor = Handles.color;

            float lHandleScale = 0.2f;
            if (rBone.Skeleton.EditorAutoScaleHandles) { lHandleScale = HandleUtility.GetHandleSize(rBone.Transform.position) * HandlesHelper.HandleScale; }

            // Render the border of the angles
            float lTwistAngle = Vector3Ext.SignedAngle(Vector3.up, rBone._Twist * Vector3.up, Vector3.forward);

            Quaternion lActualRotation = Quaternion.AngleAxis(lTwistAngle, Vector3.forward);
            Quaternion lMinRotation = Quaternion.AngleAxis(rMinAngle, Vector3.forward);
            Quaternion lMaxRotation = Quaternion.AngleAxis(rMaxAngle, Vector3.forward);

            Vector3 lMinOffset = lWorldSwingRotation * lMinRotation * Vector3.up * lHandleScale;
            Vector3 lMaxOffset = lWorldSwingRotation * lMaxRotation * Vector3.up * lHandleScale;

            Handles.color = new Color(0.1f, 0.1f, 0.6f, 1f);
            Handles.DrawLine(lWorldPosition, lWorldPosition + lMinOffset);
            Handles.DrawLine(lWorldPosition, lWorldPosition + lMaxOffset);
            //Handles.DrawLine(lWorldPosition, lWorldPosition + (lWorldSwingRotation * rBone.Twist * Vector3.up * (lHandleScale * 1.1f)));

            // Render the solid of the angles
            Handles.color = new Color(0.25f, 0.60f, 0.95f, 0.1f);
            Handles.DrawSolidArc(lWorldPosition, rBone.Transform.rotation * rBone._BoneForward, lWorldSwingRotation * lMinRotation * Vector3.up, Mathf.Abs(rMinAngle) + rMaxAngle, lHandleScale);

            // Render text
            GUI.color = new Color(0.05f, 0.05f, 0.5f, 1f);
            Handles.Label(lWorldPosition + lMinOffset, "min:\r\n" + rMinAngle.ToString("0.00"));
            Handles.Label(lWorldPosition + lMaxOffset, "max:\r\n" + rMaxAngle.ToString("0.00"));
            Handles.Label(lWorldPosition + (lWorldSwingRotation * lActualRotation * Vector3.up * (lHandleScale * 1.3f)), " " + lTwistAngle.ToString("0.00"));

            // Reset
            GUI.color = lGUIColor;
            Handles.color = lHandleColor;
#endif

            return lIsDirty;
        }
        /// <summary>
        /// This function renders out the handles that allow us to edit the twist limits. It
        /// isn't actually meant to change the twist itself
        /// </summary>
        /// <param name="rBone"></param>
        /// <param name="rMinAngle"></param>
        /// <param name="rMaxAngle"></param>
        /// <returns></returns>
        public static bool JointSwingAxisLimitsHandle(BoneControllerBone rBone, Vector3 rAxis, float rMinAngle, float rMaxAngle)
        {
            bool lIsDirty = false;

#if UNITY_EDITOR

            Vector3 lWorldPosition = rBone._Transform.position;
            Quaternion lWorldSwing = rBone.WorldBindRotation * rBone.Swing;

            Color lGUIColor = GUI.color;
            Color lHandleColor = Handles.color;

            float lHandleScale = 0.2f;
            if (rBone.Skeleton.EditorAutoScaleHandles) { lHandleScale = HandleUtility.GetHandleSize(rBone.Transform.position) * HandlesHelper.HandleScale; }

            // Render the border of the angles
            Quaternion lMinRotation = Quaternion.AngleAxis(rMinAngle, rAxis);
            Quaternion lMaxRotation = Quaternion.AngleAxis(rMaxAngle, rAxis);

            // We don't use the world swing since we want the rotation based on the bind position
            Vector3 lMinOffset = rBone.WorldBindRotation * lMinRotation * Vector3.forward * lHandleScale;
            Vector3 lMaxOffset = rBone.WorldBindRotation * lMaxRotation * Vector3.forward * lHandleScale;

            Handles.color = new Color(0.94118f, 0.39608f, 0.13333f, 1f);
            Handles.DrawLine(lWorldPosition, lWorldPosition + lMinOffset);
            Handles.DrawLine(lWorldPosition, lWorldPosition + lMaxOffset);

            // Render the solid of the angles
            Handles.color = new Color(0.94118f, 0.39608f, 0.13333f, 0.1f);
            Handles.DrawSolidArc(lWorldPosition, rBone.WorldBindRotation * rAxis, (rBone.WorldBindRotation * lMinRotation * Vector3.forward), Mathf.Abs(rMinAngle) + rMaxAngle, lHandleScale);

            // Draw text
            GUI.color = new Color(0.72549f, 0.30588f, 0.10588f, 1f);
            Handles.Label(lWorldPosition + lMinOffset, "min:\r\n" + rMinAngle.ToString("0.00"));
            Handles.Label(lWorldPosition + lMaxOffset, "max:\r\n" + rMaxAngle.ToString("0.00"));

            Vector3 lDirectionAxis = Vector3.Cross(rAxis, rBone._BindRotation * rBone._BoneForward);
            float lSwingAngle = Vector3Ext.SignedAngle(lDirectionAxis, rBone.Swing * lDirectionAxis, rAxis);
            Handles.Label(lWorldPosition + (lWorldSwing * (Vector3.forward * (lHandleScale * 1.3f))), "  " + lSwingAngle.ToString("0.00"));

            // Reset
            GUI.color = lGUIColor;
            Handles.color = lHandleColor;
#endif

            return lIsDirty;
        }
        /// <summary>
        /// Allow the joint to render it's own GUI. This GUI is used
        /// for displaying and manipulating the joint itself.
        /// </summary>
        /// <returns>Reports if the object's value was changed</returns>
        public override bool OnInspectorManipulatorGUI(IKBoneModifier rModifier)
        {
#if UNITY_EDITOR
            // Determine if the swing is changing
            if (mBone != null)
            {
                // Determine if the swing is changing
                Vector3 lSwing    = rModifier.Swing.eulerAngles;
                Vector3 lNewSwing = InspectorHelper.Vector3Fields("Swing", "Euler angles to swing the bone.", lSwing, true, true, false); //lBoneForward.x == 0f, lBoneForward.y == 0f, lBoneForward.z == 0f);
                if (lNewSwing != lSwing)
                {
                    // Grab the amount that was just rotated by based on the current rotation.
                    // We do this so the change is relative to the current swing rotation
                    Vector3 lDeltaRotations = lNewSwing - lSwing;
                    rModifier.Swing = rModifier.Swing * Quaternion.Euler(lDeltaRotations);

                    rModifier.IsDirty = true;
                }

                float lTwist    = Vector3Ext.SignedAngle(Vector3.up, rModifier.Twist * Vector3.up, Vector3.forward);
                float lNewTwist = EditorGUILayout.FloatField("Twist", lTwist);
                if (lNewTwist != lTwist)
                {
                    rModifier.Twist   = Quaternion.AngleAxis(lNewTwist, Vector3.forward);
                    rModifier.IsDirty = true;
                }

                // Reset the values if needed
                if (GUILayout.Button("reset rotation", EditorStyles.miniButton))
                {
                    rModifier.Swing   = Quaternion.identity;
                    rModifier.Twist   = Quaternion.identity;
                    rModifier.IsDirty = true;

                    mBone._Transform.localRotation = mBone._BindRotation;
                }

                if (rModifier.IsDirty)
                {
                    ApplyLimits(ref rModifier.Swing, ref rModifier.Twist);
                }
            }
#endif

            return(rModifier.IsDirty);
        }
Esempio n. 8
0
        /// <summary>
        /// Apply any rotational limits to the local rotation so it
        /// meets the constraints of this bone type
        /// </summary>
        /// <param name="rBone">Bone being processed</param>
        /// <param name="rRotation">Target local rotation of the bone to be modified</param>
        public override bool ApplyLimits(ref Quaternion rSwing, ref Quaternion rTwist)
        {
            // We may need to get rid of the twisting associated with the swing.
            if (_PreventSwingTwisting)
            {
                // Create a longitudinal axis based on the initial bone
                // direction and the current rotation. This is the "local" direction
                // of the bone relative to the bind position.
                Vector3 lTargetBoneForward = rSwing * Vector3.forward;

                // If we are preserving the the automatic twisting, we can remove it
                // by grabing the simple rotation from the start position to the new position
                rSwing = Quaternion.FromToRotation(Vector3.forward, lTargetBoneForward);
            }

            // Only process the twist if it's allowed
            if (_AllowTwist)
            {
                // Test if we should limit the twist
                if (_LimitTwist && (_MinTwistAngle > -180 || _MaxTwistAngle < 180) && !rTwist.IsIdentity())
                {
                    float lTwistAngle = Vector3Ext.SignedAngle(Vector3.up, rTwist * Vector3.up, Vector3.forward);

                    // Force the angle if it's exceeeded.
                    if (lTwistAngle > _MaxTwistAngle)
                    {
                        rTwist = Quaternion.AngleAxis(_MaxTwistAngle, Vector3.forward);
                    }
                    else if (lTwistAngle < _MinTwistAngle)
                    {
                        rTwist = Quaternion.AngleAxis(_MinTwistAngle, Vector3.forward);
                    }
                    else
                    {
                        rTwist = Quaternion.AngleAxis(lTwistAngle, Vector3.forward);
                    }
                }
            }
            else
            {
                rTwist = Quaternion.identity;
            }

            return(true);
        }
Esempio n. 9
0
        /// <summary>
        /// Calculate how much to move an rotate by
        /// </summary>
        /// <param name="rMove"></param>
        /// <param name="rRotate"></param>
        protected virtual void CalculateMove(Vector3 rWaypoint, ref Vector3 rMove, ref Quaternion rRotate)
        {
            float lDeltaTime = TimeManager.SmoothedDeltaTime;

            // Direction we need to travel in
            Vector3 lDirection = rWaypoint - transform.position;

            lDirection.Normalize();

            // Determine our rotation
            Vector3 lVerticalDirection = Vector3.Project(lDirection, transform.up);
            Vector3 lLateralDirection  = lDirection - lVerticalDirection;

            float lYawAngle = Vector3Ext.SignedAngle(transform.forward, lLateralDirection);

            if (_RotationSpeed == 0f)
            {
                rRotate = Quaternion.AngleAxis(lYawAngle, transform.up);
            }
            else
            {
                rRotate = Quaternion.AngleAxis(Mathf.Sign(lYawAngle) * Mathf.Min(Mathf.Abs(lYawAngle), _RotationSpeed * lDeltaTime), transform.up);
            }

            // Determine the movement
            float lMoveSpeed = _FastSpeed;

            if (mIsInSlowDistance && _SlowSpeed > 0f)
            {
                lMoveSpeed = _SlowSpeed;
            }

            // Set the final velocity based on the future rotation
            Quaternion lFutureRotation = transform.rotation * rRotate;

            rMove = lFutureRotation.Forward() * (lMoveSpeed * lDeltaTime);
        }
        /// <summary>
        /// Determines how close the bone is from reaching its twist limit. Values
        /// are from -1 (at min limit) to 0 (at bind angle) to 1 (at max limit).
        /// </summary>
        public override float GetTwistStress(Quaternion rLocalTwist)
        {
            if (!_AllowTwist)
            {
                return(0f);
            }
            if (!_LimitTwist)
            {
                return(0f);
            }

            // Grab the current twist angle
            float lTwistAngle = Vector3Ext.SignedAngle(Vector3.up, rLocalTwist * Vector3.up, Vector3.forward);

            // Based on the angle (and limits), determine the stress
            if (lTwistAngle == 0f)
            {
                return(0f);
            }
            else if (lTwistAngle < 0f)
            {
                if (lTwistAngle <= _MinTwistAngle)
                {
                    return(1f);
                }
                return(1f - ((_MinTwistAngle - lTwistAngle) / _MinTwistAngle));
            }
            else
            {
                if (lTwistAngle >= _MaxTwistAngle)
                {
                    return(1f);
                }
                return(1f - ((_MaxTwistAngle - lTwistAngle) / _MaxTwistAngle));
            }
        }
        /// <summary>
        /// Apply any rotational limits to the local rotation so it
        /// meets the constraints of this bone type
        /// </summary>
        /// <param name="rBone">Bone being processed</param>
        /// <param name="rRotation">Target local rotation of the bone to be modified</param>
        public override bool ApplyLimits(ref Quaternion rSwing, ref Quaternion rTwist)
        {
            //Vector3 lBoneForward = Vector3.forward; // mBone.BoneForward;

            // First thing we need to do is build our reach points based on the angles
            if (BoundaryPoints == null || BoundaryPoints.Count == 0)
            {
                ClearBoundaryPoints();
            }

            // Track whether we're in bounds
            bool lIsInLimits = (!_LimitSwing || rSwing.IsIdentity()) && (!_LimitTwist || rTwist.IsIdentity());

            // Test if we should limit the swing
            if (_LimitSwing && !rSwing.IsIdentity())
            {
                // Create a longitudinal axis based on the initial bone
                // direction and the current rotation. This is the "local" direction
                // of the bone relative to the bind position.
                Vector3 lTargetBoneForward = rSwing * Vector3.forward;

                // Determine which reach cone our bone axis is in. We shouldn't
                // get a value less than 0. If so, the reach cones could be bad.
                // For now, we'll simply move on.
                int lCurrentSliceIndex = GetReachConeIndex(lTargetBoneForward);
                if (lCurrentSliceIndex >= 0)
                {
                    // Test if we're actually valid inside the reach cone. If so,
                    // we can move on.
                    float lDot = Vector3.Dot(mReachCones[lCurrentSliceIndex].BoundaryPlane, lTargetBoneForward);
                    if (lDot >= 0)
                    {
                        lIsInLimits = true;
                        //mLastReachSliceIndex = lCurrentSliceIndex;

                        // If we are preserving the the automatic twisting, we can remove it
                        // by grabing the simple rotation from the start position to the new position
                        if (_PreventSwingTwisting)
                        {
                            rSwing = Quaternion.FromToRotation(Vector3.forward, lTargetBoneForward);
                        }
                    }
                    // If we're not in the reach cone, we need to pull the swing
                    // back so that we are.
                    else
                    {
                        Quaternion lTwist = Quaternion.identity;
                        Quaternion lSwing = Quaternion.identity;

                        // We may need to store the twisting associated with the swing. So grab it first
                        if (!_PreventSwingTwisting)
                        {
                            rSwing.DecomposeSwingTwist(Vector3.forward, ref lSwing, ref lTwist);
                        }

                        // Find the max swing rotation
                        Vector3 lCurrentBoneForward = Vector3.forward;

                        // Determine the closest intersection along the direction
                        // of old-L to new-L. This becomes the rotation we care about
                        Vector3 lNewTargetBoneForward = GetReachConeExit(lCurrentBoneForward, lTargetBoneForward);
                        rSwing = Quaternion.FromToRotation(lCurrentBoneForward, lNewTargetBoneForward);

                        // If we are aren't preventing the twist, put the twist back
                        if (!_PreventSwingTwisting)
                        {
                            rSwing = rSwing * lTwist;
                        }
                    }
                }
            }

            // Only process the twist if it's allowed
            if (_AllowTwist)
            {
                // Test if we should limit the twist
                if (_LimitTwist && (_MinTwistAngle > -180 || _MaxTwistAngle < 180) && !rTwist.IsIdentity())
                {
                    float lTwistAngle = Vector3Ext.SignedAngle(Vector3.up, rTwist * Vector3.up, Vector3.forward);

                    // Force the angle if it's exceeeded.
                    if (lTwistAngle > _MaxTwistAngle)
                    {
                        rTwist = Quaternion.AngleAxis(_MaxTwistAngle, Vector3.forward);
                    }
                    else if (lTwistAngle < _MinTwistAngle)
                    {
                        rTwist = Quaternion.AngleAxis(_MinTwistAngle, Vector3.forward);
                    }
                    else
                    {
                        rTwist = Quaternion.AngleAxis(lTwistAngle, Vector3.forward);
                    }
                }
            }
            else
            {
                rTwist = Quaternion.identity;
            }

            return(lIsInLimits);
        }
Esempio n. 12
0
        /// <summary>
        /// Called every frame so the driver can process input and
        /// update the actor controller.
        /// </summary>
        protected virtual void Update()
        {
            // Ensure we have everything we need
            if (mActorController == null)
            {
                return;
            }
            if (mInputSource == null || !mInputSource.IsEnabled)
            {
                return;
            }

            // Initialize some variables
            Vector3    lMovement = Vector3.zero;
            Quaternion lRotation = Quaternion.identity;

            // -----------------------------------------------------------------
            // INPUT
            // -----------------------------------------------------------------

            // This is the horizontal movement of the mouse or Xbox controller's right stick
            //float lYaw = mInputSource.ViewX;

            // This is the WASD buttons or Xbox controller's left stick
            Vector3 lInput = new Vector3(mInputSource.MovementX, 0f, mInputSource.MovementY);


            // -----------------------------------------------------------------
            // ATTACH TO WALL
            // -----------------------------------------------------------------
            if (mIsInToWall)
            {
                Vector3 lToWallHit       = mToWallPoint - transform.position;
                float   lToWallHitNormal = Vector3.Angle(mActorController._Transform.up, mToWallNormal);

                // Move to the target and ensure we orient ourselves to the wall
                if (lToWallHit.magnitude > 0.03f || lToWallHitNormal > 0.5f)
                {
                    mActorController.SetTargetGroundNormal(mToWallNormal);

                    lMovement = lToWallHit.normalized * Mathf.Min(MovementSpeed * Time.deltaTime, lToWallHit.magnitude);
                    mActorController.Move(lMovement);
                }
                // Once we're there, clean up
                else
                {
                    mIsInToWall   = false;
                    mToWallPoint  = Vector3.zero;
                    mToWallNormal = Vector3.zero;

                    mActorController.MaxSlopeAngle       = mSavedMaxSlopeAngle;
                    mActorController.OrientToGroundSpeed = mSavedOrientToGroundSpeed;
                    mActorController.SetTargetGroundNormal(Vector3.zero);

                    // Disable gravity temporarily
                    mActorController.IsGravityEnabled     = true;
                    mActorController.FixGroundPenetration = true;
                }
            }
            else
            {
                // -----------------------------------------------------------------
                // ROTATE
                // -----------------------------------------------------------------

                // Set the target based on the input. This works because we're looking down
                // the world's z-axis.
                if (lInput.x < 0f)
                {
                    mTargetForward = Vector3.left;
                }
                else if (lInput.x > 0f)
                {
                    mTargetForward = Vector3.right;
                }

                // If we have a target forward start rotating towards it and ignore input
                if (mTargetForward.sqrMagnitude > 0f)
                {
                    // Determine how much we need to rotate to get to the target
                    float lTargetAngle = Vector3Ext.SignedAngle(mActorController.Yaw.Forward(), mTargetForward);

                    // If there is no difference, we can turn off the target
                    if (lTargetAngle == 0f)
                    {
                        mTargetForward = Vector3.zero;
                    }
                    else
                    {
                        // Grab the actual rotation angle based on our speed. However, make sure we don't overshoot the
                        // angle. So, we do this logic to truncate it if we're only a tiny bit off.
                        float lRotationAngle = Mathf.Sign(lTargetAngle) * Mathf.Min(RotationSpeed * Time.deltaTime, Mathf.Abs(lTargetAngle));

                        // Since the rotate function deals with the actor's yaw, we just to a vector3.up (it's
                        // relative to the actor regardless of his orientation/tilt
                        lRotation = Quaternion.AngleAxis(lRotationAngle, Vector3.up);

                        // Rotate.
                        mActorController.Rotate(lRotation);
                    }
                }

                // -----------------------------------------------------------------
                // MOVE
                // -----------------------------------------------------------------

                // We get the tilt so we can add this up/down direction to the camera input. This helps
                // characters to not run off ramps since they are moving how they are facing (ie down a ramp)
                // vs. simply forward (off the ramp)
                Quaternion lTilt = QuaternionExt.FromToRotation(Vector3.up, mActorController._Transform.up);

                // Move based on WASD we add the tilt
                lMovement = lTilt * lInput * MovementSpeed * Time.deltaTime;
                mActorController.Move(lMovement);

                // -----------------------------------------------------------------
                // JUMP
                // -----------------------------------------------------------------

                // Only jump if the button is pressed and we're on the ground
                if (mInputSource.IsJustPressed("Jump"))
                {
                    if (mActorController.State.IsGrounded)
                    {
                        mActorController.AddImpulse(mActorController._Transform.up * JumpForce);
                    }
                }

                // -----------------------------------------------------------------
                // TEST FOR WALL
                // -----------------------------------------------------------------

                RaycastHit lWallHitInfo;
                if (TestForWallCollision(lMovement, out lWallHitInfo) ||
                    TestForWallAt90DegreeDrop(lMovement, out lWallHitInfo))
                {
                    // Save the tilt values
                    mIsInToWall   = true;
                    mToWallPoint  = lWallHitInfo.point;
                    mToWallNormal = lWallHitInfo.normal;

                    // Save and reset some AC values that will help us to tilt
                    mSavedOrientToGroundSpeed            = mActorController.OrientToGroundSpeed;
                    mActorController.OrientToGroundSpeed = 0.75f;

                    mSavedMaxSlopeAngle            = mActorController.MaxSlopeAngle;
                    mActorController.MaxSlopeAngle = 0f;

                    // Disable gravity temporarily
                    mActorController.IsGravityEnabled     = false;
                    mActorController.FixGroundPenetration = false;
                }
            }
        }
Esempio n. 13
0
        /// <summary>
        /// Converts the nav mesh agent data into psuedo-input that the motion controller
        /// will use to drive animations.
        /// </summary>
        protected void SimulateInput()
        {
            float lDeltaTime = TimeManager.SmoothedDeltaTime;

            // Direction we need to travel in
            Vector3 lDirection = mWaypointVector;

            lDirection.y = lDirection.y - _PathHeight;
            lDirection.Normalize();

            // Determine our view
            Vector3 lVerticalDirection = Vector3.Project(lDirection, _Transform.up);
            Vector3 lLateralDirection  = lDirection - lVerticalDirection;

            mInputFromAvatarAngle = Vector3Ext.SignedAngle(_Transform.forward, lLateralDirection);

            // Determine how much we simulate the view x. We temper it to make it smooth
            float lYawAngleAbs = Mathf.Min(Mathf.Abs(mInputFromAvatarAngle * lDeltaTime), mViewSpeedPer60FPSTick * lDeltaTime);

            if (lYawAngleAbs < EPSILON)
            {
                lYawAngleAbs = 0f;
            }

            mViewX = Mathf.Sign(mInputFromAvatarAngle) * lYawAngleAbs;

            // Determine our movement
            if (mTargetDistance > _StopDistance)
            {
                // Calculate our own slowing
                float lRelativeMoveSpeed = _NormalizedSpeed;
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    float lSlowPercent = (mTargetDistance - _StopDistance) / (_SlowDistance - _StopDistance);
                    lRelativeMoveSpeed = ((1f - _SlowFactor) * lSlowPercent) + _SlowFactor;
                }

                // TRT 4/5/2016: Force the slow distance as an absolute value
                if (mIsInSlowDistance && _SlowFactor > 0f)
                {
                    lRelativeMoveSpeed = _SlowFactor;
                }

                mMovementY = 1f * lRelativeMoveSpeed;

                mMotionController.TargetNormalizedSpeed = lRelativeMoveSpeed;
            }

            // Grab extra input information if we can
            if (mMotionController._CameraTransform == null)
            {
                mInputFromCameraAngle = mInputFromAvatarAngle;
            }
            else
            {
                Vector3 lInputForward = new Vector3(mMovementX, 0f, mMovementY);

                // We do the inverse tilt so we calculate the rotation in "natural up" space vs. "actor up" space.
                Quaternion lInvTilt = QuaternionExt.FromToRotation(_Transform.up, Vector3.up);

                // Camera forward in "natural up"
                Vector3 lCameraForward = lInvTilt * mMotionController._CameraTransform.forward;

                // Create a quaternion that gets us from our world-forward to our camera direction.
                Quaternion lToCamera = Quaternion.LookRotation(lCameraForward, lInvTilt * _Transform.up);

                // Transform joystick from world space to camera space. Now the input is relative
                // to how the camera is facing.
                Vector3 lMoveDirection = lToCamera * lInputForward;
                mInputFromCameraAngle = NumberHelper.GetHorizontalAngle(lCameraForward, lMoveDirection);
            }
        }
Esempio n. 14
0
        /// <summary>
        /// Called every frame so the driver can process input and
        /// update the actor controller.
        /// </summary>
        protected virtual void Update()
        {
            // Ensure we have everything we need
            if (mActorController == null)
            {
                return;
            }
            if (mInputSource == null || !mInputSource.IsEnabled)
            {
                return;
            }

            // Initialize some variables
            Vector3    lMovement = Vector3.zero;
            Quaternion lRotation = Quaternion.identity;

            // -----------------------------------------------------------------
            // INPUT
            // -----------------------------------------------------------------

            // This is the horizontal movement of the mouse or Xbox controller's right stick
            //float lYaw = mInputSource.ViewX;

            // This is the WASD buttons or Xbox controller's left stick
            Vector3 lInput = new Vector3(mInputSource.MovementX, 0f, mInputSource.MovementY);

            // -----------------------------------------------------------------
            // ROTATE
            // -----------------------------------------------------------------

            // Set the target based on the input. This works because we're looking down
            // the world's z-axis.
            if (lInput.x < 0f)
            {
                mTargetForward = Vector3.left;
            }
            else if (lInput.x > 0f)
            {
                mTargetForward = Vector3.right;
            }

            // If we have a target forward start rotating towards it and ignore input
            if (mTargetForward.sqrMagnitude > 0f)
            {
                // Determine how much we need to rotate to get to the target
                float lTargetAngle = Vector3Ext.SignedAngle(mActorController.Yaw.Forward(), mTargetForward);

                // If there is no difference, we can turn off the target
                if (lTargetAngle == 0f)
                {
                    mTargetForward = Vector3.zero;
                }
                else
                {
                    // Grab the actual rotation angle based on our speed. However, make sure we don't overshoot the
                    // angle. So, we do this logic to truncate it if we're only a tiny bit off.
                    float lRotationAngle = Mathf.Sign(lTargetAngle) * Mathf.Min(RotationSpeed * Time.deltaTime, Mathf.Abs(lTargetAngle));

                    // Since the rotate function deals with the actor's yaw, we just to a vector3.up (it's
                    // relative to the actor regardless of his orientation/tilt
                    lRotation = Quaternion.AngleAxis(lRotationAngle, Vector3.up);

                    // Rotate.
                    mActorController.Rotate(lRotation);
                }
            }

            // -----------------------------------------------------------------
            // MOVE
            // -----------------------------------------------------------------

            // We get the tilt so we can add this up/down direction to the camera input. This helps
            // characters to not run off ramps since they are moving how they are facing (ie down a ramp)
            // vs. simply forward (off the ramp)
            Quaternion lTilt = QuaternionExt.FromToRotation(Vector3.up, mActorController._Transform.up);

            // Move based on WASD we add the tilt
            lMovement = lTilt * lInput * MovementSpeed * Time.deltaTime;
            mActorController.Move(lMovement);

            // -----------------------------------------------------------------
            // JUMP
            // -----------------------------------------------------------------

            // Only jump if the button is pressed and we're on the ground
            if (mInputSource.IsJustPressed("Jump"))
            {
                if (mActorController.State.IsGrounded)
                {
                    mActorController.AddImpulse(mActorController._Transform.up * JumpForce);
                }
            }
        }