/// <summary>
        /// Updates the motor over time. This is called by the controller
        /// every update cycle so movement can be updated.
        /// </summary>
        /// <param name="rDeltaTime">Time since the last frame (or fixed update call)</param>
        /// <param name="rUpdateIndex">Index of the update to help manage dynamic/fixed updates. [0: Invalid update, >=1: Valid update]</param>
        /// <param name="rTiltAngle">Amount of tilting the camera needs to do to match the anchor</param>
        public override CameraTransform RigLateUpdate(float rDeltaTime, int rUpdateIndex, float rTiltAngle = 0f)
        {
            bool         lSmooth      = true;
            bool         lContinue    = true;
            Vector3      lMovement    = Vector3.zero;
            IInputSource lInputSource = RigController.InputSource;

            // Camera rotation we'll use to modify the input
            Quaternion lCameraYaw = Quaternion.Euler(0f, RigController._Transform.rotation.eulerAngles.y, 0f);

            // Follow anchor logic
            if (_FollowAnchor && Anchor != null && lMovement.sqrMagnitude == 0f)
            {
                if (!_AllowDisconnect)
                {
                    mIsFollowConnected = true;
                }
                else if (_FollowAlias.Length == 0)
                {
                    mIsFollowConnected = true;
                }
                else if (_FollowAlias.Length > 0 && lInputSource != null && lInputSource.IsPressed(_FollowAlias))
                {
                    mIsFollowConnected = true;
                }

                if (mIsFollowConnected)
                {
                    lSmooth   = false;
                    lContinue = false;
                    //Vector3 lCameraPosition = RigController._Transform.position;
                    Vector3 lAnchorPosition = AnchorPosition;

                    if (_FollowFromView)
                    {
                        //float lAngle = 90f - RigController._Transform.eulerAngles.x;
                        //float lDistance = _MaxDistance / Mathf.Cos(lAngle * Mathf.Deg2Rad);
                        Vector3 lLastPositionTarget = mPositionTarget;

                        mPositionTarget = lAnchorPosition - (RigController._Transform.forward * _MaxDistance);
                        //lMovement = lNewCameraPosition - lCameraPosition;

                        if (!_FollowElevation)
                        {
                            mPositionTarget.y = lLastPositionTarget.y;
                        }
                    }
                    else
                    {
                        lMovement.x = lAnchorPosition.x - RigController._Transform.position.x;
                        lMovement.y = (_FollowElevation ? lAnchorPosition.y - RigController._Transform.position.y : 0f);
                        lMovement.z = lAnchorPosition.z - RigController._Transform.position.z;
                    }
                }
            }
            else
            {
                mPositionTarget = RigController._Transform.position;
            }

            // Grip logic
            if (_GripPan && lInputSource != null && lMovement.sqrMagnitude == 0f)
            {
                if (_GripAlias.Length == 0 || lInputSource.IsPressed(_GripAlias))
                {
                    if (lInputSource.ViewX != 0f || lInputSource.ViewY != 0f)
                    {
                        mIsFollowConnected = false;

                        if (lContinue)
                        {
                            lContinue   = false;
                            lMovement.x = lInputSource.ViewX * -mGripUnitsPerTick;
                            lMovement.z = lInputSource.ViewY * -mGripUnitsPerTick;

                            lMovement = lCameraYaw * lMovement;
                        }
                    }
                }
            }

            // Input logic
            if (_InputPan && lInputSource != null && lMovement.sqrMagnitude == 0f)
            {
                float lZ = (_ForwardAlias.Length > 0 && lInputSource.IsPressed(_ForwardAlias) ? 1f : 0f);
                lZ = lZ - (_BackAlias.Length > 0 && lInputSource.IsPressed(_BackAlias) ? 1f : 0f);

                float lX = (_RightAlias.Length > 0 && lInputSource.IsPressed(_RightAlias) ? 1f : 0f);
                lX = lX - (_LeftAlias.Length > 0 && lInputSource.IsPressed(_LeftAlias) ? 1f : 0f);

                if (lX != 0f || lZ != 0f)
                {
                    mIsFollowConnected = false;

                    if (lContinue)
                    {
                        float lMagnitude = 1f;
                        InputManagerHelper.ConvertToRadialInput(ref lX, ref lZ, ref lMagnitude);

                        lContinue   = false;
                        lMovement.x = lX;
                        lMovement.z = lZ;

                        lMovement = (lCameraYaw * lMovement) * mInputUnitsPerTick;
                    }
                }
            }

            // Edge logic
            if (_EdgePan && lMovement.sqrMagnitude == 0f)
            {
                Vector3 lEdgeMovement = Vector3.zero;

                float lScreenWidth  = Screen.width;
                float lScreenHeight = Screen.height;

                Vector3 lMousePosition = UnityEngine.Input.mousePosition;
                lMousePosition.x = Mathf.Clamp(lMousePosition.x, 0f, lScreenWidth - 1f);
                lMousePosition.y = Mathf.Clamp(lMousePosition.y, 0f, lScreenHeight - 1f);

                float lEdgePanBorder = (_EdgePanBorder > 1f ? _EdgePanBorder : 1f);

                if (lMousePosition.x < lEdgePanBorder)
                {
                    float lPercent = (lEdgePanBorder - lMousePosition.x) / lEdgePanBorder;
                    lEdgeMovement.x = -mEdgeUnitsPerTick * lPercent;
                }
                else if (lMousePosition.x >= lScreenWidth - _EdgePanBorder)
                {
                    float lPercent = (lEdgePanBorder - (lScreenWidth - 1f - lMousePosition.x)) / lEdgePanBorder;
                    lEdgeMovement.x = mEdgeUnitsPerTick * lPercent;
                }

                if (lMousePosition.y < _EdgePanBorder)
                {
                    float lPercent = (lEdgePanBorder - lMousePosition.y) / lEdgePanBorder;
                    lEdgeMovement.z = -mEdgeUnitsPerTick * lPercent;
                }
                else if (lMousePosition.y >= lScreenHeight - _EdgePanBorder)
                {
                    float lPercent = (lEdgePanBorder - (lScreenHeight - 1f - lMousePosition.y)) / lEdgePanBorder;
                    lEdgeMovement.z = mEdgeUnitsPerTick * lPercent;
                }

                if (lEdgeMovement.sqrMagnitude > 0f)
                {
                    mIsFollowConnected = false;

                    if (lContinue)
                    {
                        lContinue   = false;
                        lMovement.x = lEdgeMovement.x;
                        lMovement.z = lEdgeMovement.z;

                        lMovement = lCameraYaw * lMovement;
                    }
                }
            }

            // Set the final results and apply any bounds
            //Vector3 lNewPosition = mRigTransform.Position + lMovement;
            mPositionTarget = mPositionTarget + lMovement;

            if (_MinBounds.x != 0f || _MaxBounds.x != 0f)
            {
                mPositionTarget.x = Mathf.Clamp(mPositionTarget.x, _MinBounds.x, _MaxBounds.x);
            }

            if (_MaxBounds.y != 0f || _MaxBounds.y != 0f)
            {
                mPositionTarget.z = Mathf.Clamp(mPositionTarget.z, _MinBounds.y, _MaxBounds.y);
            }

            lMovement = (!lSmooth ? mPositionTarget : Vector3.SmoothDamp(RigController._Transform.position, mPositionTarget, ref mPositionVelocity, rDeltaTime)) - RigController._Transform.position;
            mRigTransform.Position = RigController._Transform.position + lMovement;

            mRigTransform.Rotation = RigController._Transform.rotation;

            return(mRigTransform);
        }
