projectEli/Assets/NeoFPS/Core/MotionGraphs/States/AdaptiveJetpackState.cs
2022-11-06 20:28:33 -05:00

185 lines
7.6 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 NeoFPS.CharacterMotion.Parameters;
using NeoSaveGames.Serialization;
namespace NeoFPS.CharacterMotion.States
{
[MotionGraphElement("Airborne/Jetpack (Adaptive)", "Adaptive Jetpack")]
[HelpURL("https://docs.neofps.com/manual/motiongraphref-mgs-adaptivejetpackstate.html")]
public class AdaptiveJetpackState : FallingState
{
[SerializeField, Tooltip("An acceleration force (ignores mass) upwards for the jetpack.")]
private FloatDataReference m_JetpackForce = new FloatDataReference(15f);
[SerializeField, Tooltip("An optional parameter for the jetpack fuel. Will be consumed based on output.")]
private FloatParameter m_JetpackFuel = null;
[SerializeField, Tooltip("How the jetpack should work. Smooth reduces power as approaching the max vertical speed. Burst sets a minimum jetpack burst duration and gap between bursts to create a bouncier hover.")]
private JetpackMode m_Mode = JetpackMode.Smooth;
[SerializeField, Tooltip("The maximum vertical speed, at which the jetpack stops pushing upwards. A speed of zero is hovering.")]
private float m_MaxVerticalSpeed = 0f;
[SerializeField, Tooltip("A speed differential where the jetpack will switch on/off. Max + half this = off. Max - half this = on.")]
private float m_Hysteresis = 0.25f;
[SerializeField, Tooltip("The speed below the max at which jetpack power (and fuel consumption) starts to fall off. The power will fade out exponentially the closer you get to the max speed.")]
private float m_SpeedFalloff = 10f;
[SerializeField, Tooltip("The amount of fuel burned per second at full burn.")]
private float m_FuelBurnRate = 0.5f;
[SerializeField, Range(0f, 1f), Tooltip("A damping amount for the fuel consumption to smooth it out. Set to zero for direct feedback.")]
private float m_FuelDamping = 0.25f;
[SerializeField, Tooltip("The fuel burn rate when at the target speed, as opposed to accelerating towards it.")]
private float m_MinFuelBurn = 0.25f;
private Vector3 m_JetpackVelocity = Vector3.zero;
private bool m_Firing = false;
private float m_FuelConsumption = 0f;
enum JetpackMode
{
Smooth,
Burst
// Could add more modes later
}
public override bool completed
{
get { return false; }
}
public override Vector3 moveVector
{
get { return base.moveVector + (m_JetpackVelocity * Time.deltaTime); }
}
public override void OnValidate()
{
base.OnValidate();
m_MaxVerticalSpeed = Mathf.Clamp(m_MaxVerticalSpeed, -50f, 100f);
m_Hysteresis = Mathf.Clamp(m_Hysteresis, 0.01f, 5f);
m_MinFuelBurn = Mathf.Clamp(m_MinFuelBurn, 0f, m_FuelBurnRate);
}
public override void OnExit()
{
base.OnExit();
m_JetpackVelocity = Vector3.zero;
}
public override void Update()
{
base.Update();
float force = m_JetpackForce.value;
//if (m_JetpackPower != null)
// force *= m_JetpackPower.value;
switch (m_Mode)
{
case JetpackMode.Smooth:
{
// Get upSpeed
float upSpeed = Vector3.Dot(fallVelocity, characterController.up);
// Get the falloff based on speed
float falloff = Mathf.Clamp01((m_MaxVerticalSpeed - upSpeed) / m_SpeedFalloff);
falloff = EasingFunctions.EaseOutQuadratic(falloff);
// Calculate velocity
m_JetpackVelocity = characterController.up * force * falloff * Time.deltaTime;
if (falloff > 0f)
m_JetpackVelocity += characterController.gravity * -Time.deltaTime;
// Burn fuel
if (m_JetpackFuel != null)
{
float fuelBurn = Mathf.Lerp(m_MinFuelBurn, m_FuelBurnRate, falloff);
float fuel = m_JetpackFuel.value;
fuel -= fuelBurn * Time.deltaTime;
if (fuel < 0f)
fuel = 0f;
m_JetpackFuel.value = fuel;
}
}
break;
case JetpackMode.Burst:
{
// Get upSpeed
//Vector3 fallWithGravity = fallVelocity + characterController.gravity * Time.deltaTime;
float upSpeed = Vector3.Dot(fallVelocity, characterController.up);
// Check hysteresis
float halfHysteresis = m_Hysteresis * 0.5f;
if (upSpeed > m_MaxVerticalSpeed + halfHysteresis)
m_Firing = false;
if (upSpeed < m_MaxVerticalSpeed - halfHysteresis)
m_Firing = true;
float targetFuelConsumption = 0f;
// Calculate the movement
if (m_Firing)
{
m_JetpackVelocity = (characterController.up * force * Time.deltaTime);
targetFuelConsumption = 1f;
}
else
m_JetpackVelocity = Vector3.zero;
// Burn fuel
if (m_JetpackFuel != null)
{
float fuelDamp = 1f - m_FuelDamping;
fuelDamp = fuelDamp * fuelDamp * fuelDamp;
fuelDamp = 0.1f + fuelDamp * 0.9f;
m_FuelConsumption = Mathf.Lerp(m_FuelConsumption, targetFuelConsumption, fuelDamp);
float fuel = m_JetpackFuel.value;
fuel -= m_FuelConsumption * m_FuelBurnRate * Time.deltaTime;
if (fuel < 0f)
fuel = 0f;
m_JetpackFuel.value = fuel;
}
}
break;
}
//|| Vector3.Dot(fallVelocity, characterController.up) < m_MaxVerticalSpeed)
// Calculate jetpack velocity
//m_JetpackVelocity = (characterController.up * force * Time.deltaTime);
}
public override void CheckReferences(IMotionGraphMap map)
{
m_JetpackForce.CheckReference(map);
m_JetpackFuel = map.Swap(m_JetpackFuel);
base.CheckReferences(map);
}
#region SAVE / LOAD
private static readonly NeoSerializationKey k_JetpackVelocityKey = new NeoSerializationKey("jetpackV");
public override void WriteProperties(INeoSerializer writer)
{
base.WriteProperties(writer);
writer.WriteValue(k_JetpackVelocityKey, m_JetpackVelocity);
}
public override void ReadProperties(INeoDeserializer reader)
{
base.ReadProperties(reader);
reader.TryReadValue(k_JetpackVelocityKey, out m_JetpackVelocity, m_JetpackVelocity);
}
#endregion
}
}