1+ using System ;
2+ using Freya ;
3+
4+ public class ElevatorEase {
5+
6+ public enum Mode {
7+ FastStartPolynomial ,
8+ Trigonometric
9+ }
10+
11+ public readonly Mode mode ;
12+ public readonly float maxDistance ;
13+ public readonly float contractSpeed ;
14+ public readonly float accDuration ;
15+
16+ public readonly float t1 ;
17+ public readonly float t2 ;
18+ public readonly float tEnd ;
19+ public readonly float v ;
20+
21+ // linear section
22+ float g_c0 , g_c1 ;
23+
24+ // polynomial coefficients used by Mode.FastStartPolynomial
25+ float f_c3 , f_c4 , f_c5 ; // ease in
26+ float h_c4 , h_c5 ; // ease out (relative)
27+
28+ // constants used by Mode.Trigonometric
29+ float c_xsq , c_trigScale , c_trigInner ;
30+
31+ public ElevatorEase ( Mode mode , float maxDistance , float contractSpeed , float accDuration ) {
32+ this . mode = mode ;
33+ this . maxDistance = maxDistance ;
34+ this . contractSpeed = contractSpeed ;
35+ this . accDuration = accDuration ;
36+
37+ // derived things
38+ t1 = accDuration ;
39+ t2 = maxDistance / contractSpeed ;
40+ tEnd = t1 + t2 ;
41+ v = contractSpeed ;
42+ float tHalf = tEnd / 2 ;
43+ if ( accDuration >= tHalf ) {
44+ // no linear section - adjust accordingly
45+ t1 = t2 = tHalf ;
46+ v = 2 * ( maxDistance / tEnd ) ;
47+ }
48+
49+ // calculate coefficients
50+ g_c1 = v ;
51+ if ( mode == Mode . FastStartPolynomial ) {
52+ g_c0 = - 2 * v * t1 / 5 ;
53+ float t1_2 = t1 * t1 ;
54+ float t1_3 = t1_2 * t1 ;
55+ float t1_4 = t1_2 * t1_2 ;
56+ f_c3 = 2 * v / t1_2 ;
57+ f_c4 = 2 * v / - t1_3 ;
58+ f_c5 = 3 * v / ( 5 * t1_4 ) ;
59+ h_c4 = v / - t1_3 ;
60+ h_c5 = - 3 * v / ( 5 * t1_4 ) ;
61+ } else if ( mode == Mode . Trigonometric ) {
62+ g_c0 = - v * t1 / 2 ;
63+ c_xsq = v / ( 2 * t1 ) ;
64+ c_trigScale = v * t1 / ( Mathfs . TAU * Mathfs . TAU ) ;
65+ c_trigInner = Mathfs . TAU / t1 ;
66+ }
67+ }
68+
69+ float EaseIn ( float t ) {
70+ float x2 = t * t ;
71+
72+ if ( mode == Mode . FastStartPolynomial ) {
73+ float x3 = x2 * t ;
74+ float x4 = x2 * x2 ;
75+ float x5 = x3 * x2 ;
76+ return f_c3 * x3 + f_c4 * x4 + f_c5 * x5 ;
77+ } else if ( mode == Mode . Trigonometric ) {
78+ return c_xsq * x2 + c_trigScale * ( MathF . Cos ( c_trigInner * t ) - 1 ) ;
79+ }
80+ throw new NotImplementedException ( ) ;
81+ }
82+
83+ float Linear ( float t ) => g_c0 + g_c1 * t ;
84+
85+ float EaseOut ( float t ) {
86+ if ( mode == Mode . FastStartPolynomial ) {
87+ // this one is asymmetric, and needs special handling
88+ float x = t - tEnd ; // remap to relative
89+ float x2 = x * x ;
90+ float x4 = x2 * x2 ;
91+ float x5 = x4 * x ;
92+ return h_c4 * x4 + h_c5 * x5 + maxDistance ;
93+ }
94+
95+ // same as ease-in but reversed
96+ return maxDistance - EaseIn ( tEnd - t ) ;
97+ }
98+
99+ public float Eval ( float t ) {
100+ // check extremes:
101+ if ( t <= 0 )
102+ return 0 ;
103+ if ( t >= tEnd )
104+ return maxDistance ;
105+ // check functions:
106+ if ( t < t1 )
107+ return EaseIn ( t ) ;
108+ if ( t > t2 )
109+ return EaseOut ( t ) ;
110+ return Linear ( t ) ;
111+ }
112+
113+ }
0 commit comments