186 lines
7.2 KiB
C#
186 lines
7.2 KiB
C#
#if !NEOFPS_FORCE_QUALITY && (UNITY_ANDROID || UNITY_IOS || UNITY_TIZEN || (UNITY_WSA && NETFX_CORE) || NEOFPS_FORCE_LIGHTWEIGHT)
|
|
#define NEOFPS_LIGHTWEIGHT
|
|
#endif
|
|
|
|
using UnityEngine;
|
|
using NeoFPS.CharacterMotion.MotionData;
|
|
using NeoSaveGames.Serialization;
|
|
|
|
namespace NeoFPS.CharacterMotion.States
|
|
{
|
|
[MotionGraphElement("Airborne/Falling", "Falling")]
|
|
[HelpURL("https://docs.neofps.com/manual/motiongraphref-mgs-fallingstate.html")]
|
|
public class FallingState : MotionGraphState
|
|
{
|
|
[SerializeField, Tooltip("The input driven acceleration while falling.")]
|
|
private FloatDataReference m_HorizontalAcceleration = new FloatDataReference(50f);
|
|
|
|
[SerializeField, Tooltip("The top horizontal movement speed (for keyboard input or max analog input)")]
|
|
private FloatDataReference m_TopSpeed = new FloatDataReference(5f);
|
|
|
|
[SerializeField, Tooltip("The multiplier applied to the max movement speed when strafing")]
|
|
private FloatDataReference m_StrafeMultiplier = new FloatDataReference(0.75f);
|
|
|
|
[SerializeField, Tooltip("The multiplier applied to the max movement speed when moving in reverse")]
|
|
private FloatDataReference m_ReverseMultiplier = new FloatDataReference(0.5f);
|
|
|
|
[SerializeField, Tooltip("A drag acceleration applied to horizontal movement")]
|
|
private FloatDataReference m_HorizontalDrag = new FloatDataReference(0f);
|
|
|
|
[SerializeField, Tooltip("Should the speed of the character decelerate to top speed")]
|
|
private bool m_ClampSpeed = false;
|
|
|
|
[SerializeField, Range(0f, 1f), Tooltip("The amount of damping to apply when changing direction")]
|
|
private float m_Damping = 0.25f;
|
|
|
|
private const float k_TinyValue = 0.001f;
|
|
|
|
private Vector3 m_MotorAcceleration = Vector3.zero;
|
|
private Vector3 m_OutVelocity = Vector3.zero;
|
|
|
|
protected Vector3 fallVelocity
|
|
{
|
|
get { return m_OutVelocity; }
|
|
}
|
|
|
|
public override bool applyGroundingForce
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public override Vector3 moveVector
|
|
{
|
|
get { return m_OutVelocity * Time.deltaTime; }
|
|
}
|
|
|
|
public override bool ignorePlatformMove
|
|
{
|
|
get { return true; }
|
|
}
|
|
|
|
public override void OnValidate()
|
|
{
|
|
base.OnValidate();
|
|
m_HorizontalAcceleration.ClampValue(0f, 1000f);
|
|
m_TopSpeed.ClampValue(0f, 1f);
|
|
m_StrafeMultiplier.ClampValue(0f, 1f);
|
|
m_ReverseMultiplier.ClampValue(0f, 1f);
|
|
}
|
|
|
|
public override void OnEnter()
|
|
{
|
|
base.OnEnter();
|
|
m_MotorAcceleration = Vector3.zero;
|
|
m_OutVelocity = characterController.velocity;
|
|
}
|
|
|
|
public override void OnExit()
|
|
{
|
|
base.OnExit();
|
|
m_OutVelocity = Vector3.zero;
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
|
|
// Update the current velocity (Note: The y value is handled by the standard gravity calculations in the parent mover)
|
|
Vector3 up = characterController.up;
|
|
Vector3 upVelocity = up * Vector3.Dot(characterController.velocity, up);
|
|
Vector3 hVelocity = characterController.velocity - upVelocity;
|
|
|
|
float topSpeed = m_TopSpeed.value;
|
|
float directionMultiplier = 1f;
|
|
Vector3 targetVelocity = hVelocity;
|
|
|
|
if (controller.inputMoveScale < k_TinyValue)
|
|
{
|
|
// clamp speed
|
|
if (m_ClampSpeed)
|
|
targetVelocity = Vector3.ClampMagnitude(targetVelocity, topSpeed);
|
|
}
|
|
else
|
|
{
|
|
// Calculate speed based on move direction
|
|
if (controller.inputMoveDirection.y < 0f)
|
|
directionMultiplier *= Mathf.Lerp(1f, m_ReverseMultiplier.value, -controller.inputMoveDirection.y);
|
|
directionMultiplier *= Mathf.Lerp(1f, m_StrafeMultiplier.value, Mathf.Abs(controller.inputMoveDirection.x));
|
|
|
|
// Get the input based move direction
|
|
Vector3 direction = characterController.forward * controller.inputMoveDirection.y;
|
|
direction += characterController.right * controller.inputMoveDirection.x;
|
|
|
|
// Get the target speed based on the input & current speed in the desired direction
|
|
float inputSpeed = topSpeed * controller.inputMoveScale * directionMultiplier;
|
|
float alignedSpeed = Vector3.Dot(hVelocity, direction);
|
|
|
|
// Clamp top speed
|
|
if (m_ClampSpeed && alignedSpeed > topSpeed)
|
|
alignedSpeed = topSpeed;
|
|
|
|
// Get the target vector
|
|
targetVelocity = direction * Mathf.Max(inputSpeed, alignedSpeed);
|
|
}
|
|
|
|
// Apply drag
|
|
if (m_HorizontalDrag.value > k_TinyValue)
|
|
{
|
|
float dragMultiplier = Mathf.Clamp01(1f - (m_HorizontalDrag.value * Time.deltaTime));
|
|
targetVelocity *= dragMultiplier;
|
|
}
|
|
|
|
// Change velocity
|
|
float hAcceleration = m_HorizontalAcceleration.value;
|
|
if (hAcceleration < k_TinyValue)
|
|
{
|
|
// Don't use acceleration (instant)
|
|
m_OutVelocity = targetVelocity;
|
|
}
|
|
else
|
|
{
|
|
// Accelerate if required
|
|
if (targetVelocity != hVelocity)
|
|
{
|
|
// Get maximum acceleration
|
|
float maxAccel = hAcceleration * directionMultiplier;
|
|
// Accelerate the velocity
|
|
m_OutVelocity = Vector3.SmoothDamp(hVelocity, targetVelocity, ref m_MotorAcceleration, Mathf.Lerp(0.05f, 0.25f, m_Damping), maxAccel);
|
|
}
|
|
}
|
|
|
|
// Set the local vertical to match the previous velocity
|
|
m_OutVelocity = Vector3.ProjectOnPlane(m_OutVelocity, up);
|
|
m_OutVelocity += upVelocity;
|
|
}
|
|
|
|
public override void CheckReferences(IMotionGraphMap map)
|
|
{
|
|
base.CheckReferences(map);
|
|
m_TopSpeed.CheckReference(map);
|
|
m_StrafeMultiplier.CheckReference(map);
|
|
m_ReverseMultiplier.CheckReference(map);
|
|
m_HorizontalAcceleration.CheckReference(map);
|
|
}
|
|
|
|
#region SAVE / LOAD
|
|
|
|
private static readonly NeoSerializationKey k_AccelerationKey = new NeoSerializationKey("acceleration");
|
|
private static readonly NeoSerializationKey k_VelocityKey = new NeoSerializationKey("velocity");
|
|
|
|
public override void WriteProperties(INeoSerializer writer)
|
|
{
|
|
base.WriteProperties(writer);
|
|
writer.WriteValue(k_AccelerationKey, m_MotorAcceleration);
|
|
writer.WriteValue(k_VelocityKey, m_OutVelocity);
|
|
}
|
|
|
|
public override void ReadProperties(INeoDeserializer reader)
|
|
{
|
|
base.ReadProperties(reader);
|
|
reader.TryReadValue(k_AccelerationKey, out m_MotorAcceleration, m_MotorAcceleration);
|
|
reader.TryReadValue(k_VelocityKey, out m_OutVelocity, m_OutVelocity);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |