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