You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
4.6 KiB
C#
163 lines
4.6 KiB
C#
using System;
|
|
|
|
namespace Otter {
|
|
/// <summary>
|
|
/// Component that will slowly interpolate a value toward a target using a speed and acceleration.
|
|
/// This component can move the value and does not know about time at all.
|
|
/// </summary>
|
|
public class Lerper : Component {
|
|
|
|
#region Private Fields
|
|
|
|
float initValue, targetSpeed, speed, distance;
|
|
|
|
bool endPhase = false;
|
|
|
|
#endregion
|
|
|
|
#region Public Fields
|
|
|
|
/// <summary>
|
|
/// The acceleration for moving toward the target.
|
|
/// </summary>
|
|
public float Acceleration;
|
|
|
|
/// <summary>
|
|
/// The maximum speed for moving toward the target.
|
|
/// </summary>
|
|
public float MaxSpeed;
|
|
|
|
#endregion
|
|
|
|
#region Public Properties
|
|
|
|
/// <summary>
|
|
/// If the Lerper has completed its movement.
|
|
/// </summary>
|
|
public bool Completed { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The current target to move toward.
|
|
/// </summary>
|
|
public float Target { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The current value.
|
|
/// </summary>
|
|
public float Value { get; private set; }
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
/// <summary>
|
|
/// Create a new Lerper.
|
|
/// </summary>
|
|
/// <param name="value">The initial value.</param>
|
|
/// <param name="accel">The acceleration for moving toward the target.</param>
|
|
/// <param name="maxSpeed">The max speed for moving toward the target.</param>
|
|
public Lerper(float value, float accel, float maxSpeed) {
|
|
initValue = value;
|
|
Value = value;
|
|
Acceleration = accel;
|
|
MaxSpeed = maxSpeed;
|
|
Completed = false;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Set the target.
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
public void SetTarget(float value) {
|
|
if (Target == value) return;
|
|
|
|
Target = value;
|
|
|
|
initValue = Value;
|
|
endPhase = false;
|
|
Completed = false;
|
|
distance = Math.Abs(initValue - Target);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Force the current value.
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
public void SetValue(float value) {
|
|
Value = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update the Lerper.
|
|
/// </summary>
|
|
public override void Update() {
|
|
base.Update();
|
|
|
|
if (Completed) {
|
|
Value = Target;
|
|
return;
|
|
}
|
|
|
|
var currentDistance = Math.Abs(Target - Value);
|
|
var stoppingDistance = (MaxSpeed * MaxSpeed) / (2 * Acceleration);
|
|
var earlyStopDistance = (speed * speed) / (2 * Acceleration);
|
|
|
|
if (!endPhase) {
|
|
targetSpeed = MaxSpeed * Math.Sign(Target - Value);
|
|
|
|
if (currentDistance <= stoppingDistance) {
|
|
if (speed == MaxSpeed) {
|
|
targetSpeed = 0;
|
|
endPhase = true;
|
|
}
|
|
if (speed < MaxSpeed) {
|
|
if (currentDistance <= earlyStopDistance) {
|
|
targetSpeed = 0;
|
|
endPhase = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
speed = Util.Approach(speed, targetSpeed, Acceleration);
|
|
|
|
if (endPhase) {
|
|
if (Target > Value) {
|
|
if (speed < Acceleration) speed = Acceleration;
|
|
Value = Util.Approach(Value, Target, speed);
|
|
}
|
|
if (Target < Value) {
|
|
if (speed > -Acceleration) speed = -Acceleration;
|
|
Value = Util.Approach(Value, Target, -speed);
|
|
}
|
|
}
|
|
else {
|
|
Value += speed;
|
|
}
|
|
|
|
if (currentDistance <= Acceleration * 5) {
|
|
speed = 0;
|
|
Completed = true;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Operators
|
|
|
|
public static implicit operator float(Lerper lerper) {
|
|
return lerper.Value;
|
|
}
|
|
public static implicit operator int(Lerper lerper) {
|
|
return (int)lerper.Value;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|