288 lines
13 KiB
C#
288 lines
13 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using Reset.Core.Tools;
|
|
using Sirenix.OdinInspector;
|
|
|
|
namespace Reset.Units{
|
|
public class UnitMovementHandler : MonoBehaviour{
|
|
[ShowInInspector, InlineProperty, HideLabel, FoldoutGroup("Resolved Movement", expanded: true)]
|
|
public ResolvedMovement resolvedMovement;
|
|
|
|
[HideInInspector] public Vector3 outputMoveDirection;
|
|
[HideInInspector] public Vector3 additionalMoveDirection;
|
|
|
|
// SmoothDamp Velocities
|
|
private Quaternion refVelocityRotationSpeed;
|
|
private float refVelocityAcceleration;
|
|
private float refVelocityDeacceleration;
|
|
|
|
// Smoothing Values
|
|
private float directionChangeDotLerp;
|
|
private Vector3 moveSmoothVelocityRef;
|
|
private float gravitySmoothVelocityRef;
|
|
|
|
// References
|
|
private CharacterController controller;
|
|
private PlayerControls controls;
|
|
private LockOnManager lockOnManager;
|
|
|
|
// Movement Data
|
|
[ShowInInspector, PropertyOrder(2), FoldoutGroup("Movement Data", expanded: true), InlineProperty, HideLabel] public UnitMovementData data = new();
|
|
|
|
void Awake(){
|
|
controller = GetComponent<CharacterController>();
|
|
controls = GetComponent<PlayerControls>();
|
|
lockOnManager = GetComponent<LockOnManager>();
|
|
|
|
InitAllSettings();
|
|
}
|
|
|
|
void Start(){
|
|
resolvedMovement = new ResolvedMovement{
|
|
moveDirection = new ResolvedMovement.MoveDirection(transform)
|
|
};
|
|
}
|
|
|
|
void Update(){
|
|
SmoothAllSettings();
|
|
|
|
UpdateCurrentDirection();
|
|
UpdateCurrentGravity();
|
|
UpdateCurrentSpeed();
|
|
UpdateCurrentRotation();
|
|
|
|
DoMovement();
|
|
|
|
DebugOverlayDrawer.ChangeValue("Movement", "Move Direction (Local)", resolvedMovement.moveDirection.Local);
|
|
DebugOverlayDrawer.ChangeValue("Movement", "Move Direction (World)", resolvedMovement.moveDirection.World);
|
|
}
|
|
|
|
// Update the direction, called every frame
|
|
private void UpdateCurrentDirection(){
|
|
// Get input value
|
|
Vector2 targetDirection = new Vector2(controls.rawMoveInput.x, controls.rawMoveInput.y);
|
|
|
|
targetDirection = (Camera.main.transform.rotation * targetDirection.ToVector3()).ToVector2();
|
|
|
|
// Deadzone
|
|
if (targetDirection.magnitude < .08f) {
|
|
targetDirection = Vector2.zero;
|
|
}
|
|
|
|
// Set Raw Direciton
|
|
resolvedMovement.moveDirection.RawWorld = targetDirection;
|
|
|
|
// Get current direction
|
|
Vector2 currentDirection = resolvedMovement.moveDirection.World;
|
|
|
|
// Also need to find the dot value of the current input versus the current move direction
|
|
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
|
|
Vector3 slerpedValue;
|
|
Vector2 lerpedValue;
|
|
Vector2 newDirection;
|
|
|
|
if (controller.isGrounded){
|
|
slerpedValue = Vector3.Slerp(currentDirection, targetDirection, data.softening.Value * Time.deltaTime);
|
|
lerpedValue = Vector2.Lerp(currentDirection, targetDirection, data.softening.Value * Time.deltaTime);
|
|
|
|
newDirection = Vector2.Lerp(slerpedValue, lerpedValue, directionChangeDotLerp);
|
|
} else {
|
|
newDirection = Vector2.Lerp(currentDirection, targetDirection, data.softening.Value * data.airDirectionDecay.Value * Time.deltaTime);
|
|
}
|
|
|
|
// Commit the new direction
|
|
resolvedMovement.moveDirection.World = newDirection;
|
|
}
|
|
|
|
// Update the speed, called every frame
|
|
private void UpdateCurrentSpeed(){
|
|
// ""Smooth"" the speed
|
|
float smoothedSpeed;
|
|
|
|
if (resolvedMovement.moveDirection.Local.magnitude < controls.rawMoveInput.magnitude) {
|
|
smoothedSpeed = Mathf.MoveTowards(resolvedMovement.moveSpeed, data.moveSpeed.Value, data.acceleration.Value * Time.deltaTime);
|
|
} else {
|
|
smoothedSpeed = Mathf.MoveTowards(resolvedMovement.moveSpeed, 0f, data.deacceleration.Value * Time.deltaTime);
|
|
}
|
|
|
|
// Commit the speed
|
|
resolvedMovement.moveSpeed = smoothedSpeed;
|
|
|
|
DebugOverlayDrawer.ChangeValue("Movement", "Resolved Speed", resolvedMovement.moveSpeed);
|
|
}
|
|
|
|
// Update the gravity, called every frame
|
|
private void UpdateCurrentGravity(){
|
|
// Accelerate gravity
|
|
if (!controller.isGrounded){
|
|
resolvedMovement.gravity -= data.gravityAcceleration.Value * Time.deltaTime;
|
|
}
|
|
|
|
// Create the final gravity value
|
|
float gravityMoveDirection = Physics.gravity.y * resolvedMovement.gravity;
|
|
}
|
|
|
|
// Update the rotation, called every frame
|
|
private void UpdateCurrentRotation(){
|
|
// Get input value
|
|
Vector3 inputMovement = new Vector3(controls.rawMoveInput.x, 0f, controls.rawMoveInput.y);
|
|
|
|
Quaternion targetRotation = Quaternion.identity;
|
|
// Switch the desired rotation based on current movement setting
|
|
switch (data.rotateFacing.Value) { // TODO: Check that this isn't broken
|
|
// Just look at target
|
|
case PlayerFacingDirection.TowardsTarget:
|
|
// Look directly at the target
|
|
targetRotation = 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){
|
|
targetRotation = Quaternion.LookRotation(resolvedMovement.moveDirection.RawWorld.ToVector3(), Vector3.up);
|
|
}
|
|
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; }
|
|
|
|
targetRotation = Camera.main.transform.rotation * Quaternion.LookRotation(inputMovement);
|
|
break;
|
|
case PlayerFacingDirection.MatchCamera:
|
|
// Look the same direction as the camera
|
|
targetRotation = Quaternion.Euler(Camera.main.transform.rotation.eulerAngles.Flatten(0, null, 0));
|
|
break;
|
|
case PlayerFacingDirection.Static:
|
|
// Don't change
|
|
targetRotation = transform.rotation;
|
|
break;
|
|
}
|
|
|
|
DebugOverlayDrawer.ChangeValue("Rotation", "Target Rotation", targetRotation.eulerAngles);
|
|
|
|
// Add the current input into the created rotation
|
|
if (inputMovement.magnitude > .05) {
|
|
// Quaternion inputRot = Camera.main.transform.rotation * Quaternion.LookRotation(inputMovement);
|
|
// resolvedMovement.rotation = Quaternion.RotateTowards(resolvedMovement.rotation, targetRotation, 10f);
|
|
resolvedMovement.rotation = targetRotation;
|
|
}
|
|
|
|
// Set final rotation
|
|
transform.rotation = Quaternion.Slerp(transform.rotation, resolvedMovement.rotation, data.rotationSpeed.Value * Time.deltaTime).Flatten(0, null, 0);
|
|
}
|
|
|
|
// Move with default settings
|
|
public void DoMovement(){
|
|
DoMovement(resolvedMovement.moveDirection.World, 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 = moveDir;
|
|
float moveYDir = resolvedMovement.gravity;
|
|
|
|
// Add their related speeds
|
|
moveXZDir *= speed * Time.deltaTime;
|
|
moveYDir *= data.gravityScale.Value * Time.deltaTime;
|
|
|
|
// Construct the direction and move
|
|
Vector3 finalDir = new Vector3(moveXZDir.x, moveYDir, moveXZDir.y);
|
|
controller.Move(finalDir);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
public void SetNewDirection(Vector2 value, float relativity, bool absolute){ // new
|
|
if (absolute){
|
|
resolvedMovement.moveDirection.World = Vector2.Lerp(resolvedMovement.moveDirection.World, value, relativity);
|
|
} else {
|
|
resolvedMovement.moveDirection.World = Vector2.Lerp(resolvedMovement.moveDirection.World, resolvedMovement.moveDirection.World + value, relativity);
|
|
}
|
|
}
|
|
|
|
public void SetNewRawDirection(Vector2 value, float relativity, bool absolute){ // new
|
|
if (absolute){
|
|
resolvedMovement.moveDirection.RawWorld = Vector2.Lerp(resolvedMovement.moveDirection.RawWorld, value, relativity);
|
|
} else {
|
|
resolvedMovement.moveDirection.RawWorld = Vector2.Lerp(resolvedMovement.moveDirection.RawWorld, resolvedMovement.moveDirection.RawWorld + value, relativity);
|
|
}
|
|
}
|
|
|
|
public void SetNewSpeed(float value, float relativity, bool absolute){ // new
|
|
if (absolute){
|
|
resolvedMovement.moveSpeed = Mathf.Lerp(resolvedMovement.moveSpeed, value, relativity);
|
|
} else {
|
|
resolvedMovement.moveSpeed = Mathf.Lerp(resolvedMovement.moveSpeed, resolvedMovement.moveSpeed + value, relativity);
|
|
}
|
|
}
|
|
|
|
public void SetNewRotation(Quaternion value, float relativity, bool absolute){ // new
|
|
if (absolute){
|
|
resolvedMovement.rotation = Quaternion.Lerp(resolvedMovement.rotation, value, relativity);
|
|
} else {
|
|
resolvedMovement.rotation = Quaternion.Lerp(resolvedMovement.rotation, resolvedMovement.rotation * value, relativity);
|
|
}
|
|
}
|
|
|
|
[Button("Initialize Settings", ButtonHeight = 30), PropertySpace(10,5 )]
|
|
void InitAllSettings(){
|
|
var settingsList = data.GetAllSettings();
|
|
|
|
foreach (IResettableSettingValue value in settingsList) {
|
|
value.Initialize();
|
|
value.Verify();
|
|
}
|
|
}
|
|
|
|
void SmoothAllSettings(){
|
|
var settingsList = data.GetAllSettings();
|
|
|
|
foreach (IResettableSettingValue value in settingsList) {
|
|
value.SmoothAndEase();
|
|
}
|
|
}
|
|
|
|
public void AddToCurrentDirection(Vector3 inputDirection, float power){ // Old
|
|
Debug.LogError("Using an old movement command! Switch to one of the new alternatives!");
|
|
}
|
|
|
|
public void SmoothToSpeed(float desiredSpeed, float smoothing){ // Old
|
|
Debug.LogError("Using an old movement command! Switch to one of the new alternatives!");
|
|
}
|
|
|
|
public void SetNewDirection(Vector3 inputDirection){ // NOTE: If smoothing desired add a default bool for smoothing maybe? // Old
|
|
Debug.LogError("Using an old movement command! Switch to one of the new alternatives!");
|
|
}
|
|
|
|
public void SetNewGravity(float value){
|
|
Debug.LogError("Using an old movement command! Switch to one of the new alternatives!");
|
|
}
|
|
|
|
public void SetSpecifiedRotation(Quaternion inputRotation){ // Old
|
|
Debug.LogError("Using an old movement command! Switch to one of the new alternatives!");
|
|
}
|
|
|
|
public void OverwriteDirectionFromInput(Vector2 value, float priority, float speed = Mathf.Infinity){ // Old
|
|
Debug.LogError("Using an old movement command! Switch to one of the new alternatives!");
|
|
}
|
|
}
|
|
}
|
|
|