/// <summary> /// Updates the motion over time. This is called by the controller /// every update cycle so animations and stages 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> public override void Update(float rDeltaTime, int rUpdateIndex) { mMovement = Vector3.zero; mRotation = Quaternion.identity; // Determine if the view rotation is active mForceRotationToCamera = false; if (mMotionController._InputSource.IsPressed(_RotateActionAlias)) { if (mMotionController._CameraTransform != null) { mForceRotationToCamera = true; } } // Grab the state info float lInputMax = (IsRunActive ? 1f : 0.5f); MotionState lState = mMotionController.State; // Convert the input to radial so we deal with keyboard and gamepad input the same. float lInputX = (mMotionController._InputSource.IsPressed(_StrafeLeftActionAlias) ? -1f : 0f); lInputX = lInputX + (mMotionController._InputSource.IsPressed(_StrafeRightActionAlias) ? 1f : 0f); if (mForceRotationToCamera && lInputX == 0f) { lInputX = lState.InputX; } float lInputMagnitude = Mathf.Sqrt((lInputX * lInputX) + (lState.InputY * lState.InputY)); lInputX = Mathf.Clamp(lInputX, -lInputMax, lInputMax); float lInputY = Mathf.Clamp(lState.InputY, -lInputMax, lInputMax); lInputMagnitude = Mathf.Clamp(lInputMagnitude, 0f, lInputMax); InputManagerHelper.ConvertToRadialInput(ref lInputX, ref lInputY, ref lInputMagnitude); // Smooth the input mInputX.Add(lInputX); mInputY.Add(lInputY); mInputMagnitude.Add(lInputMagnitude); // Modify the input values to add some lag mMotionController.State.InputX = mInputX.Average; mMotionController.State.InputY = mInputY.Average; mMotionController.State.InputMagnitudeTrend.Replace(mInputMagnitude.Average); // If we're meant to rotate with the camera (and OnCameraUpdate isn't already attached), do it here if (_RotateWithCamera && !(mMotionController.CameraRig is BaseCameraRig)) { OnCameraUpdated(rDeltaTime, rUpdateIndex, null); } // If we're not rotating with the camera, rotate with the input if (_RotateWithInput && !mForceRotationToCamera) { RotateUsingInput(rDeltaTime, ref mRotation); } }
/// <summary> /// Updates the motion over time. This is called by the controller /// every update cycle so animations and stages 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> public override void Update(float rDeltaTime, int rUpdateIndex) { mMovement = Vector3.zero; mRotation = Quaternion.identity; // Test if we stop sneak due to a change in stance. We do this here to transition if (mMotionController.State.AnimatorStates[mMotionLayer._AnimatorLayerIndex].MotionPhase == 0 && mMotionController._InputSource != null && mMotionController._InputSource.IsEnabled) { //if (mMotionController._InputSource.IsJustPressed(_ActionAlias)) if (mMotionController._InputSource.IsReleased(_ActionAlias)) { // We have to use the forced value our we'll change the current blend value as we transition mMotionController.ForcedInput.x = mInputX.Average; mMotionController.ForcedInput.y = mInputY.Average; mMotionController.SetAnimatorMotionPhase(mMotionLayer._AnimatorLayerIndex, PHASE_END, 0, true); } } // Grab the state info MotionState lState = mMotionController.State; // Convert the input to radial so we deal with keyboard and gamepad input the same. float lInputX = lState.InputX; float lInputY = lState.InputY; float lInputMagnitude = lState.InputMagnitudeTrend.Value; InputManagerHelper.ConvertToRadialInput(ref lInputX, ref lInputY, ref lInputMagnitude, 0.5f); // Smooth the input mInputX.Add(lInputX); mInputY.Add(lInputY); mInputMagnitude.Add(lInputMagnitude); // Use the smoothed values for input mMotionController.State.InputX = mInputX.Average; mMotionController.State.InputY = mInputY.Average; mMotionController.State.InputMagnitudeTrend.Replace(mInputMagnitude.Average); // If we're not dealing with an ootii camera rig, we need to rotate to the camera here if (_RotateWithCamera && !(mMotionController.CameraRig is BaseCameraRig)) { OnCameraUpdated(rDeltaTime, rUpdateIndex, null); } // Rotate as needed if (!_RotateWithCamera && _RotateWithInput) { RotateUsingInput(rDeltaTime, ref mRotation); } }
/// <summary> /// We smooth the input so that we don't start and stop immediately in the blend tree. That can create pops. /// </summary> protected void SmoothInput() { MotionState lState = mMotionController.State; // Convert the input to radial so we deal with keyboard and gamepad input the same. float lInputMax = (IsRunActive ? 1f : 0.5f); float lInputX = Mathf.Clamp(lState.InputX, -lInputMax, lInputMax); float lInputY = Mathf.Clamp(lState.InputY, -lInputMax, lInputMax); float lInputMagnitude = Mathf.Clamp(lState.InputMagnitudeTrend.Value, 0f, lInputMax); InputManagerHelper.ConvertToRadialInput(ref lInputX, ref lInputY, ref lInputMagnitude); // Smooth the input mInputX.Add(lInputX); mInputY.Add(lInputY); mInputMagnitude.Add(lInputMagnitude); // Modify the input values to add some lag mMotionController.State.InputX = mInputX.Average; mMotionController.State.InputY = mInputY.Average; mMotionController.State.InputMagnitudeTrend.Replace(mInputMagnitude.Average); }
/// <summary> /// Updates the motion over time. This is called by the controller /// every update cycle so animations and stages 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> public override void Update(float rDeltaTime, int rUpdateIndex) { mMovement = Vector3.zero; mRotation = Quaternion.identity; // Grab the state info MotionState lState = mMotionController.State; // Convert the input to radial so we deal with keyboard and gamepad input the same. float lInputMax = (IsRunActive ? 1f : 0.5f); float lInputX = Mathf.Clamp(lState.InputX, -lInputMax, lInputMax); float lInputY = Mathf.Clamp(lState.InputY, -lInputMax, lInputMax); float lInputMagnitude = Mathf.Clamp(lState.InputMagnitudeTrend.Value, 0f, lInputMax); InputManagerHelper.ConvertToRadialInput(ref lInputX, ref lInputY, ref lInputMagnitude); // Smooth the input mInputX.Add(lInputX); mInputY.Add(lInputY); mInputMagnitude.Add(lInputMagnitude); // Modify the input values to add some lag mMotionController.State.InputX = mInputX.Average; mMotionController.State.InputY = mInputY.Average; mMotionController.State.InputMagnitudeTrend.Replace(mInputMagnitude.Average); // If we're not dealing with an ootii camera rig, we need to rotate to the camera here if (_RotateWithCamera && !(mMotionController.CameraRig is BaseCameraRig)) { OnCameraUpdated(rDeltaTime, rUpdateIndex, null); } if (!_RotateWithCamera && _RotateWithInput) { RotateUsingInput(rDeltaTime, ref mRotation); } }
/// <summary> /// Updates the motion over time. This is called by the controller /// every update cycle so animations and stages 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> public override void Update(float rDeltaTime, int rUpdateIndex) { mRotation = Quaternion.identity; // Grab the state info MotionState lState = mMotionController.State; // Convert the input to radial so we deal with keyboard and gamepad input the same. float lInputX = lState.InputX; float lInputY = lState.InputY; float lInputMag = lState.InputMagnitudeTrend.Value; InputManagerHelper.ConvertToRadialInput(ref lInputX, ref lInputY, ref lInputMag); //, (IsRunActive ? 1f : 0.5f)); // Ensure we support the stop delay. This way, we can get out // of the blend tree with a nice transition if (lState.InputMagnitudeTrend.Value < 0.4f) { // Only set the timer if it's not set yet if (mStopTime == 0f) { mStopInput.x = mInputX.Average; mStopInput.y = mInputY.Average; mStopTime = Time.time + _StopDelay; mInputX.Clear(mStopInput.x); mInputY.Clear(mStopInput.y); mInputMagnitude.Clear(Mathf.Sqrt((mInputX.Value * mInputX.Value) + (mInputY.Value * mInputY.Value))); } } // Clear the timer else { mStopTime = 0f; } // When we're processing normally, update all the input values if (mStopTime == 0f) { mInputX.Add(lInputX); mInputY.Add(lInputY); mInputMagnitude.Add(lInputMag); } // If we've reached our stop time, it's time to stop else if (Time.time > mStopTime) { // Determine how we'll stop based on the direction if (!(mMotionLayer._AnimatorStateID == STATE_IdlePoseOut)) { mMotionController.SetAnimatorMotionPhase(mMotionLayer._AnimatorLayerIndex, PHASE_STOP, 0, true); } // If we're already stopping, we can clear our movement info. We don't want // to clear the movement before the transition our our blend tree will drop to idle else { mStopTime = 0f; mInputX.Clear(); mInputY.Clear(); mInputMagnitude.Clear(); lState.AnimatorStates[mMotionLayer._AnimatorLayerIndex].MotionPhase = 0; lState.AnimatorStates[mMotionLayer._AnimatorLayerIndex].MotionParameter = 0; } } // Modify the input values to add some lag lState.InputX = mInputX.Average; lState.InputY = mInputY.Average; lState.InputMagnitudeTrend.Replace(mInputMagnitude.Average); // Finally, set the state value mMotionController.State = lState; // If we're not dealing with an ootii camera rig, we need to rotate to the camera here if (_RotateWithCamera && !(mMotionController.CameraRig is BaseCameraRig)) { OnCameraUpdated(rDeltaTime, rUpdateIndex, null); } if (!_RotateWithCamera && _RotateWithInput) { RotateUsingInput(rDeltaTime, ref mRotation); } // Allow the base class to render debug info base.Update(rDeltaTime, rUpdateIndex); }
/// <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> /// Updates the motion over time. This is called by the controller /// every update cycle so animations and stages 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> public override void Update(float rDeltaTime, int rUpdateIndex) { mMovement = Vector3.zero; mRotation = Quaternion.identity; mNoInputElapsed = mNoInputElapsed + rDeltaTime; // If we're at the surface and grounded, we can't be going fast bool lAllowRunning = (!mSwimmerInfo.IsInShallowWater(mActorController.GroundingLayers)) && IsRunning; // Grab the state info MotionState lState = mMotionController.State; // Convert the input to radial so we deal with keyboard and gamepad input the same. float lInputX = lState.InputX; float lInputY = lState.InputY; float lInputMagnitude = lState.InputMagnitudeTrend.Value; InputManagerHelper.ConvertToRadialInput(ref lInputX, ref lInputY, ref lInputMagnitude, (lAllowRunning ? 1f : 0.5f)); // If input stops, we're going to keep our current value // and have the motion come to a smooth stop as needed if (lInputMagnitude > 0f) { mInputX.Add(lInputX); mInputY.Add(lInputY); mInputMagnitude.Add(lInputMagnitude); mNoInputElapsed = 0f; } // Use the averaged values for input lState.InputX = mInputX.Average; lState.InputY = mInputY.Average; lState.InputMagnitudeTrend.Replace(mInputMagnitude.Average); mMotionController.State = lState; // Determine how we'll stop based on the direction if (mMotionLayer._AnimatorStateID == STATE_SwimTree && mNoInputElapsed > 0.15f) { mMotionController.SetAnimatorMotionPhase(mMotionLayer._AnimatorLayerIndex, PHASE_STOP_SWIM, 0, true); } // We do this so we can re-enter the movement if needed if (mMotionLayer._AnimatorTransitionID == TRANS_SwimTree_TreadIdlePose) { mMotionController.SetAnimatorMotionPhase(mMotionLayer._AnimatorLayerIndex, 0, 0, true); } // Do a surface check to see if we're exiting the water float lWaterMovement = mSwimmerInfo.WaterSurface.position.y - mSwimmerInfo.WaterSurfaceLastPosition.y; if (mSwimmerInfo.TestExitWater(lWaterMovement)) { mMotionController.SetAnimatorMotionPhase(mMotionLayer._AnimatorLayerIndex, PHASE_STOP_IDLE, 0, true); return; } // If we're at the surface, we may need to move with the surface if (mSwimmerInfo.IsAtWaterSurface(0.5f)) { mMovement.y = mMovement.y + lWaterMovement; mSwimmerInfo.CreateRipples(mMotionController._Transform.position); } else { mSwimmerInfo.CreateUnderwaterEffect(mMotionController.Animator, HumanBodyBones.Head); } mSwimmerInfo.WaterSurfaceLastPosition = mSwimmerInfo.WaterSurface.position; // Move based on the buoyancy mMovement = mMovement + mSwimmerInfo.GetBuoyancy(rDeltaTime); // Move vertically float lAngle = 0f; if (mMotionController._InputSource != null) { float lUpSpeed = mMotionController._InputSource.GetValue(_UpAlias) * _VerticalSpeed; if (lUpSpeed != 0f) { lAngle = _MaxPitch; } if (mSwimmerInfo.IsAtWaterSurface(0f)) { lUpSpeed = 0f; } float lDownSpeed = mMotionController._InputSource.GetValue(_DownAlias) * -_VerticalSpeed; if (lDownSpeed != 0f) { lAngle = -_MaxPitch; } if (mActorController.IsGrounded) { lDownSpeed = 0f; } mMovement.y = mMovement.y + ((lUpSpeed + lDownSpeed) * rDeltaTime); } // If we're not using the keys, we may use the mouse if (_DiveWithCamera && lAngle == 0f) { float lUpSpeed = 0f; float lDownSpeed = 0f; float lAdjustedMaxPitch = _MaxPitch - 5f; float lCameraAngle = NumberHelper.GetHorizontalAngle(mMotionController._CameraTransform.forward, mMotionController._Transform.forward, mMotionController._CameraTransform.right); if (lCameraAngle > 5f) { lCameraAngle = lCameraAngle - 5f; lUpSpeed = (Mathf.Min(lCameraAngle, lAdjustedMaxPitch) / lAdjustedMaxPitch) * _VerticalSpeed; if (mSwimmerInfo.IsAtWaterSurface(0f)) { lUpSpeed = 0f; lCameraAngle = 0f; } } else if (lCameraAngle < -5f) { lCameraAngle = lCameraAngle + 5f; lDownSpeed = (Mathf.Max(lCameraAngle, -lAdjustedMaxPitch) / -lAdjustedMaxPitch) * -_VerticalSpeed; if (mActorController.IsGrounded) { lDownSpeed = 0f; lCameraAngle = 0f; } } if (lCameraAngle != 0f) { lAngle = Mathf.Clamp(lAngle + lCameraAngle, -_MaxPitch, _MaxPitch); mMovement.y = mMovement.y + ((lUpSpeed + lDownSpeed) * rDeltaTime); } } //Utilities.Debug.Log.ScreenWrite("Angle:" + lAngle.ToString("f3"), 14); // Rotate the body if we can RotateBody(-lAngle); // If we're not dealing with an ootii camera rig, we need to rotate to the camera here if (_RotateWithCamera && !(mMotionController.CameraRig is BaseCameraRig)) { OnCameraUpdated(rDeltaTime, rUpdateIndex, null); } // Rotate as needed if (!_RotateWithCamera && _RotateWithInput) { RotateUsingInput(rDeltaTime, ref mRotation); } }