Exemple #2
0
        /// <summary>
        /// Called every frame to perform processing. We only use
        /// this function if it's not called by another component.
        /// </summary>
        protected void Update()
        {
            if (mAnimator == null)
            {
                return;
            }
            if (mCameraRig == null)
            {
                return;
            }
            if (Time.deltaTime == 0f)
            {
                return;
            }

            // Store the state we're in
            mStateInfo      = mAnimator.GetCurrentAnimatorStateInfo(0);
            mTransitionInfo = mAnimator.GetAnimatorTransitionInfo(0);

            if (mCameraRig.Mode == 2)
            {
                if (mStance != 2)
                {
                    mPrevStance = mStance;
                    mStance     = 2;
                }
            }
            else
            {
                if (mStance == 2)
                {
                    mStance = mPrevStance;
                }
            }

            // Determine the stance we're in
            if (mInputSource != null && mInputSource.IsPressed(KeyCode.LeftControl))
            {
                //if (mStance != 2)
                //{
                //    mPrevStance = mStance;
                //    mStance = 2;

                //    mPrevRigMode = CameraRigMode;

                //    // Start the transition process
                //    //_CameraRig.TransitionToMode(EnumCameraMode.FIRST_PERSON);
                //    CameraRigMode = EnumCameraMode.FIRST_PERSON;
                //}
            }
            else if (mStance == 2)
            {
                //mStance = mPrevStance;

                ////_CameraRig.TransitionToMode(mPrevRigMode);
                //CameraRigMode = mPrevRigMode;
            }
            else if (mInputSource != null && mInputSource.IsJustPressed(KeyCode.T))
            {
                mPrevStance = mStance;
                if (mStance == 0)
                {
                    mStance = 1;
                    ((AdventureRig)mCameraRig).AnchorOrbitsCamera = false;
                }
                else if (mStance == 1)
                {
                    mStance = 0;
                    ((AdventureRig)mCameraRig).AnchorOrbitsCamera = true;
                }

                mCameraRig.Mode = 0;
            }

            // Grab the direction and speed of the input relative to our current heading
            StickToWorldspace(this.transform, _CameraRig.transform, ref mTempState);

            // Ensure some of the other values are set correctly
            mTempState.Acceleration   = mState.Acceleration;
            mTempState.InitialHeading = mState.InitialHeading;

            // Ranged movement allows for slow forward, backwards, and strafing
            if (mStance == 2)
            {
                //CameraRigMode = EnumCameraMode.FIRST_PERSON;

                mTempState.Speed *= _TargetingStanceMovementSpeedMultiplier;

                // Change our heading if needed
                if (mTempState.Speed == 0)
                {
                    if (IsInBackwardsState)
                    {
                        mTempState.InitialHeading = 2;
                    }
                    else
                    {
                        mTempState.InitialHeading = 0;
                    }
                }
                else if (mTempState.Speed != 0 && mState.Speed == 0)
                {
                    float lInitialAngle = Mathf.Abs(mTempState.FromCameraAngle);
                    if (lInitialAngle < mForwardHeadingLimit)
                    {
                        mTempState.InitialHeading = 0;
                    }
                    else if (lInitialAngle > 180f - mBackwardsHeadingLimit)
                    {
                        mTempState.InitialHeading = 2;
                    }
                    else
                    {
                        mTempState.InitialHeading = 1;
                    }
                }

                // Ensure we're always facing forward
                //mYAxisRotationAngle = NumberHelper.GetHorizontalAngle(transform.forward, _CameraRig.transform.forward);
                //mTempState.FromAvatarAngle = 0f;
            }
            // Combat movement allows for forward, backwards, strafing, and pivoting
            else if (mStance == 1)
            {
                // Determine our initial heading
                if (mTempState.Speed == 0)
                {
                    if (IsInBackwardsState)
                    {
                        mTempState.InitialHeading = 2;
                    }
                    else
                    {
                        mTempState.InitialHeading = 0;
                    }
                }
                else if (mTempState.Speed != 0 && mState.Speed == 0)
                {
                    float lInitialAngle = Mathf.Abs(mTempState.FromCameraAngle);
                    if (lInitialAngle < mForwardHeadingLimit)
                    {
                        mTempState.InitialHeading = 0;
                    }
                    else if (lInitialAngle > 180f - mBackwardsHeadingLimit)
                    {
                        mTempState.InitialHeading = 2;
                    }
                    else
                    {
                        mTempState.InitialHeading = 1;
                    }
                }

                // Ensure if we've been heading forward that we don't allow the
                // avatar to rotate back facing the player
                if (mTempState.InitialHeading == 0)
                {
                    //CameraRigMode = EnumCameraMode.THIRD_PERSON_FOLLOW;

                    // Force the input to make us go forwards
                    if (mTempState.Speed > 0.1f && (mTempState.FromCameraAngle < -90 || mTempState.FromCameraAngle > 90))
                    {
                        mTempState.InputY = 1;
                    }

                    // If no forward rotation is allowed, this is easy
                    if (mForwardHeadingLimit == 0f)
                    {
                        mTempState.FromAvatarAngle = 0f;
                    }
                    // Respect the foward rotation limits
                    else
                    {
                        // Test if our rotation reaches the max from the camera. We use the camera since
                        // the avatar itself rotates and this limit is relative.
                        if (mTempState.FromCameraAngle < -mForwardHeadingLimit)
                        {
                            mTempState.FromCameraAngle = -mForwardHeadingLimit;
                        }
                        else if (mTempState.FromCameraAngle > mForwardHeadingLimit)
                        {
                            mTempState.FromCameraAngle = mForwardHeadingLimit;
                        }

                        // If we have reached a limit, we need to adjust the avatar angle
                        if (Mathf.Abs(mTempState.FromCameraAngle) == mForwardHeadingLimit)
                        {
                            // Flip the angle if we're crossing over the axis
                            if (Mathf.Sign(mTempState.FromCameraAngle) != Mathf.Sign(mState.FromCameraAngle))
                            {
                                mTempState.FromCameraAngle = -mTempState.FromCameraAngle;
                            }

                            // Only allow the avatar to rotate the heading limit, taking into account the angular
                            // difference between the camera and the avatar
                            mTempState.FromAvatarAngle = mTempState.FromCameraAngle + NumberHelper.GetHorizontalAngle(transform.forward, _CameraRig.transform.forward);
                        }
                    }
                }
                else if (mTempState.InitialHeading == 2)
                {
                    //CameraRigMode = EnumCameraMode.THIRD_PERSON_FIXED;

                    // Force the input to make us go backwards
                    if (mTempState.Speed > 0.1f && (mTempState.FromCameraAngle > -90 && mTempState.FromCameraAngle < 90))
                    {
                        mTempState.InputY = -1;
                    }

                    // Ensure we don't go beyond our boundry
                    if (mBackwardsHeadingLimit != 0f)
                    {
                        float lBackwardsHeadingLimit = 180f - mBackwardsHeadingLimit;

                        // Test if our rotation reaches the max from the camera. We use the camera since
                        // the avatar itself rotates and this limit is relative.
                        if (mTempState.FromCameraAngle <= 0 && mTempState.FromCameraAngle > -lBackwardsHeadingLimit)
                        {
                            mTempState.FromCameraAngle = -lBackwardsHeadingLimit;
                        }
                        else if (mTempState.FromCameraAngle >= 0 && mTempState.FromCameraAngle < lBackwardsHeadingLimit)
                        {
                            mTempState.FromCameraAngle = lBackwardsHeadingLimit;
                        }

                        // If we have reached a limit, we need to adjust the avatar angle
                        if (Mathf.Abs(mTempState.FromCameraAngle) == lBackwardsHeadingLimit)
                        {
                            // Only allow the avatar to rotate the heading limit, taking into account the angular
                            // difference between the camera and the avatar
                            mTempState.FromAvatarAngle = mTempState.FromCameraAngle + NumberHelper.GetHorizontalAngle(transform.forward, _CameraRig.transform.forward);
                        }

                        // Since we're moving backwards, we need to flip the movement angle.
                        // If we're not moving and simply finishing an animation, we don't
                        // want to rotate at all.
                        if (mTempState.Speed == 0)
                        {
                            mTempState.FromAvatarAngle = 0f;
                        }
                        else if (mTempState.FromAvatarAngle <= 0)
                        {
                            mTempState.FromAvatarAngle += 180f;
                        }
                        else if (mTempState.FromAvatarAngle > 0)
                        {
                            mTempState.FromAvatarAngle -= 180f;
                        }
                    }
                }
                else if (mTempState.InitialHeading == 1)
                {
                    //CameraRigMode = EnumCameraMode.THIRD_PERSON_FIXED;

                    // Move out of the sidestep if needed
                    if (mTempState.InputY > 0.1)
                    {
                        mTempState.InitialHeading = 0;
                    }
                    else if (mTempState.InputY < -0.1)
                    {
                        mTempState.InitialHeading = 2;
                    }

                    // We need to be able to rotate our avatar so it's facing
                    // in the direction of the camera
                    if (mTempState.InitialHeading == 1)
                    {
                        mTempState.FromCameraAngle = 0f;
                        mTempState.FromAvatarAngle = mTempState.FromCameraAngle + NumberHelper.GetHorizontalAngle(transform.forward, _CameraRig.transform.forward);
                    }
                }
            }

            // Determine the acceleration. We test this agains the 'last-last' speed so
            // that we are averaging out one frame.
            //mLastAcceleration = mAcceleration;
            mPrevState.Acceleration = mState.Acceleration;

            // Determine the trend so we can figure out acceleration
            if (mTempState.Speed == mState.Speed)
            {
                if (mSpeedTrendDirection != 0)
                {
                    mSpeedTrendDirection = 0;
                }
            }
            else if (mTempState.Speed < mState.Speed)
            {
                if (mSpeedTrendDirection != 1)
                {
                    mSpeedTrendDirection = 1;
                    if (mMecanimUpdateDelay <= 0f)
                    {
                        mMecanimUpdateDelay = 0.2f;
                    }
                }

                // Acceleration needs to stay consistant for mecanim
                mTempState.Acceleration = mTempState.Speed - mSpeedTrendStart;
            }
            else if (mTempState.Speed > mState.Speed)
            {
                if (mSpeedTrendDirection != 2)
                {
                    mSpeedTrendDirection = 2;
                    if (mMecanimUpdateDelay <= 0f)
                    {
                        mMecanimUpdateDelay = 0.2f;
                    }
                }

                // Acceleration needs to stay consistant for mecanim
                mTempState.Acceleration = mTempState.Speed - mSpeedTrendStart;
            }

            // Shuffle the states to keep us from having to reallocated
            AdventureControllerState lTempState = mPrevState;

            mPrevState = mState;
            mState     = mTempState;
            mTempState = lTempState;

            // Apply the movement and rotation
            ApplyMovement();
            ApplyRotation();

            // Delay a bit before we update the speed if we're accelerating
            // or decelerating.
            mMecanimUpdateDelay -= Time.deltaTime;
            if (mMecanimUpdateDelay <= 0f)
            {
                mAnimator.SetFloat("Speed", mState.Speed); //, 0.05f, Time.deltaTime);

                mSpeedTrendStart = mState.Speed;
            }

            // Update the direction relative to the avatar
            mAnimator.SetFloat("Avatar Direction", mState.FromAvatarAngle);

            // At this point, we never use angular speed. Rotation is done
            // in the ApplyRotation() function. Angular speed currently only effects
            // locomotion.
            mAnimator.SetFloat("Angular Speed", 0f);

            // The stance determins if we're in exploration or combat mode.
            mAnimator.SetInteger("Stance", mStance);

            // The direction from the camera
            mAnimator.SetFloat("Camera Direction", mState.FromCameraAngle); //, 0.05f, Time.deltaTime);

            // The raw input from the UI
            mAnimator.SetFloat("Input X", mState.InputX); //, 0.25f, Time.deltaTime);
            mAnimator.SetFloat("Input Y", mState.InputY); //, 0.25f, Time.deltaTime);
        }
        /// <summary>
        /// LateUpdate logic for the controller should be done here. This allows us
        /// to support dynamic and fixed update times
        /// </summary>
        /// <param name="rDeltaTime">Time since the last frame (or fixed update call)</param>
        /// <param name="rUpdateIndex">Index of the update to help manage dynamic/fixed updates. [0: Invalid update, >=1: Valid update]</param>
        public override void RigLateUpdate(float rDeltaTime, int rUpdateIndex)
        {
            // Get out if we're not in a valid update
            if (rUpdateIndex < 0)
            {
                return;
            }
            if (mInputSource == null)
            {
                return;
            }

            // Determine the linear movement
            Vector3    lMovement = Vector3.zero;
            Quaternion lRotation = _Transform.rotation;

            float lSpeed = _MoveSpeed;

            if (mInputSource.IsPressed(KeyCode.LeftShift))
            {
                lSpeed *= _FastFactor;
            }
            if (mInputSource.IsPressed(KeyCode.Space))
            {
                lSpeed *= _SlowFactor;
            }

            if (mInputSource.IsViewingActivated)
            {
                // Handle the rotations
                float lYaw         = mInputSource.ViewX;
                float lYawMovement = lYaw * mDegreesPer60FPSTick;
                mYaw = (mYaw + lYawMovement) % 360f;

                float lPitch         = mInputSource.ViewY * (_InvertPitch ? -1 : 1);
                float lPitchMovement = lPitch * mDegreesPer60FPSTick;
                mPitch = (mPitch + lPitchMovement) % 360f;

                lRotation = Quaternion.AngleAxis(mYaw, Vector3.up) * Quaternion.AngleAxis(mPitch, Vector3.right);

                // Handle the movement
                float lInputY = 0f;
                if (mInputSource.IsPressed(KeyCode.E))
                {
                    lInputY = 1f;
                }
                if (mInputSource.IsPressed(KeyCode.Q))
                {
                    lInputY = -1f;
                }

                float lInputX = 0f;
                if (mInputSource.IsPressed(KeyCode.D))
                {
                    lInputX = 1f;
                }
                if (mInputSource.IsPressed(KeyCode.A))
                {
                    lInputX = -1f;
                }

                float lInputZ = 0f;
                if (mInputSource.IsPressed(KeyCode.W))
                {
                    lInputZ = 1f;
                }
                if (mInputSource.IsPressed(KeyCode.S))
                {
                    lInputZ = -1f;
                }

                Vector3 lVelocity = new Vector3(lInputX, lInputY, lInputZ);
                lMovement = lRotation * (lVelocity * lSpeed * rDeltaTime);
            }
            // Deal with the scroll wheel
            else if (mInputSource.GetValue("Mouse ScrollWheel") != 0f)
            {
                float lInputZ = mInputSource.GetValue("Mouse ScrollWheel") * _ScrollFactor;

                Vector3 lVelocity = new Vector3(0f, 0f, lInputZ);
                lMovement = lRotation * (lVelocity * lSpeed * rDeltaTime);
            }

            if (_Anchor == null)
            {
                _Transform.rotation = lRotation;

                // Apply movement if it exists
                if (lMovement.sqrMagnitude > 0f)
                {
                    _Transform.position = _Transform.position + lMovement;
                }
            }
            else
            {
            }
        }