using System;
using UnityEngine;
namespace Framework.Support {
/// Integrates position and velocity using the Runge Kutta 4 method
public struct RungeKutta4 {
#region struct State
/// Stores the current state of the system
private struct State {
/// Position of the object
public Vector3 Position;
/// Velocity the object is moving at
public Vector3 Velocity;
}
#endregion // struct State
#region struct Derivative
/// Stores the derivative state of the system
private struct Derivative {
/// Velocity of the object
public Vector3 Velocity;
/// Acceleration the object's velocity is increasing at
public Vector3 Acceleration;
}
#endregion // struct Derivative
/// Performs one Runge Kutta 4 simulation step
/// Velocity of the object
/// Acceleration of the object at (t + dt)
/// Amount of time that will be simulated
/// The translation of the object after the specified delta time
public Vector3 Step(ref Vector3 velocity, Vector3 acceleration, float deltaTime) {
var state = new State();
state.Position = Vector3.zero;
state.Velocity = velocity;
this.acceleration = acceleration;
integrate(ref state, deltaTime);
velocity = state.Velocity;
return state.Position;
}
/// Integrates the state over the specified delta time
/// State that will be integrated
/// Amount of time that has passed
private void integrate(ref State state, float deltaTime) {
Derivative a, b, c, d;
a = evaluate(state, 0.0f, new Derivative());
b = evaluate(state, deltaTime * 0.5f, a);
c = evaluate(state, deltaTime * 0.5f, b);
d = evaluate(state, deltaTime, c);
Vector3 velocity = (
1.0f / 6.0f * (a.Velocity + 2.0f * (b.Velocity + c.Velocity) + d.Velocity)
);
Vector3 acceleration = (
1.0f / 6.0f * (a.Acceleration + 2.0f * (b.Acceleration + c.Acceleration) + d.Acceleration)
);
state.Position += velocity * deltaTime;
state.Velocity += acceleration * deltaTime;
}
/// Linearly integrates a single state over the specified time
/// State at the beginning of the simulation
/// Amount of time that should be simulated
/// Derivative describing how the state changes
/// The state after the specified amount of time has passed
private Derivative evaluate(State initial, float deltaTime, Derivative derivative) {
State state;
state.Position = initial.Position + derivative.Velocity * deltaTime;
state.Velocity = initial.Velocity + derivative.Acceleration * deltaTime;
Derivative output;
output.Velocity = state.Velocity;
output.Acceleration = this.acceleration;
return output;
}
private Vector3 acceleration;
}
} // namespace Framework.Support