Files
project-reset/Assets/Scripts/Player/UnitMovementHandler.cs

258 lines
9.4 KiB
C#

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<CharacterController>();
}
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();
}
}
}