using UnityEngine;
using UOP1.StateMachine;
using UOP1.StateMachine.ScriptableObjects;
///
/// This Action handles horizontal movement while in the air, keeping momentum, simulating air resistance, and accelerating towards the desired speed.
///
[CreateAssetMenu(fileName = "AerialMovement", menuName = "State Machines/Actions/Aerial Movement")]
public class AerialMovementActionSO : StateActionSO
{
public float Speed => _speed;
public float Acceleration => _acceleration;
[Tooltip("Desired horizontal movement speed while in the air")]
[SerializeField] [Range(0.1f, 100f)] private float _speed = 10f;
[Tooltip("The acceleration applied to reach the desired speed")]
[SerializeField] [Range(0.1f, 100f)] private float _acceleration = 20f;
protected override StateAction CreateAction() => new AerialMovementAction();
}
public class AerialMovementAction : StateAction
{
private new AerialMovementActionSO OriginSO => (AerialMovementActionSO)base.OriginSO;
private Protagonist _protagonist;
public override void Awake(StateMachine stateMachine)
{
_protagonist = stateMachine.GetComponent();
}
public override void OnUpdate()
{
Vector3 velocity = _protagonist.movementVector;
Vector3 input = _protagonist.movementInput;
float speed = OriginSO.Speed;
float acceleration = OriginSO.Acceleration;
SetVelocityPerAxis(ref velocity.x, input.x, acceleration, speed);
SetVelocityPerAxis(ref velocity.z, input.z, acceleration, speed);
_protagonist.movementVector = velocity;
}
private void SetVelocityPerAxis(ref float currentAxisSpeed, float axisInput, float acceleration, float targetSpeed)
{
if (axisInput == 0f)
{
if (currentAxisSpeed != 0f)
{
ApplyAirResistance(ref currentAxisSpeed);
}
}
else
{
(float absVel, float absInput) = (Mathf.Abs(currentAxisSpeed), Mathf.Abs(axisInput));
(float signVel, float signInput) = (Mathf.Sign(currentAxisSpeed), Mathf.Sign(axisInput));
targetSpeed *= absInput;
if (signVel != signInput || absVel < targetSpeed)
{
currentAxisSpeed += axisInput * acceleration * Time.deltaTime;
currentAxisSpeed = Mathf.Clamp(currentAxisSpeed, -targetSpeed, targetSpeed);
}
else
{
ApplyAirResistance(ref currentAxisSpeed);
}
}
}
private void ApplyAirResistance(ref float value)
{
float sign = Mathf.Sign(value);
value -= sign * Protagonist.AIR_RESISTANCE * Time.deltaTime;
if (Mathf.Sign(value) != sign)
value = 0;
}
}