Dynamics/FloatDynamics.cs
using System;
using Sandbox;
namespace Andicraft.SecondOrderDynamics;
public class FloatDynamics : SecondOrderDynamics<float>
{
public float MinWrapValue = 0f;
public float MaxWrapValue = 0f;
/// <summary>
/// Tells you if the system is set to wrap the value.
/// </summary>
public bool Wrapping => !MinWrapValue.AlmostEqual( MaxWrapValue, 0.001f );
private float HalfWrap => MathF.Abs(MaxWrapValue - MinWrapValue) * 0.5f;
/// <inheritdoc/>
public FloatDynamics(float startingValue) : base(startingValue)
{
}
/// <inheritdoc/>
public FloatDynamics(Vector3 parameters, float startingValue) : base(parameters, startingValue)
{
}
/// <inheritdoc/>
public FloatDynamics(float frequency, float damping, float response, float startingValue) : base(frequency, damping, response, startingValue)
{
}
/// <inheritdoc/>
public override void Reset(float value)
{
_previousValue = value;
_currentValue = value;
_velocity = 0;
}
/// <inheritdoc/>
public override float Update(float deltaTime, float target, bool setVelocity = false, float velocity = default)
{
if (Wrapping)
{
target = Utils.Wrap(target, MinWrapValue, MaxWrapValue);
var dist = target - _currentValue;
var distOtherDir = target + HalfWrap * -1 * MathF.Sign(dist) - _currentValue;
if (MathF.Abs(distOtherDir) < MathF.Abs(dist))
{
target += HalfWrap * -1 * MathF.Sign(dist);
}
}
if (setVelocity == false)
{
velocity = (target - _previousValue) / deltaTime;
_previousValue = target;
}
var k2Stable = MathF.Max(k2, MathF.Max(deltaTime * deltaTime / 2 + deltaTime * k1 / 2, deltaTime * k1));
_currentValue += deltaTime * _velocity;
_velocity += deltaTime * (target + k3 * velocity - _currentValue - k1 * _velocity) / k2Stable;
return Wrapping ? Utils.Wrap(_currentValue, MinWrapValue, MaxWrapValue) : _currentValue;
}
}