Last active
May 18, 2023 18:20
-
-
Save grilme99/6742672cbb3547d99cccee026af4588d to your computer and use it in GitHub Desktop.
Spring implementation for Unity based on Nevermore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A physical model of a spring, based off: | |
// https://github.com/Quenty/NevermoreEngine/blob/2ad8cea7dd3ad79a39afd7d7b785b489b90553fd/src/spring/src/Shared/Spring.lua | |
// | |
// A spring is an object that will compute based upon Hooke's law. Properties only evaluate upon index making this class | |
// good for lazy applications. | |
using System; | |
using UnityEngine; | |
public class Spring | |
{ | |
private float _damper = 1; | |
private float _speed = 1; | |
private float _time0 = Time.time; | |
private Vector3 _position0; | |
private Vector3 _velocity0; | |
private Vector3 _target; | |
public Spring(Vector3 initial) | |
{ | |
_position0 = initial; | |
_velocity0 = 0 * initial; | |
_target = initial; | |
} | |
public void Impulse(Vector3 velocity) | |
{ | |
Velocity += velocity; | |
} | |
public void TimeSkip(float delta) | |
{ | |
var now = Time.time; | |
var (position, velocity) = _positionVelocity(now + delta); | |
_position0 = position; | |
_velocity0 = velocity; | |
_time0 = now; | |
} | |
public Vector3 Position | |
{ | |
get | |
{ | |
var (position, _) = _positionVelocity(Time.time); | |
return position; | |
} | |
set | |
{ | |
var now = Time.time; | |
var (_, velocity) = _positionVelocity(now); | |
_position0 = value; | |
_velocity0 = velocity; | |
_time0 = now; | |
} | |
} | |
public Vector3 Velocity | |
{ | |
get | |
{ | |
var now = Time.time; | |
var (_, velocity) = _positionVelocity(now); | |
return velocity; | |
} | |
set | |
{ | |
var now = Time.time; | |
var (position, _) = _positionVelocity(now); | |
_position0 = position; | |
_velocity0 = value; | |
_time0 = now; | |
} | |
} | |
public Vector3 Target | |
{ | |
get { return _target; } | |
set | |
{ | |
_target = value; | |
_resolvePropertyUpdate(); | |
} | |
} | |
public float Damper | |
{ | |
get { return _damper; } | |
set | |
{ | |
_damper = value; | |
_resolvePropertyUpdate(); | |
} | |
} | |
public float Speed | |
{ | |
get { return _speed; } | |
set | |
{ | |
_speed = Mathf.Max(0, value); | |
_resolvePropertyUpdate(); | |
} | |
} | |
private void _resolvePropertyUpdate() | |
{ | |
var now = Time.time; | |
var (position, velocity) = _positionVelocity(now); | |
_position0 = position; | |
_velocity0 = velocity; | |
_time0 = now; | |
} | |
// https://github.com/Quenty/NevermoreEngine/blob/main/src/spring/src/Shared/Spring.lua#L232 | |
private (Vector3, Vector3) _positionVelocity(float now) | |
{ | |
var p0 = _position0; | |
var v0 = _velocity0; | |
var p1 = _target; | |
var d = _damper; | |
var s = _speed; | |
var t = s * (now - _time0); | |
var d2 = d * d; | |
float h, si, co; | |
if (d2 < 1) | |
{ | |
h = MathF.Sqrt(1 - d2); | |
var ep = Mathf.Exp(-d * t) / h; | |
co = ep * Mathf.Cos(h * t); | |
si = ep * Mathf.Sin(h * t); | |
} | |
else if (d2 > 0.999 && d2 < 1.001) | |
{ | |
h = 1; | |
var ep = Mathf.Exp(-d * t) / h; | |
co = ep; | |
si = ep * t; | |
} | |
else | |
{ | |
h = Mathf.Sqrt(d2 - 1); | |
var u = Mathf.Exp((-d + h) * t) / (2 * h); | |
var v = Mathf.Exp((-d - h) * t) / (2 * h); | |
co = u + v; | |
si = u - v; | |
} | |
var a0 = h * co + d * si; | |
var a1 = 1 - a0; | |
var a2 = si / s; | |
var b0 = -s * si; | |
var b1 = s * si; | |
var b2 = h * co - d * si; | |
return (a0 * p0 + a1 * p1 + a2 * v0, | |
b0 * p0 + b1 * p1 + b2 * v0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment