using System; using System.Collections.Generic; using UnityEngine; using Drawing; using Reset.Movement; using Sirenix.OdinInspector; public enum PlayerFacingDirection{ TowardsTarget = 0, MatchForward, MatchCamera, Static, Momentum, SpecifiedDirection } namespace Reset.Units{ // public interface IBuffSource{ - Unused good idea? // public Object sourceObject(); // public // } [Serializable] public class UnitMovementData : ICloneable{ // Movement Direction public float accelerationSmoothing = 5f; public float deaccelerationSmoothing = 5f; public AnimationCurve deaccelerationCurve; // Move Speed public float moveSpeedTarget = 15f; public float moveSpeedSoothing = 10f; // Jumping [ShowInInspector, ReadOnly] public float jumpPower; public float jumpPowerDecay = 3f; // Gravity [ShowInInspector, ReadOnly] public float gravityPower; public float gravityMax = 8f; public float gravityAcceleration = 1f; public float gravityScale = 1f; // Rotation [ShowInInspector, SerializeReference] public Enum rotateFacing; public float rotationSpeedTarget = 5f; public float rotationSmoothing = 1f; public object Clone(){ return this.MemberwiseClone(); } } public class UnitMovementHandler : MonoBehaviour{ // class MovementFloatModifier{ // // IBuffSource source // public float value; // } // Debug viewing // Smoothed Values [ShowInInspector, ReadOnly] private float outputSpeed; [ShowInInspector, ReadOnly] private float additionalSpeed; [ShowInInspector, ReadOnly] private Vector3 outputMoveDirection; [ShowInInspector, ReadOnly] private Vector3 additionalMoveDirection; [ShowInInspector, ReadOnly] private Quaternion outputRotation; [ShowInInspector, ReadOnly] private Quaternion specifiedRotation; [ShowInInspector, ReadOnly] private float outputRotationSpeed; private CharacterController controller; public PlayerControls controls; [ShowInInspector, PropertyOrder(2)] public UnitMovementData data = new UnitMovementData(); [HideInInspector] public UnitMovementData defaultData; [Button, PropertyOrder(1)] void ResetMovementData(){ data = new UnitMovementData(); } void Awake(){ controller = GetComponent(); } private void Start(){ defaultData = (UnitMovementData)data.Clone(); } void Update(){ UpdateCurrentDirection(); UpdateCurrentSpeed(); UpdateCurrentGravity(); UpdateCurrentRotation(); DoMovement(); } public void AddToCurrentDirection(Vector3 inputDirection, float power){ additionalMoveDirection += inputDirection.normalized; additionalSpeed = power; } public void SetSpecifiedRotation(Quaternion inputRotation){ specifiedRotation = inputRotation; } private void UpdateCurrentDirection(){ // Get input value Vector3 inputMovement = new Vector3(controls.rawMoveInput.x, 0f, controls.rawMoveInput.y); // Construct move direction Vector3 targetDirection = inputMovement; if (inputMovement.magnitude < .1f) { targetDirection = Vector3.zero; } // Remove Y from variables Vector3 targetNoY = new Vector3(targetDirection.x, 0f, targetDirection.z); Vector3 currentNoY = new Vector3(outputMoveDirection.x, 0f, outputMoveDirection.z); // Smooth movement if (targetNoY.magnitude > currentNoY.magnitude) { currentNoY = Vector3.Slerp(currentNoY, targetNoY,data.accelerationSmoothing * Time.deltaTime); } else { // float deaccelValue = data.deaccelerationCurve.Evaluate(inputMovement.magnitude); currentNoY = Vector3.Lerp(currentNoY, targetNoY, data.deaccelerationSmoothing * Time.deltaTime); } // Commit move direction outputMoveDirection = new Vector3(currentNoY.x, outputMoveDirection.y, currentNoY.z); } private void UpdateCurrentSpeed(){ outputSpeed = Mathf.Lerp(outputSpeed, data.moveSpeedTarget, data.moveSpeedSoothing * Time.deltaTime); } private void UpdateCurrentGravity(){ // Accelerate gravity data.gravityPower += data.gravityAcceleration * Time.deltaTime; data.gravityPower = Mathf.Min(data.gravityPower, data.gravityMax); // Apply a constant gravity if the player is grounded if (controller.isGrounded) { data.gravityPower = .1f; } // Create the final gravity value float gravityMoveDirection = data.jumpPower + (Physics.gravity.y * data.gravityPower); // Commit gravity to move direction, ignoring XZ since those are done in UpdateMovementDirection outputMoveDirection.y = gravityMoveDirection; } private void UpdateCurrentRotation(){ // Get input value Vector3 inputMovement = new Vector3(controls.rawMoveInput.x, 0f, controls.rawMoveInput.y); switch (data.rotateFacing) { // TODO: Recomment case PlayerFacingDirection.TowardsTarget: Debug.LogError("Not implemented..."); break; case PlayerFacingDirection.Momentum: if (inputMovement.magnitude > .03f){ outputRotation = Camera.main.transform.rotation * Quaternion.LookRotation(outputMoveDirection); } break; case PlayerFacingDirection.MatchForward: if (controls.rawMoveInput.magnitude < 0.01f) { break; } outputRotation = Camera.main.transform.rotation * Quaternion.LookRotation(inputMovement); break; case PlayerFacingDirection.MatchCamera: outputRotation = Quaternion.Euler(Camera.main.transform.rotation.eulerAngles.Flatten(0, null, 0)); break; case PlayerFacingDirection.Static: outputRotation = transform.rotation; break; case PlayerFacingDirection.SpecifiedDirection: outputRotation = specifiedRotation; break; } // Calculate rotation speed outputRotationSpeed = Mathf.Lerp(outputRotationSpeed, data.rotationSpeedTarget, data.rotationSmoothing * Time.deltaTime); // Set final rotation transform.rotation = Quaternion.Lerp(transform.rotation, outputRotation, outputRotationSpeed * Time.deltaTime).Flatten(0, null, 0); } public void DoMovement(){ DoMovement(outputMoveDirection, outputSpeed, data.gravityScale); } public void DoMovement(Vector3 moveDir, float speed, float gravity){ // Commit the move, with respect to the camera's rotation Vector3 moveXZDir = new Vector3(moveDir.x, 0f, moveDir.z); Vector3 moveYDir = new Vector3(0f, moveDir.y, 0f); Vector3 addDir = additionalMoveDirection; moveXZDir *= speed * Time.deltaTime; moveYDir *= gravity * Time.deltaTime; addDir *= additionalSpeed * Time.deltaTime; Vector3 finalDir = moveXZDir + moveYDir; controller.Move((Camera.main.transform.rotation.Flatten(0, null, 0) * finalDir) + addDir); } void LateUpdate(){ UpdateGravityLate(); DecayAdditionalDirection(); } void DecayAdditionalDirection(){ // Get input value Vector3 inputMovement = new Vector3(controls.rawMoveInput.x, 0f, controls.rawMoveInput.y); // Ignore values under deadzone if (inputMovement.magnitude < .1f) { inputMovement = Vector3.zero; } // Remove Y from variables Vector3 currentNoY = new Vector3(additionalMoveDirection.x, 0f, additionalMoveDirection.z); if (inputMovement.magnitude < currentNoY.magnitude) { additionalMoveDirection = Vector3.Slerp(additionalMoveDirection, Vector3.zero,data.accelerationSmoothing * Time.deltaTime); } else { // float deaccelValue = data.deaccelerationCurve.Evaluate(inputMovement.magnitude); additionalMoveDirection = Vector3.Lerp(additionalMoveDirection, Vector3.zero, data.deaccelerationSmoothing * Time.deltaTime); } } private void UpdateGravityLate(){ // Decay jump power data.jumpPower -= data.jumpPowerDecay * Time.deltaTime; data.jumpPower = Mathf.Max(0f, data.jumpPower); } public void AssignNewData(UnitMovementData movementData){ data = (UnitMovementData)movementData.Clone(); } } }