/// <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); }
/// <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 { } }