Created
October 2, 2024 15:53
-
-
Save lucas-jones/d42187cb62b93b1b20077134abbadd75 to your computer and use it in GitHub Desktop.
Typescript Spring
This file contains hidden or 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
export class Spring { | |
target: number = 0; | |
position: number = 0; | |
velocity: number = 0; | |
frequency: number = 0.2; | |
damping: number = 1; | |
constructor(frequency: number = 0.2, damping: number = 1) { | |
this.frequency = frequency; | |
this.damping = damping; | |
} | |
update(deltaTime: number) { | |
var parms = CalcDampedSpringMotionParams(deltaTime, this.frequency, this.damping); | |
UpdateDampedSpringMotion(this, this.target, parms); | |
} | |
} | |
export const UpdateDampedSpringMotion = (spring: Spring, equilibriumPos: number, params: SpringParams) => { | |
const oldPos = spring.position - equilibriumPos; | |
const oldVel = spring.velocity; | |
spring.position = oldPos * params.posPosCoef + oldVel * params.positionVelCoef + equilibriumPos; | |
spring.velocity = oldPos * params.velPosCoef + oldVel * params.velocityVelCoef; | |
}; | |
export type SpringParams = { | |
posPosCoef: number; | |
positionVelCoef: number; | |
velPosCoef: number; | |
velocityVelCoef: number; | |
}; | |
export const CalcDampedSpringMotionParams = (deltaTime: number, angularFrequency: number, dampingRatio: number) => { | |
const epsilon = 0.0001; | |
var springParams: SpringParams = { | |
posPosCoef: 0, | |
positionVelCoef: 0, | |
velPosCoef: 0, | |
velocityVelCoef: 0, | |
}; | |
if (dampingRatio < 0.0) dampingRatio = 0.0; | |
if (angularFrequency < 0.0) angularFrequency = 0.0; | |
if (angularFrequency < epsilon) { | |
springParams.posPosCoef = 1.0; | |
springParams.positionVelCoef = 0.0; | |
springParams.velPosCoef = 0.0; | |
springParams.velocityVelCoef = 1.0; | |
return; | |
} | |
if (dampingRatio > 1.0 + epsilon) { | |
var za = -angularFrequency * dampingRatio; | |
var zb = angularFrequency * Math.sqrt(dampingRatio * dampingRatio - 1.0); | |
var z1 = za - zb; | |
var z2 = za + zb; | |
var e1 = Math.exp(z1 * deltaTime); | |
var e2 = Math.exp(z2 * deltaTime); | |
var invTwoZb = 1.0 / (2.0 * zb); | |
var e1_Over_TwoZb = e1 * invTwoZb; | |
var e2_Over_TwoZb = e2 * invTwoZb; | |
var z1e1_Over_TwoZb = z1 * e1_Over_TwoZb; | |
var z2e2_Over_TwoZb = z2 * e2_Over_TwoZb; | |
springParams.posPosCoef = e1_Over_TwoZb * z2 - z2e2_Over_TwoZb + e2; | |
springParams.positionVelCoef = -e1_Over_TwoZb + e2_Over_TwoZb; | |
springParams.velPosCoef = (z1e1_Over_TwoZb - z2e2_Over_TwoZb + e2) * z2; | |
springParams.velocityVelCoef = -z1e1_Over_TwoZb + z2e2_Over_TwoZb; | |
} else if (dampingRatio < 1.0 - epsilon) { | |
var omegaZeta = angularFrequency * dampingRatio; | |
var alpha = angularFrequency * Math.sqrt(1.0 - dampingRatio * dampingRatio); | |
var expTerm = Math.exp(-omegaZeta * deltaTime); | |
var cosTerm = Math.cos(alpha * deltaTime); | |
var sinTerm = Math.sin(alpha * deltaTime); | |
var invAlpha = 1.0 / alpha; | |
var expSin = expTerm * sinTerm; | |
var expCos = expTerm * cosTerm; | |
var expOmegaZetaSin_Over_Alpha = expTerm * omegaZeta * sinTerm * invAlpha; | |
springParams.posPosCoef = expCos + expOmegaZetaSin_Over_Alpha; | |
springParams.positionVelCoef = expSin * invAlpha; | |
springParams.velPosCoef = -expSin * alpha - omegaZeta * expOmegaZetaSin_Over_Alpha; | |
springParams.velocityVelCoef = expCos - expOmegaZetaSin_Over_Alpha; | |
} else { | |
var expTerm = Math.exp(-angularFrequency * deltaTime); | |
var timeExp = deltaTime * expTerm; | |
var timeExpFreq = timeExp * angularFrequency; | |
springParams.posPosCoef = timeExpFreq + expTerm; | |
springParams.positionVelCoef = timeExp; | |
springParams.velPosCoef = -angularFrequency * timeExpFreq; | |
springParams.velocityVelCoef = -timeExpFreq + expTerm; | |
} | |
return springParams; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment