projectEli/Assets/NeoFPS/Core/MotionGraphs/States/SwimSmoothUnderwaterState.cs

214 lines
8.9 KiB
C#
Raw Normal View History

2022-11-07 01:28:33 +00:00
#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("Swimming/Swim Underwater (Smooth)", "SwimUnderwater")]
[HelpURL("https://docs.neofps.com/manual/motiongraphref-mgs-swimsmoothunderwaterstate.html")]
public class SwimSmoothUnderwaterState : MotionGraphState
{
[SerializeField, Tooltip("The transform parameter which contains the transform of the water zone object")]
private TransformParameter m_WaterZoneParameter = null;
[SerializeField, Tooltip("The crouch hold parameter (used for flying down)")]
private SwitchParameter m_CrouchHold = null;
[SerializeField, Tooltip("The crouch hold parameter (used for flying up)")]
private SwitchParameter m_JumpHold = null;
[SerializeField, Tooltip("The top movement speed (for keyboard input or max analog input)")]
private FloatDataReference m_SwimSpeed = new FloatDataReference(5f);
[SerializeField, Tooltip("The maximum acceleration")]
private FloatDataReference m_Acceleration = new FloatDataReference(25f);
[SerializeField, Tooltip("The multiplier applied to the max movement speed and acceleration when strafing")]
private FloatDataReference m_StrafeMultiplier = new FloatDataReference(0.75f);
[SerializeField, Tooltip("The multiplier applied to the max movement speed and acceleration when moving in reverse")]
private FloatDataReference m_ReverseMultiplier = new FloatDataReference(0.5f);
[SerializeField, Tooltip("The multiplier applied to the acceleration when no input is detected")]
private FloatDataReference m_IdleMultiplier = new FloatDataReference(0.5f);
[SerializeField, Tooltip("The maximum movement speed and acceleration due to up or down input")]
private FloatDataReference m_UpDownSpeed = new FloatDataReference(1f);
private const float k_TinyValue = 0.001f;
private Transform m_WaterZoneTransform = null;
private IWaterZone m_WaterZone = null;
private Vector3 m_MotorAcceleration = Vector3.zero;
private Vector3 m_OutVelocity = Vector3.zero;
private Vector3 m_FlowAcceleration = Vector3.zero;
private Vector3 m_FlowVelocity = Vector3.zero;
public override Vector3 moveVector
{
get { return (m_OutVelocity + m_FlowVelocity) * Time.deltaTime; }
}
public override bool applyGravity
{
get { return false; }
}
public override bool applyGroundingForce
{
get { return false; }
}
public override bool ignorePlatformMove
{
get { return false; }
}
public override void OnValidate()
{
base.OnValidate();
m_SwimSpeed.ClampValue(0.1f, 50f);
m_UpDownSpeed.ClampValue(0.1f, 25f);
m_StrafeMultiplier.ClampValue(0f, 2f);
m_ReverseMultiplier.ClampValue(0f, 2f);
m_IdleMultiplier.ClampValue(0f, 1f);
m_Acceleration.ClampValue(0f, 100f);
}
public override void OnEnter()
{
base.OnEnter();
}
public override void OnExit()
{
base.OnExit();
m_MotorAcceleration = Vector3.zero;
m_OutVelocity = Vector3.zero;
m_FlowAcceleration = Vector3.zero;
m_FlowVelocity = Vector3.zero;
}
public override void Update()
{
base.Update();
// Get the water zone
if (m_WaterZoneParameter != null)
{
if (m_WaterZoneTransform != m_WaterZoneParameter.value)
{
m_WaterZoneTransform = m_WaterZoneParameter.value;
if (m_WaterZoneTransform != null)
m_WaterZone = m_WaterZoneTransform.GetComponent<IWaterZone>();
}
}
// Get movement axes
Vector3 up = characterController.up;
Vector3 right = characterController.right;
Vector3 forward = Quaternion.AngleAxis(-controller.aimController.pitch, right) * characterController.forward;
// Get up / down input
float upDown = 0f;
if (m_JumpHold != null && m_JumpHold.on)
upDown += 1f;
if (m_CrouchHold != null && m_CrouchHold.on)
upDown -= 1f;
// Get the input direction multipliers
bool idle = controller.inputMoveScale < 0.02f;
float directionMultiplier = m_IdleMultiplier.value;
if (!idle)
{
// Get the input vector
Vector2 input = controller.inputMoveDirection;
// Apply axis multipliers
input.x *= m_StrafeMultiplier.value;
if (input.y < 0f)
input.y *= m_ReverseMultiplier.value;
// Direction multiplier is new magnitude
directionMultiplier = input.magnitude;
}
// Get target input velocity
Vector3 targetVelocity = Vector3.zero;
if (!idle || upDown != 0f)
{
// Get target velocity
float topSpeed = m_SwimSpeed.value * directionMultiplier * controller.inputMoveScale;
targetVelocity += forward * (controller.inputMoveDirection.y * topSpeed);
targetVelocity += right * (controller.inputMoveDirection.x * topSpeed);
targetVelocity += up * (upDown * m_UpDownSpeed.value);
}
// Accelerate if required
float acceleration = m_Acceleration.value;
if (acceleration < k_TinyValue)
m_OutVelocity = targetVelocity;
else
{
var currentVelocity = characterController.velocity - m_FlowVelocity;
if (targetVelocity != currentVelocity)
{
// Get maximum acceleration
float maxAccel = acceleration;
// Accelerate the velocity
m_OutVelocity = Vector3.SmoothDamp(currentVelocity, targetVelocity, ref m_MotorAcceleration, 0.25f, maxAccel);
}
}
// Add water flow
if (m_WaterZone != null)
{
m_FlowVelocity = Vector3.SmoothDamp(
m_FlowVelocity,
m_WaterZone.FlowAtPosition(controller.localTransform.position + characterController.up * characterController.radius),
ref m_FlowAcceleration,
0.5f,
m_Acceleration.value
);
}
}
public override void CheckReferences(IMotionGraphMap map)
{
m_WaterZoneParameter = map.Swap(m_WaterZoneParameter);
m_CrouchHold = map.Swap(m_CrouchHold);
m_JumpHold = map.Swap(m_JumpHold);
m_SwimSpeed.CheckReference(map);
m_Acceleration.CheckReference(map);
m_StrafeMultiplier.CheckReference(map);
m_ReverseMultiplier.CheckReference(map);
m_IdleMultiplier.CheckReference(map);
m_UpDownSpeed.CheckReference(map);
base.CheckReferences(map);
}
#region SAVE / LOAD
private static readonly NeoSerializationKey k_AccelerationKey = new NeoSerializationKey("acceleration");
private static readonly NeoSerializationKey k_VelocityKey = new NeoSerializationKey("velocity");
private static readonly NeoSerializationKey k_FlowAccelerationKey = new NeoSerializationKey("flowA");
private static readonly NeoSerializationKey k_FlowVelocityKey = new NeoSerializationKey("flowV");
public override void WriteProperties(INeoSerializer writer)
{
base.WriteProperties(writer);
writer.WriteValue(k_AccelerationKey, m_MotorAcceleration);
writer.WriteValue(k_VelocityKey, m_OutVelocity);
writer.WriteValue(k_FlowAccelerationKey, m_FlowAcceleration);
writer.WriteValue(k_FlowVelocityKey, m_FlowVelocity);
}
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);
reader.TryReadValue(k_FlowAccelerationKey, out m_FlowAcceleration, m_FlowAcceleration);
reader.TryReadValue(k_FlowVelocityKey, out m_FlowVelocity, m_FlowVelocity);
}
#endregion
}
}