407 lines
19 KiB
C#
407 lines
19 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using ParadoxNotion.Design;
|
|
using PlasticPipe.PlasticProtocol.Messages;
|
|
using Reset.Core.Tools;
|
|
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 SettingValue<Vector2> moveSmoothing = new SettingValue<Vector2>(new Vector2(.5f, .5f));
|
|
public SettingValue<float> acceleration = new SettingValue<float>(5f);
|
|
public SettingValue<float> deaccerlation = new SettingValue<float>(5f);
|
|
|
|
[SliderField(0,1)]
|
|
public SettingValue<float> airDirectionDecay = new SettingValue<float>(1f); // TODO: Check default value
|
|
|
|
// Move Speed
|
|
public SettingValue<float> moveSpeed = new SettingValue<float>(15f, defaultSmoothing: 10f);
|
|
|
|
// Jumping
|
|
[ShowInInspector] public SettingValue<float> jumpPower = new SettingValue<float>(0f);
|
|
public SettingValue<float> jumpPowerDecay = new SettingValue<float>(3f); // TODO: Check default value
|
|
|
|
// Gravity
|
|
[ShowInInspector] public SettingValue<float> gravityPower = new SettingValue<float>(1f);
|
|
public SettingValue<float> gravityMax = new SettingValue<float>(8f);
|
|
public SettingValue<float> gravityAcceleration = new SettingValue<float>(1f);
|
|
public SettingValue<float> gravityScale = new SettingValue<float>(1f);
|
|
|
|
// Rotation
|
|
[ShowInInspector, SerializeReference] public Enum rotateFacing;
|
|
public SettingValue<float> rotationSpeed = new SettingValue<float>(5f);
|
|
public SettingValue<float> rotationInputBlending = new SettingValue<float>(.3f);
|
|
|
|
public object Clone(){
|
|
return MemberwiseClone();
|
|
}
|
|
}
|
|
|
|
public class ResolvedMovement{
|
|
[ShowInInspector] public UnitMovementHandler.MoveDirection moveDirection;
|
|
public float moveSpeed;
|
|
public Quaternion rotation;
|
|
public float rotationSpeed;
|
|
public float gravity;
|
|
}
|
|
|
|
public class UnitMovementHandler : MonoBehaviour{
|
|
public struct MoveDirection{
|
|
private Transform owner;
|
|
|
|
private Vector2 _moveDir; // Always local
|
|
|
|
public Vector2 World{
|
|
get => owner.TransformDirection(_moveDir);
|
|
set{
|
|
_moveDir = owner.InverseTransformDirection(value);
|
|
}
|
|
}
|
|
|
|
public Vector2 Local{
|
|
get => _moveDir;
|
|
set {
|
|
_moveDir = value;
|
|
}
|
|
}
|
|
|
|
public MoveDirection(Transform ownerTransform){
|
|
owner = ownerTransform;
|
|
_moveDir = Vector2.zero;
|
|
}
|
|
}
|
|
|
|
[ShowInInspector]
|
|
public ResolvedMovement resolvedMovement;
|
|
|
|
// class MovementFloatModifier{
|
|
// // IBuffSource source
|
|
// public float value;
|
|
// }
|
|
|
|
//
|
|
[FoldoutGroup("Final Values"), ShowInInspector, ReadOnly] private float outputSpeed;
|
|
[FoldoutGroup("Final Values"), ShowInInspector, ReadOnly] private float additionalSpeed;
|
|
[FoldoutGroup("Final Values"), ShowInInspector, ReadOnly] public Vector3 outputMoveDirection;
|
|
[FoldoutGroup("Final Values"), ShowInInspector, ReadOnly] public Vector3 additionalMoveDirection;
|
|
[FoldoutGroup("Final Values"), ShowInInspector, ReadOnly] private Quaternion outputRotation;
|
|
[FoldoutGroup("Final Values"), ShowInInspector, ReadOnly] private Quaternion specifiedRotation;
|
|
[FoldoutGroup("Final Values"), ShowInInspector, ReadOnly] private float outputRotationSpeed;
|
|
|
|
// Lerps
|
|
private float directionChangeDotLerp;
|
|
private Vector3 moveSmoothVelocityRef;
|
|
private float gravitySmoothVelocityRef;
|
|
|
|
// References
|
|
private CharacterController controller;
|
|
private PlayerControls controls;
|
|
private LockOnManager lockOnManager;
|
|
|
|
// Movement Data
|
|
[ShowInInspector, PropertyOrder(2)] public UnitMovementData data = new();
|
|
[ShowInInspector, PropertyOrder(2)] public UnitMovementData smoothing = new();
|
|
[ShowInInspector, PropertyOrder(2)] public UnitMovementData easing = new();
|
|
|
|
[HideInInspector] public UnitMovementData defaultData;
|
|
[HideInInspector] public UnitMovementData defaultSmoothing;
|
|
[HideInInspector] public UnitMovementData defaultEasing;
|
|
|
|
void Awake(){
|
|
controller = GetComponent<CharacterController>();
|
|
controls = GetComponent<PlayerControls>();
|
|
lockOnManager = GetComponent<LockOnManager>();
|
|
}
|
|
|
|
void Start(){
|
|
defaultData = (UnitMovementData)data.Clone();
|
|
defaultSmoothing = (UnitMovementData)smoothing.Clone();
|
|
defaultEasing = (UnitMovementData)easing.Clone();
|
|
|
|
resolvedMovement = new ResolvedMovement();
|
|
resolvedMovement.moveDirection = new MoveDirection(transform);
|
|
}
|
|
|
|
void Update(){
|
|
UpdateCurrentDirection();
|
|
UpdateCurrentGravity();
|
|
UpdateCurrentSpeed();
|
|
// UpdateCurrentRotation();
|
|
DoMovement();
|
|
}
|
|
|
|
// Add directly to the direction
|
|
public void AddToCurrentDirection(Vector3 inputDirection, float power){ // Old
|
|
additionalMoveDirection += inputDirection.normalized;
|
|
additionalSpeed = power;
|
|
}
|
|
|
|
public void SmoothToSpeed(float desiredSpeed, float smoothing){ // Old
|
|
additionalSpeed = Mathf.Lerp(additionalSpeed, desiredSpeed, smoothing * Time.deltaTime);
|
|
}
|
|
|
|
public void SetNewDirection(Vector3 inputDirection){ // NOTE: If smoothing desired add a default bool for smoothing maybe? // Old
|
|
additionalMoveDirection = inputDirection.Flatten(null, 0f, null);
|
|
}
|
|
|
|
public void SetNewGravity(float value){
|
|
additionalMoveDirection.y = value;
|
|
}
|
|
|
|
// Hold a new rotation to be moved to during PlayerFacingDirection.SpecifiedRotation
|
|
public void SetSpecifiedRotation(Quaternion inputRotation){ // Old
|
|
specifiedRotation = inputRotation;
|
|
}
|
|
|
|
// Blend between the current direction and an input direction, based on the current controller input
|
|
public void OverwriteDirectionFromInput(Vector2 value, float priority, float speed = Mathf.Infinity){ // Old
|
|
// Create a new direction that is the current controller input * the amount of power they should have
|
|
Vector3 dirToAdd = new Vector3(controls.rawMoveInput.x * value.x, 0f, controls.rawMoveInput.y * value.y);
|
|
|
|
// Multiply it by the current magnitude (why? i forgor)
|
|
dirToAdd *= controls.rawMoveInput.magnitude;
|
|
|
|
// Blend the existing direction into it
|
|
dirToAdd = Vector3.Lerp(outputMoveDirection, dirToAdd, priority * controls.rawMoveInput.magnitude);
|
|
|
|
// Set the new direction
|
|
outputMoveDirection = new Vector3(dirToAdd.x, outputMoveDirection.y, dirToAdd.z);
|
|
|
|
// Everthing under here is for the speed now. If it's not set do...nothing. Otherwise set it to the max value between move speed and the new speed
|
|
if (float.IsPositiveInfinity(speed)) {
|
|
return;
|
|
}
|
|
|
|
outputSpeed = Mathf.Lerp(outputSpeed, Mathf.Max(data.moveSpeed.value, speed), priority);
|
|
}
|
|
|
|
// Setting absolute to true will cause the current gravity to snap to the new gravity value.
|
|
// Keeping it false will make it apply additively to the current gravity. Both options use relativty for linear interpolation.
|
|
public void SetNewGravity(float value, float relativity, bool absolute){ // new
|
|
if (absolute){
|
|
resolvedMovement.gravity = Mathf.Lerp(resolvedMovement.gravity, value, relativity);
|
|
} else {
|
|
resolvedMovement.gravity = Mathf.Lerp(resolvedMovement.gravity, resolvedMovement.gravity + value, relativity);
|
|
}
|
|
}
|
|
|
|
// Update the direction, called every frame
|
|
private void UpdateCurrentDirection(){
|
|
// Get input value
|
|
Vector2 targetDirection = new Vector2(controls.rawMoveInput.x, controls.rawMoveInput.y);
|
|
|
|
// Deadzone
|
|
if (targetDirection.magnitude < .05f) {
|
|
targetDirection = Vector2.zero;
|
|
}
|
|
|
|
// Get current direction
|
|
Vector2 currentDirection = resolvedMovement.moveDirection.Local;
|
|
|
|
// Also need to find the dot value of the current input versus the current move direction
|
|
Vector3 slerpedValue;
|
|
Vector2 lerpedValue;
|
|
Vector2 newDirection;
|
|
|
|
float switchedDirection = Vector3.Dot(targetDirection, currentDirection);
|
|
float switchedDirectionRemapped = Mathf.Lerp(0, 1, switchedDirection);
|
|
|
|
directionChangeDotLerp = Mathf.Lerp(switchedDirection, switchedDirectionRemapped, 5f * Time.deltaTime) ; // turn that .5f into a variable
|
|
|
|
DebugOverlayDrawer.ChangeValue("Movement", "Direction Change Dot", directionChangeDotLerp);
|
|
|
|
// Smooth movement. Use deaccel smoothing if the input magnitude is lower, and accel smoothing if it's higher
|
|
// Also checks when grounded to only use Slerp on the ground
|
|
if (targetDirection.magnitude > currentDirection.magnitude) {
|
|
if (controller.isGrounded){
|
|
slerpedValue = Vector3.Slerp(currentDirection, targetDirection, data.acceleration.value * Time.deltaTime); // This used to be a slerp. If rotational movement broke this is why
|
|
|
|
// slerpedValue = Quaternion.AngleAxis(30, Vector3.up) * slerpedValue;
|
|
lerpedValue = Vector2.Lerp(currentDirection, targetDirection,data.acceleration.value * Time.deltaTime);
|
|
|
|
newDirection = Vector2.Lerp(slerpedValue, slerpedValue, directionChangeDotLerp);
|
|
// newDirection = slerpedValue;
|
|
} else {
|
|
newDirection = Vector2.Lerp(currentDirection, targetDirection, data.acceleration.value * Time.deltaTime);
|
|
}
|
|
} else {
|
|
if (controller.isGrounded){
|
|
slerpedValue = Vector3.Slerp(currentDirection, targetDirection, data.deaccerlation.value * Time.deltaTime); // This used to be a slerp. If rotational movement broke this is why
|
|
lerpedValue = Vector2.Lerp(currentDirection, targetDirection, data.deaccerlation.value * Time.deltaTime);
|
|
|
|
newDirection = Vector2.Lerp(lerpedValue, slerpedValue, directionChangeDotLerp);
|
|
} else {
|
|
newDirection = Vector2.Lerp(currentDirection, targetDirection, data.deaccerlation.value * data.airDirectionDecay.value * Time.deltaTime);
|
|
}
|
|
}
|
|
|
|
// newDirection = Vector2.MoveTowards(currentDirection, targetDirection.Rotate(-Vector2.Angle(currentDirection, targetDirection)), 2f * Time.deltaTime);
|
|
|
|
// Commit move direction
|
|
resolvedMovement.moveDirection.Local = Vector2.SmoothDamp(
|
|
resolvedMovement.moveDirection.Local,
|
|
newDirection,
|
|
ref smoothing.moveSmoothing.refVel,
|
|
smoothing.moveSmoothing.smoothing *Time.deltaTime); // TODO: Check this smoothing
|
|
|
|
resolvedMovement.moveDirection.Local = newDirection;
|
|
}
|
|
|
|
// Update the speed, called every frame
|
|
private void UpdateCurrentSpeed(){
|
|
//TODO: Is accel/deaccel ever used in this file????????
|
|
|
|
resolvedMovement.moveSpeed = Mathf.Lerp(resolvedMovement.moveSpeed, data.moveSpeed.value, data.moveSpeed.smoothing * Time.deltaTime);
|
|
}
|
|
|
|
// Update the gravity, called every frame
|
|
private void UpdateCurrentGravity(){
|
|
// Accelerate gravity
|
|
if (!controller.isGrounded){
|
|
resolvedMovement.gravity -= data.gravityAcceleration.value * Time.deltaTime;
|
|
}
|
|
|
|
// resolvedMovement.gravity = Mathf.Clamp(resolvedMovement.gravity, Mathf.NegativeInfinity, data.gravityMax.value);
|
|
|
|
// Apply a constant gravity if the player is grounded
|
|
if (controller.isGrounded) {
|
|
// resolvedMovement.gravity = -.3f;
|
|
}
|
|
|
|
// Create the final gravity value
|
|
float gravityMoveDirection = data.jumpPower.value + (Physics.gravity.y * resolvedMovement.gravity);
|
|
// resolvedMovement.gravity = data.jumpPower.value + (Physics.gravity.y * data.gravityPower.currentValue);
|
|
|
|
// Commit gravity to move direction, ignoring XZ since those are done in UpdateMovementDirection
|
|
outputMoveDirection.y = Mathf.SmoothDamp(outputMoveDirection.y, gravityMoveDirection, ref gravitySmoothVelocityRef, .1f * Time.deltaTime);
|
|
}
|
|
|
|
// Update the rotation, called every frame
|
|
private void UpdateCurrentRotation(){
|
|
// Get input value
|
|
Vector3 inputMovement = new Vector3(controls.rawMoveInput.x, 0f, controls.rawMoveInput.y);
|
|
|
|
// Switch the desired rotation based on current movement setting
|
|
switch (data.rotateFacing) {
|
|
// Just look at target
|
|
case PlayerFacingDirection.TowardsTarget:
|
|
// Look directly at the target
|
|
outputRotation = Quaternion.LookRotation(transform.position.DirectionTo(lockOnManager.mainTarget.gameObject.transform.position));
|
|
break;
|
|
case PlayerFacingDirection.Momentum:
|
|
// Look towards the current direction the agent is moving
|
|
if (inputMovement.magnitude > .05f){
|
|
outputRotation = Camera.main.transform.rotation * Quaternion.LookRotation(outputMoveDirection);
|
|
}
|
|
break;
|
|
case PlayerFacingDirection.MatchForward:
|
|
// Look towards the input direction....why??? I guess cause move direction is PlayerFacingDirection.Momentum.
|
|
if (controls.rawMoveInput.magnitude < 0.05f) { break; }
|
|
|
|
outputRotation = Camera.main.transform.rotation * Quaternion.LookRotation(inputMovement);
|
|
break;
|
|
case PlayerFacingDirection.MatchCamera:
|
|
// Look the same direction as the camera
|
|
outputRotation = Quaternion.Euler(Camera.main.transform.rotation.eulerAngles.Flatten(0, null, 0));
|
|
break;
|
|
case PlayerFacingDirection.Static:
|
|
// Don't change
|
|
outputRotation = transform.rotation;
|
|
break;
|
|
case PlayerFacingDirection.SpecifiedDirection:
|
|
// Look at an inputed rotation
|
|
outputRotation = specifiedRotation;
|
|
break;
|
|
}
|
|
|
|
// Add the current input into the created rotation
|
|
if (inputMovement.magnitude > .05){
|
|
outputRotation = Quaternion.Lerp(outputRotation, Camera.main.transform.rotation * Quaternion.LookRotation(inputMovement), data.rotationInputBlending.value);
|
|
}
|
|
|
|
// Calculate rotation speed, as in how fast the fella rotates. This value has it's own smoothing to allow for gradual increasing/decreasing of the speed till it reaches the target
|
|
outputRotationSpeed = Mathf.Lerp(outputRotationSpeed, data.rotationSpeed.value, data.rotationSpeed.smoothing * Time.deltaTime);
|
|
|
|
// Set final rotation
|
|
transform.rotation = Quaternion.Slerp(transform.rotation, outputRotation, outputRotationSpeed * Time.deltaTime).Flatten(0, null, 0);
|
|
}
|
|
|
|
// Move with default settings
|
|
public void DoMovement(){
|
|
DoMovement(resolvedMovement.moveDirection.Local, resolvedMovement.moveSpeed, data.gravityScale.value); // TODO: Gets multiplied a second time in DoMovement by gravity scale????
|
|
}
|
|
|
|
// Custom move from input
|
|
public void DoMovement(Vector2 moveDir, float speed, float gravityScale){
|
|
// Debug.Log($"moveDir: {moveDir}, agent velocity: {transform.InverseTransformDirection(controller.velocity.normalized)}");
|
|
|
|
// Seperate the different move directions. Additonal becomes it's own because it needs to be added independently of the other two
|
|
Vector2 moveXZDir = new Vector3(moveDir.x, moveDir.y);
|
|
float moveYDir = resolvedMovement.gravity;
|
|
Vector3 addDir = additionalMoveDirection;
|
|
|
|
// Add their related speeds
|
|
moveXZDir *= speed * Time.deltaTime;
|
|
moveYDir *= data.gravityScale.value * Time.deltaTime;
|
|
addDir *= additionalSpeed * Time.deltaTime;
|
|
|
|
// Construct the direction and move
|
|
Vector3 finalDir = new Vector3(moveXZDir.x, moveYDir,moveXZDir.y) ;
|
|
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);
|
|
|
|
// Decay the direction
|
|
if (inputMovement.magnitude < currentNoY.magnitude) {
|
|
additionalMoveDirection = Vector3.Slerp(additionalMoveDirection, Vector3.zero,data.acceleration.value * Time.deltaTime);
|
|
} else {
|
|
// float deaccelValue = data.deaccelerationCurve.Evaluate(inputMovement.magnitude);
|
|
additionalMoveDirection = Vector3.Lerp(additionalMoveDirection, Vector3.zero, data.deaccerlation.value * Time.deltaTime);
|
|
}
|
|
|
|
// Decay the gravity
|
|
additionalMoveDirection.y -= data.gravityPower.value;
|
|
additionalMoveDirection.y = Mathf.Max(0f, additionalMoveDirection.y);
|
|
}
|
|
|
|
private void UpdateGravityLate(){
|
|
// Decay jump power
|
|
data.jumpPower.value -= data.jumpPowerDecay.value * Time.deltaTime;
|
|
data.jumpPower.value = Mathf.Max(0f, data.jumpPower.value);
|
|
}
|
|
}
|
|
}
|
|
|