185 lines
7.6 KiB
C#
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
|
|||
|
}
|
|||
|
}
|