├── .gitignore
├── .vscode
└── settings.json
├── LICENSE.txt
├── README.md
├── Resources
└── Icon128.png
├── Unity
└── EasingFunctions.cs
├── native_cpp
└── EasingFunctions.hpp
├── native_csharp
└── EasingFunctions.cs
├── native_python
└── EasingFunctions.py
├── tests
├── NativeCpp_test.py
├── NativeCsharp_test.py
└── NativePython_test.py
└── unreal_engine
├── CommonEasingLibrary.cpp
└── CommonEasingLibrary.h
/.gitignore:
--------------------------------------------------------------------------------
1 | .pytest_cache
2 | __pycache__
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.testing.pytestArgs": ["tests"],
3 | "python.testing.unittestEnabled": false,
4 | "python.testing.pytestEnabled": true
5 | }
6 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 MrRobin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Easing Functions
7 |
8 |
9 |
10 | *Available for C++, C#, Python, Unreal Engine and Unity*
11 |
12 |
13 |
14 | #
15 |
16 |
17 |
18 | [](https://github.com/mrrobinofficial/easing/blob/HEAD/LICENSE.txt)
19 | 
20 |
21 | [*Original Creator - cjddmut*](https://github.com/cjddmut)
22 | [*Original Gist - Easing Functions for Unity3D*](https://gist.github.com/cjddmut/d789b9eb78216998e95c)
23 |
24 |
25 |
26 | ## Quick guide
27 |
28 | This repo is a comprehensive collection of easing functions that can be utilized in different programming languages and game development frameworks. The repository provides a set of easing functions designed to facilitate smooth and gradual transitions between values, commonly used in animation systems, user interface interactions, and other scenarios that require smooth motion.
29 |
30 | Benefits and Use Cases:
31 | - Smooth Transitions: The easing functions provided in this repository enable developers to achieve smooth and gradual transitions between values, allowing for more visually appealing animations and movements.
32 | - Animation Systems: The easing functions can be integrated into animation systems to control the interpolation between keyframes, resulting in more natural and fluid animations.
33 | - User Interface Interactions: These easing functions can enhance user interface interactions by providing smooth transitions in response to user input, such as button clicks or slider adjustments.
34 | - Game Development: The repository's support for Unreal Engine and Unity makes it valuable for game developers who want to incorporate smooth motion and animations into their games.
35 |
36 | ## Examples
37 |
38 | ### C# and Unity
39 |
40 | ```csharp
41 | int x = 0;
42 | ```
43 |
44 | ### C++ and Unreal
45 |
46 | ```cpp
47 | int32 x = 0;
48 | ```
49 |
50 | ### Python
51 |
52 | ```python
53 | x = 0;
54 | ```
55 |
--------------------------------------------------------------------------------
/Resources/Icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrRobinOfficial/EasingFunctions/4b0da2497eb8a9ab6671f440c645f9fe4651590b/Resources/Icon128.png
--------------------------------------------------------------------------------
/Unity/EasingFunctions.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Created by C.J. Kimberlin
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2019
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | *
27 | * TERMS OF USE - EASING EQUATIONS
28 | * Open source under the BSD License.
29 | * Copyright (c)2001 Robert Penner
30 | * All rights reserved.
31 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
32 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
33 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
34 | * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
35 | *
36 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
37 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
38 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 | *
42 | *
43 | * ============= Description =============
44 | *
45 | * Below is an example of how to use the easing functions in the file. There is a getting function that will return the function
46 | * from an enum. This is useful since the enum can be exposed in the editor and then the function queried during Start().
47 | *
48 | * EasingFunction.Ease ease = EasingFunction.Ease.EaseInOutQuad;
49 | * EasingFunction.EasingFunc func = GetEasingFunction(ease;
50 | *
51 | * float value = func(0, 10, 0.67f);
52 | *
53 | * EasingFunction.EaseingFunc derivativeFunc = GetEasingFunctionDerivative(ease);
54 | *
55 | * float derivativeValue = derivativeFunc(0, 10, 0.67f);
56 | */
57 |
58 | public static class EasingFunction
59 | {
60 | public enum EaseType : byte
61 | {
62 | EaseInQuad = 0,
63 | EaseOutQuad,
64 | EaseInOutQuad,
65 | EaseInCubic,
66 | EaseOutCubic,
67 | EaseInOutCubic,
68 | EaseInQuart,
69 | EaseOutQuart,
70 | EaseInOutQuart,
71 | EaseInQuint,
72 | EaseOutQuint,
73 | EaseInOutQuint,
74 | EaseInSine,
75 | EaseOutSine,
76 | EaseInOutSine,
77 | EaseInExpo,
78 | EaseOutExpo,
79 | EaseInOutExpo,
80 | EaseInCirc,
81 | EaseOutCirc,
82 | EaseInOutCirc,
83 | Linear,
84 | Spring,
85 | EaseInBounce,
86 | EaseOutBounce,
87 | EaseInOutBounce,
88 | EaseInBack,
89 | EaseOutBack,
90 | EaseInOutBack,
91 | EaseInElastic,
92 | EaseOutElastic,
93 | EaseInOutElastic,
94 | }
95 |
96 | private const float NATURAL_LOG_OF_2 = 0.693147181f;
97 |
98 | /// Easing functions ///
99 |
100 | public static float Linear(float start, float end, float value) => Mathf.Lerp(start, end, value);
101 |
102 | public static float Spring(float start, float end, float value)
103 | {
104 | value = Mathf.Clamp01(value);
105 | value = (Mathf.Sin(value * Mathf.PI * (0.2f + 2.5f * value * value * value)) * Mathf.Pow(1f - value, 2.2f) + value) * (1f + (1.2f * (1f - value)));
106 | return start + (end - start) * value;
107 | }
108 |
109 | public static float EaseInQuad(float start, float end, float value)
110 | {
111 | end -= start;
112 | return end * value * value + start;
113 | }
114 |
115 | public static float EaseOutQuad(float start, float end, float value)
116 | {
117 | end -= start;
118 | return -end * value * (value - 2) + start;
119 | }
120 |
121 | public static float EaseInOutQuad(float start, float end, float value)
122 | {
123 | value /= .5f;
124 | end -= start;
125 | if (value < 1) return end * 0.5f * value * value + start;
126 | value--;
127 | return -end * 0.5f * (value * (value - 2) - 1) + start;
128 | }
129 |
130 | public static float EaseInCubic(float start, float end, float value)
131 | {
132 | end -= start;
133 | return end * value * value * value + start;
134 | }
135 |
136 | public static float EaseOutCubic(float start, float end, float value)
137 | {
138 | value--;
139 | end -= start;
140 | return end * (value * value * value + 1) + start;
141 | }
142 |
143 | public static float EaseInOutCubic(float start, float end, float value)
144 | {
145 | value /= .5f;
146 | end -= start;
147 | if (value < 1) return end * 0.5f * value * value * value + start;
148 | value -= 2;
149 | return end * 0.5f * (value * value * value + 2) + start;
150 | }
151 |
152 | public static float EaseInQuart(float start, float end, float value)
153 | {
154 | end -= start;
155 | return end * value * value * value * value + start;
156 | }
157 |
158 | public static float EaseOutQuart(float start, float end, float value)
159 | {
160 | value--;
161 | end -= start;
162 | return -end * (value * value * value * value - 1) + start;
163 | }
164 |
165 | public static float EaseInOutQuart(float start, float end, float value)
166 | {
167 | value /= .5f;
168 | end -= start;
169 | if (value < 1) return end * 0.5f * value * value * value * value + start;
170 | value -= 2;
171 | return -end * 0.5f * (value * value * value * value - 2) + start;
172 | }
173 |
174 | public static float EaseInQuint(float start, float end, float value)
175 | {
176 | end -= start;
177 | return end * value * value * value * value * value + start;
178 | }
179 |
180 | public static float EaseOutQuint(float start, float end, float value)
181 | {
182 | value--;
183 | end -= start;
184 | return end * (value * value * value * value * value + 1) + start;
185 | }
186 |
187 | public static float EaseInOutQuint(float start, float end, float value)
188 | {
189 | value /= .5f;
190 | end -= start;
191 | if (value < 1) return end * 0.5f * value * value * value * value * value + start;
192 | value -= 2;
193 | return end * 0.5f * (value * value * value * value * value + 2) + start;
194 | }
195 |
196 | public static float EaseInSine(float start, float end, float value)
197 | {
198 | end -= start;
199 | return -end * Mathf.Cos(value * (Mathf.PI * 0.5f)) + end + start;
200 | }
201 |
202 | public static float EaseOutSine(float start, float end, float value)
203 | {
204 | end -= start;
205 | return end * Mathf.Sin(value * (Mathf.PI * 0.5f)) + start;
206 | }
207 |
208 | public static float EaseInOutSine(float start, float end, float value)
209 | {
210 | end -= start;
211 | return -end * 0.5f * (Mathf.Cos(Mathf.PI * value) - 1) + start;
212 | }
213 |
214 | public static float EaseInExpo(float start, float end, float value)
215 | {
216 | end -= start;
217 | return end * Mathf.Pow(2, 10 * (value - 1)) + start;
218 | }
219 |
220 | public static float EaseOutExpo(float start, float end, float value)
221 | {
222 | end -= start;
223 | return end * (-Mathf.Pow(2, -10 * value) + 1) + start;
224 | }
225 |
226 | public static float EaseInOutExpo(float start, float end, float value)
227 | {
228 | value /= .5f;
229 | end -= start;
230 |
231 | if (value < 1)
232 | return end * 0.5f * Mathf.Pow(2, 10 * (value - 1)) + start;
233 |
234 | value--;
235 |
236 | return end * 0.5f * (-Mathf.Pow(2, -10 * value) + 2) + start;
237 | }
238 |
239 | public static float EaseInCirc(float start, float end, float value)
240 | {
241 | end -= start;
242 | return -end * (Mathf.Sqrt(1 - value * value) - 1) + start;
243 | }
244 |
245 | public static float EaseOutCirc(float start, float end, float value)
246 | {
247 | value--;
248 | end -= start;
249 | return end * Mathf.Sqrt(1 - value * value) + start;
250 | }
251 |
252 | public static float EaseInOutCirc(float start, float end, float value)
253 | {
254 | value /= .5f;
255 | end -= start;
256 | if (value < 1) return -end * 0.5f * (Mathf.Sqrt(1 - value * value) - 1) + start;
257 | value -= 2;
258 | return end * 0.5f * (Mathf.Sqrt(1 - value * value) + 1) + start;
259 | }
260 |
261 | public static float EaseInBounce(float start, float end, float value)
262 | {
263 | end -= start;
264 | float d = 1f;
265 | return end - EaseOutBounce(0, end, d - value) + start;
266 | }
267 |
268 | public static float EaseOutBounce(float start, float end, float value)
269 | {
270 | value /= 1f;
271 | end -= start;
272 | if (value < (1 / 2.75f))
273 | {
274 | return end * (7.5625f * value * value) + start;
275 | }
276 | else if (value < (2 / 2.75f))
277 | {
278 | value -= (1.5f / 2.75f);
279 | return end * (7.5625f * (value) * value + .75f) + start;
280 | }
281 | else if (value < (2.5 / 2.75))
282 | {
283 | value -= (2.25f / 2.75f);
284 | return end * (7.5625f * (value) * value + .9375f) + start;
285 | }
286 | else
287 | {
288 | value -= (2.625f / 2.75f);
289 | return end * (7.5625f * (value) * value + .984375f) + start;
290 | }
291 | }
292 |
293 | public static float EaseInOutBounce(float start, float end, float value)
294 | {
295 | end -= start;
296 | float d = 1f;
297 | if (value < d * 0.5f) return EaseInBounce(0, end, value * 2) * 0.5f + start;
298 | else return EaseOutBounce(0, end, value * 2 - d) * 0.5f + end * 0.5f + start;
299 | }
300 |
301 | public static float EaseInBack(float start, float end, float value)
302 | {
303 | end -= start;
304 | value /= 1;
305 | float s = 1.70158f;
306 | return end * (value) * value * ((s + 1) * value - s) + start;
307 | }
308 |
309 | public static float EaseOutBack(float start, float end, float value)
310 | {
311 | float s = 1.70158f;
312 | end -= start;
313 | value = (value) - 1;
314 | return end * ((value) * value * ((s + 1) * value + s) + 1) + start;
315 | }
316 |
317 | public static float EaseInOutBack(float start, float end, float value)
318 | {
319 | float s = 1.70158f;
320 | end -= start;
321 | value /= .5f;
322 | if ((value) < 1)
323 | {
324 | s *= (1.525f);
325 | return end * 0.5f * (value * value * (((s) + 1) * value - s)) + start;
326 | }
327 | value -= 2;
328 | s *= (1.525f);
329 | return end * 0.5f * ((value) * value * (((s) + 1) * value + s) + 2) + start;
330 | }
331 |
332 | public static float EaseInElastic(float start, float end, float value)
333 | {
334 | end -= start;
335 |
336 | float d = 1f;
337 | float p = d * .3f;
338 | float s;
339 | float a = 0;
340 |
341 | if (value == 0)
342 | return start;
343 |
344 | if ((value /= d) == 1)
345 | return start + end;
346 |
347 | if (a == 0f || a < Mathf.Abs(end))
348 | {
349 | a = end;
350 | s = p / 4;
351 | }
352 | else
353 | s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
354 |
355 | return -(a * Mathf.Pow(2, 10 * (value -= 1)) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p)) + start;
356 | }
357 |
358 | public static float EaseOutElastic(float start, float end, float value)
359 | {
360 | end -= start;
361 |
362 | float d = 1f;
363 | float p = d * .3f;
364 | float s;
365 | float a = 0;
366 |
367 | if (value == 0) return start;
368 |
369 | if ((value /= d) == 1) return start + end;
370 |
371 | if (a == 0f || a < Mathf.Abs(end))
372 | {
373 | a = end;
374 | s = p * 0.25f;
375 | }
376 | else
377 | {
378 | s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
379 | }
380 |
381 | return (a * Mathf.Pow(2, -10 * value) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p) + end + start);
382 | }
383 |
384 | public static float EaseInOutElastic(float start, float end, float value)
385 | {
386 | end -= start;
387 |
388 | float d = 1f;
389 | float p = d * .3f;
390 | float s;
391 | float a = 0;
392 |
393 | if (value == 0) return start;
394 |
395 | if ((value /= d * 0.5f) == 2) return start + end;
396 |
397 | if (a == 0f || a < Mathf.Abs(end))
398 | {
399 | a = end;
400 | s = p / 4;
401 | }
402 | else
403 | {
404 | s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
405 | }
406 |
407 | if (value < 1) return -0.5f * (a * Mathf.Pow(2, 10 * (value -= 1)) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p)) + start;
408 | return a * Mathf.Pow(2, -10 * (value -= 1)) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p) * 0.5f + end + start;
409 | }
410 |
411 | //
412 | // These are derived functions that the motor can use to get the speed at a specific time.
413 | //
414 | // The easing functions all work with a normalized time (0 to 1) and the returned value here
415 | // reflects that. Values returned here should be divided by the actual time.
416 | //
417 | // TODO: These functions have not had the testing they deserve. If there is odd behavior around
418 | // dash speeds then this would be the first place I'd look.
419 |
420 | public static float LinearD(float start, float end, float value) => end - start;
421 |
422 | public static float EaseInQuadD(float start, float end, float value) => 2f * (end - start) * value;
423 |
424 | public static float EaseOutQuadD(float start, float end, float value)
425 | {
426 | end -= start;
427 | return -end * value - end * (value - 2);
428 | }
429 |
430 | public static float EaseInOutQuadD(float start, float end, float value)
431 | {
432 | value /= .5f;
433 | end -= start;
434 |
435 | if (value < 1)
436 | {
437 | return end * value;
438 | }
439 |
440 | value--;
441 |
442 | return end * (1 - value);
443 | }
444 |
445 | public static float EaseInCubicD(float start, float end, float value) => 3f * (end - start) * value * value;
446 |
447 | public static float EaseOutCubicD(float start, float end, float value)
448 | {
449 | value--;
450 | end -= start;
451 | return 3f * end * value * value;
452 | }
453 |
454 | public static float EaseInOutCubicD(float start, float end, float value)
455 | {
456 | value /= .5f;
457 | end -= start;
458 |
459 | if (value < 1)
460 | {
461 | return (3f / 2f) * end * value * value;
462 | }
463 |
464 | value -= 2;
465 |
466 | return (3f / 2f) * end * value * value;
467 | }
468 |
469 | public static float EaseInQuartD(float start, float end, float value)
470 | {
471 | return 4f * (end - start) * value * value * value;
472 | }
473 |
474 | public static float EaseOutQuartD(float start, float end, float value)
475 | {
476 | value--;
477 | end -= start;
478 | return -4f * end * value * value * value;
479 | }
480 |
481 | public static float EaseInOutQuartD(float start, float end, float value)
482 | {
483 | value /= .5f;
484 | end -= start;
485 |
486 | if (value < 1)
487 | {
488 | return 2f * end * value * value * value;
489 | }
490 |
491 | value -= 2;
492 |
493 | return -2f * end * value * value * value;
494 | }
495 |
496 | public static float EaseInQuintD(float start, float end, float value)
497 | {
498 | return 5f * (end - start) * value * value * value * value;
499 | }
500 |
501 | public static float EaseOutQuintD(float start, float end, float value)
502 | {
503 | value--;
504 | end -= start;
505 | return 5f * end * value * value * value * value;
506 | }
507 |
508 | public static float EaseInOutQuintD(float start, float end, float value)
509 | {
510 | value /= .5f;
511 | end -= start;
512 |
513 | if (value < 1)
514 | {
515 | return (5f / 2f) * end * value * value * value * value;
516 | }
517 |
518 | value -= 2;
519 |
520 | return (5f / 2f) * end * value * value * value * value;
521 | }
522 |
523 | public static float EaseInSineD(float start, float end, float value)
524 | {
525 | return (end - start) * 0.5f * Mathf.PI * Mathf.Sin(0.5f * Mathf.PI * value);
526 | }
527 |
528 | public static float EaseOutSineD(float start, float end, float value)
529 | {
530 | end -= start;
531 | return (Mathf.PI * 0.5f) * end * Mathf.Cos(value * (Mathf.PI * 0.5f));
532 | }
533 |
534 | public static float EaseInOutSineD(float start, float end, float value)
535 | {
536 | end -= start;
537 | return end * 0.5f * Mathf.PI * Mathf.Sin(Mathf.PI * value);
538 | }
539 |
540 | public static float EaseInExpoD(float start, float end, float value) => 10f * NATURAL_LOG_OF_2 * (end - start) * Mathf.Pow(2f, 10f * (value - 1));
541 |
542 | public static float EaseOutExpoD(float start, float end, float value)
543 | {
544 | end -= start;
545 | return 5f * NATURAL_LOG_OF_2 * end * Mathf.Pow(2f, 1f - 10f * value);
546 | }
547 |
548 | public static float EaseInOutExpoD(float start, float end, float value)
549 | {
550 | value /= .5f;
551 | end -= start;
552 |
553 | if (value < 1)
554 | return 5f * NATURAL_LOG_OF_2 * end * Mathf.Pow(2f, 10f * (value - 1));
555 |
556 | value--;
557 |
558 | return (5f * NATURAL_LOG_OF_2 * end) / (Mathf.Pow(2f, 10f * value));
559 | }
560 |
561 | public static float EaseInCircD(float start, float end, float value) => (end - start) * value / Mathf.Sqrt(1f - value * value);
562 |
563 | public static float EaseOutCircD(float start, float end, float value)
564 | {
565 | value--;
566 | end -= start;
567 | return (-end * value) / Mathf.Sqrt(1f - value * value);
568 | }
569 |
570 | public static float EaseInOutCircD(float start, float end, float value)
571 | {
572 | value /= .5f;
573 | end -= start;
574 |
575 | if (value < 1)
576 | {
577 | return (end * value) / (2f * Mathf.Sqrt(1f - value * value));
578 | }
579 |
580 | value -= 2;
581 |
582 | return (-end * value) / (2f * Mathf.Sqrt(1f - value * value));
583 | }
584 |
585 | public static float EaseInBounceD(float start, float end, float value)
586 | {
587 | end -= start;
588 | float d = 1f;
589 |
590 | return EaseOutBounceD(0, end, d - value);
591 | }
592 |
593 | public static float EaseOutBounceD(float start, float end, float value)
594 | {
595 | value /= 1f;
596 | end -= start;
597 |
598 | if (value < (1 / 2.75f))
599 | {
600 | return 2f * end * 7.5625f * value;
601 | }
602 | else if (value < (2 / 2.75f))
603 | {
604 | value -= (1.5f / 2.75f);
605 | return 2f * end * 7.5625f * value;
606 | }
607 | else if (value < (2.5 / 2.75))
608 | {
609 | value -= (2.25f / 2.75f);
610 | return 2f * end * 7.5625f * value;
611 | }
612 | else
613 | {
614 | value -= (2.625f / 2.75f);
615 | return 2f * end * 7.5625f * value;
616 | }
617 | }
618 |
619 | public static float EaseInOutBounceD(float start, float end, float value)
620 | {
621 | end -= start;
622 | float d = 1f;
623 |
624 | return value < d * 0.5f ? EaseInBounceD(0, end, value * 2) * 0.5f : EaseOutBounceD(0, end, value * 2 - d) * 0.5f;
625 | }
626 |
627 | public static float EaseInBackD(float start, float end, float value)
628 | {
629 | const float s = 1.70158f;
630 | return 3f * (s + 1f) * (end - start) * value * value - 2f * s * (end - start) * value;
631 | }
632 |
633 | public static float EaseOutBackD(float start, float end, float value)
634 | {
635 | const float s = 1.70158f;
636 | end -= start;
637 | value = (value) - 1;
638 |
639 | return end * ((s + 1f) * value * value + 2f * value * ((s + 1f) * value + s));
640 | }
641 |
642 | public static float EaseInOutBackD(float start, float end, float value)
643 | {
644 | float s = 1.70158f;
645 | end -= start;
646 | value /= .5f;
647 |
648 | if ((value) < 1)
649 | {
650 | s *= (1.525f);
651 | return 0.5f * end * (s + 1) * value * value + end * value * ((s + 1f) * value - s);
652 | }
653 |
654 | value -= 2;
655 | s *= (1.525f);
656 | return 0.5f * end * ((s + 1) * value * value + 2f * value * ((s + 1f) * value + s));
657 | }
658 |
659 | public static float EaseInElasticD(float start, float end, float value)
660 | {
661 | return EaseOutElasticD(start, end, 1f - value);
662 | }
663 |
664 | public static float EaseOutElasticD(float start, float end, float value)
665 | {
666 | end -= start;
667 |
668 | float d = 1f;
669 | float p = d * .3f;
670 | float s;
671 | float a = 0;
672 |
673 | if (a == 0f || a < Mathf.Abs(end))
674 | {
675 | a = end;
676 | s = p * 0.25f;
677 | }
678 | else
679 | {
680 | s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
681 | }
682 |
683 | return (a * Mathf.PI * d * Mathf.Pow(2f, 1f - 10f * value) *
684 | Mathf.Cos((2f * Mathf.PI * (d * value - s)) / p)) / p - 5f * NATURAL_LOG_OF_2 * a *
685 | Mathf.Pow(2f, 1f - 10f * value) * Mathf.Sin((2f * Mathf.PI * (d * value - s)) / p);
686 | }
687 |
688 | public static float EaseInOutElasticD(float start, float end, float value)
689 | {
690 | end -= start;
691 |
692 | float d = 1f;
693 | float p = d * .3f;
694 | float s;
695 | float a = 0;
696 |
697 | if (a == 0f || a < Mathf.Abs(end))
698 | {
699 | a = end;
700 | s = p / 4;
701 | }
702 | else
703 | {
704 | s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
705 | }
706 |
707 | if (value < 1)
708 | {
709 | value -= 1;
710 |
711 | return -5f * NATURAL_LOG_OF_2 * a * Mathf.Pow(2f, 10f * value) * Mathf.Sin(2 * Mathf.PI * (d * value - 2f) / p) -
712 | a * Mathf.PI * d * Mathf.Pow(2f, 10f * value) * Mathf.Cos(2 * Mathf.PI * (d * value - s) / p) / p;
713 | }
714 |
715 | value -= 1;
716 |
717 | return a * Mathf.PI * d * Mathf.Cos(2f * Mathf.PI * (d * value - s) / p) / (p * Mathf.Pow(2f, 10f * value)) -
718 | 5f * NATURAL_LOG_OF_2 * a * Mathf.Sin(2f * Mathf.PI * (d * value - s) / p) / (Mathf.Pow(2f, 10f * value));
719 | }
720 |
721 | public static float SpringD(float start, float end, float value)
722 | {
723 | value = Mathf.Clamp01(value);
724 | end -= start;
725 |
726 | // Damn... Thanks http://www.derivative-calculator.net/
727 | // TODO: And it's a little bit wrong
728 | return end * (6f * (1f - value) / 5f + 1f) * (-2.2f * Mathf.Pow(1f - value, 1.2f) *
729 | Mathf.Sin(Mathf.PI * value * (2.5f * value * value * value + 0.2f)) + Mathf.Pow(1f - value, 2.2f) *
730 | (Mathf.PI * (2.5f * value * value * value + 0.2f) + 7.5f * Mathf.PI * value * value * value) *
731 | Mathf.Cos(Mathf.PI * value * (2.5f * value * value * value + 0.2f)) + 1f) -
732 | 6f * end * (Mathf.Pow(1 - value, 2.2f) * Mathf.Sin(Mathf.PI * value * (2.5f * value * value * value + 0.2f)) + value
733 | / 5f);
734 |
735 | }
736 |
737 | public delegate float Function(float start, float end, float value);
738 |
739 | ///
740 | /// Returns the function associated to the easingFunction enum. This value returned should be cached as it allocates memory
741 | /// to return.
742 | ///
743 | /// The enum associated with the easing function.
744 | /// The easing function
745 | public static Function GetEasingFunction(EaseType type) => type switch
746 | {
747 | EaseType.EaseInQuad => EaseInQuad,
748 | EaseType.EaseOutQuad => EaseOutQuad,
749 | EaseType.EaseInOutQuad => EaseInOutQuad,
750 | EaseType.EaseInCubic => EaseInCubic,
751 | EaseType.EaseOutCubic => EaseOutCubic,
752 | EaseType.EaseInOutCubic => EaseInOutCubic,
753 | EaseType.EaseInQuart => EaseInQuart,
754 | EaseType.EaseOutQuart => EaseOutQuart,
755 | EaseType.EaseInOutQuart => EaseInOutQuart,
756 | EaseType.EaseInQuint => EaseInQuint,
757 | EaseType.EaseOutQuint => EaseOutQuint,
758 | EaseType.EaseInOutQuint => EaseInOutQuint,
759 | EaseType.EaseInSine => EaseInSine,
760 | EaseType.EaseOutSine => EaseOutSine,
761 | EaseType.EaseInOutSine => EaseInOutSine,
762 | EaseType.EaseInExpo => EaseInExpo,
763 | EaseType.EaseOutExpo => EaseOutExpo,
764 | EaseType.EaseInOutExpo => EaseInOutExpo,
765 | EaseType.EaseInCirc => EaseInCirc,
766 | EaseType.EaseOutCirc => EaseOutCirc,
767 | EaseType.EaseInOutCirc => EaseInOutCirc,
768 | EaseType.Linear => Linear,
769 | EaseType.Spring => Spring,
770 | EaseType.EaseInBounce => EaseInBounce,
771 | EaseType.EaseOutBounce => EaseOutBounce,
772 | EaseType.EaseInOutBounce => EaseInOutBounce,
773 | EaseType.EaseInBack => EaseInBack,
774 | EaseType.EaseOutBack => EaseOutBack,
775 | EaseType.EaseInOutBack => EaseInOutBack,
776 | EaseType.EaseInElastic => EaseInElastic,
777 | EaseType.EaseOutElastic => EaseOutElastic,
778 | EaseType.EaseInOutElastic => EaseInOutElastic,
779 | _ => null,
780 | };
781 |
782 | ///
783 | /// Gets the derivative function of the appropriate easing function. If you use an easing function for position then this
784 | /// function can get you the speed at a given time (normalized).
785 | ///
786 | ///
787 | /// The derivative function
788 | public static Function GetEasingFunctionDerivative(EaseType type) => type switch
789 | {
790 | EaseType.EaseInQuad => EaseInQuadD,
791 | EaseType.EaseOutQuad => EaseOutQuadD,
792 | EaseType.EaseInOutQuad => EaseInOutQuadD,
793 | EaseType.EaseInCubic => EaseInCubicD,
794 | EaseType.EaseOutCubic => EaseOutCubicD,
795 | EaseType.EaseInOutCubic => EaseInOutCubicD,
796 | EaseType.EaseInQuart => EaseInQuartD,
797 | EaseType.EaseOutQuart => EaseOutQuartD,
798 | EaseType.EaseInOutQuart => EaseInOutQuartD,
799 | EaseType.EaseInQuint => EaseInQuintD,
800 | EaseType.EaseOutQuint => EaseOutQuintD,
801 | EaseType.EaseInOutQuint => EaseInOutQuintD,
802 | EaseType.EaseInSine => EaseInSineD,
803 | EaseType.EaseOutSine => EaseOutSineD,
804 | EaseType.EaseInOutSine => EaseInOutSineD,
805 | EaseType.EaseInExpo => EaseInExpoD,
806 | EaseType.EaseOutExpo => EaseOutExpoD,
807 | EaseType.EaseInOutExpo => EaseInOutExpoD,
808 | EaseType.EaseInCirc => EaseInCircD,
809 | EaseType.EaseOutCirc => EaseOutCircD,
810 | EaseType.EaseInOutCirc => EaseInOutCircD,
811 | EaseType.Linear => LinearD,
812 | EaseType.Spring => SpringD,
813 | EaseType.EaseInBounce => EaseInBounceD,
814 | EaseType.EaseOutBounce => EaseOutBounceD,
815 | EaseType.EaseInOutBounce => EaseInOutBounceD,
816 | EaseType.EaseInBack => EaseInBackD,
817 | EaseType.EaseOutBack => EaseOutBackD,
818 | EaseType.EaseInOutBack => EaseInOutBackD,
819 | EaseType.EaseInElastic => EaseInElasticD,
820 | EaseType.EaseOutElastic => EaseOutElasticD,
821 | EaseType.EaseInOutElastic => EaseInOutElasticD,
822 | _ => null,
823 | };
824 | }
--------------------------------------------------------------------------------
/native_cpp/EasingFunctions.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Created by C.J. Kimberlin
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2019
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | *
27 | * TERMS OF USE - EASING EQUATIONS
28 | * Open source under the BSD License.
29 | * Copyright (c)2001 Robert Penner
30 | * All rights reserved.
31 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
32 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
33 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
34 | * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
35 | *
36 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
37 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
38 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 | *
42 | *
43 | * ============= Description =============
44 | *
45 | * Below is an example of how to use the easing functions in the file. There is a getting function that will return the function
46 | * from an enum. This is useful since the enum can be exposed in the editor and then the function queried during start().
47 | *
48 | * EasingFunction.Ease ease = EasingFunction.Ease.EaseInOutQuad;
49 | * EasingFunction.EasingFunc func = GetEasingFunction(ease;
50 | *
51 | * float alpha = func(0, 10, 0.67f);
52 | *
53 | * EasingFunction.EaseingFunc derivativeFunc = GetEasingFunctionDerivative(ease);
54 | *
55 | * float derivativeValue = derivativeFunc(0, 10, 0.67f);
56 | */
57 |
58 | #include
59 |
60 | class EasingFunctions
61 | {
62 | #define NATURAL_LOG_OF_2 0.693147181f
63 | #define PI 3.14159274101257324219f
64 |
65 | public:
66 | enum EEaseType : unsigned int
67 | {
68 | EASE_LINEAR = 0,
69 | EASE_SPRING,
70 | EASE_IN_QUAD,
71 | EASE_OUT_QUAD,
72 | EASE_IN_OUT_QUAD,
73 | EASE_IN_CUBIC,
74 | EASE_OUT_CUBIC,
75 | EASE_IN_OUT_CUBIC,
76 | EASE_IN_QUART,
77 | EASE_OUT_QUART,
78 | EASE_IN_OUT_QUART,
79 | EASE_IN_QUINT,
80 | EASE_OUT_QUINT,
81 | EASE_IN_OUT_QUINT,
82 | EASE_IN_SINE,
83 | EASE_OUT_SINE,
84 | EASE_IN_OUT_SINE,
85 | EASE_IN_EXPO,
86 | EASE_OUT_EXPO,
87 | EASE_IN_OUT_EXPO,
88 | EASE_IN_CIRC,
89 | EASE_OUT_CIRC,
90 | EASE_IN_OUT_CIRC,
91 | EASE_IN_BOUNCE,
92 | EASE_OUT_BOUNCE,
93 | EASE_IN_OUT_BOUNCE,
94 | EASE_IN_BACK,
95 | EASE_OUT_BACK,
96 | EASE_IN_OUT_BACK,
97 | EASE_IN_ELASTIC,
98 | EASE_OUT_ELASTIC,
99 | EASE_IN_OUT_ELASTIC
100 | };
101 |
102 | private:
103 | template
104 | static T Lerp(T a, T b, T t)
105 | {
106 | return a * (T(1.0f) -t) + (b * t);
107 | }
108 |
109 | template
110 | static T Pow(T base, T exponent)
111 | {
112 | T result = T(1.0f);
113 |
114 | for (T i = 0; i < exponent; ++i) {
115 | result *= base;
116 | }
117 |
118 | return result;
119 | }
120 |
121 | template
122 | static T Sin(T x)
123 | {
124 | T result = x;
125 | T term = x;
126 | T x_squared = -x * x;
127 | T factorial = 1;
128 | T denominator = 1;
129 |
130 | for (int i = 1; i < 10; i++) {
131 | factorial *= i;
132 | denominator *= 2 * i * (2 * i + 1);
133 | term *= x_squared / denominator;
134 |
135 | if (i % 2 == 1) {
136 | result -= term;
137 | } else {
138 | result += term;
139 | }
140 | }
141 |
142 | return result;
143 | }
144 |
145 | template
146 | static T Clamp(T alpha, T min, T max)
147 | {
148 | return alpha < min ? min : (alpha > max ? max : alpha);
149 | }
150 |
151 | public:
152 | template
153 | static T GetEaseFromType(EEaseType easeType, T start, T end, T alpha)
154 | {
155 | switch (easeType)
156 | {
157 | default:
158 | return T(0.0f);
159 |
160 | case EEaseType::EASE_LINEAR:
161 | return EaseLinear(start, end, alpha);
162 |
163 | case EEaseType::EASE_SPRING:
164 | return EaseSpring(start, end, alpha);
165 |
166 | case EEaseType::EASE_IN_QUAD:
167 | return EaseInQuad(start, end, alpha);
168 |
169 | case EEaseType::EASE_OUT_QUAD:
170 | return EaseOutQuad(start, end, alpha);
171 |
172 | case EEaseType::EASE_IN_OUT_QUAD:
173 | return EaseInOutQuad(start, end, alpha);
174 |
175 | case EEaseType::EASE_IN_CUBIC:
176 | return EaseInCubic(start, end, alpha);
177 |
178 | case EEaseType::EASE_OUT_CUBIC:
179 | return EaseOutCubic(start, end, alpha);
180 |
181 | case EEaseType::EASE_IN_OUT_CUBIC:
182 | return EaseInOutCubic(start, end, alpha);
183 |
184 | case EEaseType::EASE_IN_QUART:
185 | return EaseInQuart(start, end, alpha);
186 |
187 | case EEaseType::EASE_OUT_QUART:
188 | return EaseOutQuart(start, end, alpha);
189 |
190 | case EEaseType::EASE_IN_OUT_QUART:
191 | return EaseInOutQuart(start, end, alpha);
192 |
193 | case EEaseType::EASE_IN_QUINT:
194 | return EaseInQuint(start, end, alpha);
195 |
196 | case EEaseType::EASE_OUT_QUINT:
197 | return EaseOutQuint(start, end, alpha);
198 |
199 | case EEaseType::EASE_IN_OUT_QUINT:
200 | return EaseInOutQuint(start, end, alpha);
201 |
202 | case EEaseType::EASE_IN_SINE:
203 | return EaseInSine(start, end, alpha);
204 |
205 | case EEaseType::EASE_OUT_SINE:
206 | return EaseOutSine(start, end, alpha);
207 |
208 | case EEaseType::EASE_IN_OUT_SINE:
209 | return EaseInOutSine(start, end, alpha);
210 |
211 | case EEaseType::EASE_IN_EXPO:
212 | return EaseInExpo(start, end, alpha);
213 |
214 | case EEaseType::EASE_OUT_EXPO:
215 | return EaseOutExpo(start, end, alpha);
216 |
217 | case EEaseType::EASE_IN_OUT_EXPO:
218 | return EaseInOutExpo(start, end, alpha);
219 |
220 | case EEaseType::EASE_IN_CIRC:
221 | return EaseInCirc(start, end, alpha);
222 |
223 | case EEaseType::EASE_OUT_CIRC:
224 | return EaseOutCirc(start, end, alpha);
225 |
226 | case EEaseType::EASE_IN_OUT_CIRC:
227 | return EaseInOutCirc(start, end, alpha);
228 |
229 | case EEaseType::EASE_IN_BOUNCE:
230 | return EaseInBounce(start, end, alpha);
231 |
232 | case EEaseType::EASE_OUT_BOUNCE:
233 | return EaseOutBounce(start, end, alpha);
234 |
235 | case EEaseType::EASE_IN_OUT_BOUNCE:
236 | return EaseInOutBounce(start, end, alpha);
237 |
238 | case EEaseType::EASE_IN_BACK:
239 | return EaseInBack(start, end, alpha);
240 |
241 | case EEaseType::EASE_OUT_BACK:
242 | return EaseOutBack(start, end, alpha);
243 |
244 | case EEaseType::EASE_IN_OUT_BACK:
245 | return EaseInOutBack(start, end, alpha);
246 |
247 | case EEaseType::EASE_IN_ELASTIC:
248 | return EaseInElastic(start, end, alpha);
249 |
250 | case EEaseType::EASE_OUT_ELASTIC:
251 | return EaseOutElastic(start, end, alpha);
252 |
253 | case EEaseType::EASE_IN_OUT_ELASTIC:
254 | return EaseInOutElastic(start, end, alpha);
255 | }
256 | }
257 |
258 | /// Easing functions ///
259 |
260 | template
261 | static T EaseLinear(T start, T end, T alpha)
262 | {
263 | return Lerp(start, end, alpha);
264 | }
265 |
266 | template
267 | static T EaseSpring(T start, T end, T alpha)
268 | {
269 | alpha = Clamp(alpha, T(0.0f), T(1.0f));
270 | alpha = (Sin(alpha * PI * (T(0.2f) + T(2.5f) * alpha * alpha * alpha)) * Pow(T(1.0f) - alpha, T(2.2f)) + alpha) * (T(1.0f) + (T(1.2f) * (1.0f - alpha)));
271 |
272 | return start + (end - start) * alpha;
273 | }
274 |
275 | template
276 | static T EaseInQuad(T start, T end, T alpha)
277 | {
278 | end -= start;
279 | return end * alpha * alpha + start;
280 | }
281 |
282 | template
283 | static T EaseOutQuad(T start, T end, T alpha)
284 | {
285 | end -= start;
286 | return -end * alpha * (alpha - T(2.0f)) + start;
287 | }
288 |
289 | template
290 | static T EaseInOutQuad(T start, T end, T alpha)
291 | {
292 | alpha /= T(0.5f);
293 | end -= start;
294 | if (alpha < T(1.0f)) return end * T(0.5f) * alpha * alpha + start;
295 | alpha--;
296 | return -end * T(0.5f) * (alpha * (alpha - T(2.0f)) - T(1.0f)) + start;
297 | }
298 |
299 | template
300 | static float EaseInCubic(T start, T end, T alpha)
301 | {
302 | end -= start;
303 | return end * alpha * alpha * alpha + start;
304 | }
305 |
306 | template
307 | static float EaseOutCubic(T start, T end, T alpha)
308 | {
309 | alpha--;
310 | end -= start;
311 | return end * (alpha * alpha * alpha + T(1.0f)) + start;
312 | }
313 |
314 | template
315 | static float EaseInOutCubic(T start, T end, T alpha)
316 | {
317 | alpha /= T(0.5f);
318 | end -= start;
319 | if (alpha < T(1.0f)) return end * T(0.5f) * alpha * alpha * alpha + start;
320 | alpha -= T(2.0f);
321 | return end * T(0.5f) * (alpha * alpha * alpha + T(2.0f)) + start;
322 | }
323 |
324 | template
325 | static float EaseInQuart(T start, T end, T alpha)
326 | {
327 | end -= start;
328 | return end * alpha * alpha * alpha * alpha + start;
329 | }
330 |
331 | template
332 | static float EaseOutQuart(T start, T end, T alpha)
333 | {
334 | alpha--;
335 | end -= start;
336 | return -end * (alpha * alpha * alpha * alpha - T(1.0f)) + start;
337 | }
338 |
339 | static float EaseInOutQuart(float start, float end, float alpha)
340 | {
341 | alpha /= 0.5f;
342 | end -= start;
343 | if (alpha < 1) return end * 0.5f * alpha * alpha * alpha * alpha + start;
344 | alpha -= 2;
345 | return -end * 0.5f * (alpha * alpha * alpha * alpha - 2) + start;
346 | }
347 |
348 | static float EaseInQuint(float start, float end, float alpha)
349 | {
350 | end -= start;
351 | return end * alpha * alpha * alpha * alpha * alpha + start;
352 | }
353 |
354 | static float EaseOutQuint(float start, float end, float alpha)
355 | {
356 | alpha--;
357 | end -= start;
358 | return end * (alpha * alpha * alpha * alpha * alpha + 1) + start;
359 | }
360 |
361 | static float EaseInOutQuint(float start, float end, float alpha)
362 | {
363 | alpha /= 0.5f;
364 | end -= start;
365 | if (alpha < 1) return end * 0.5f * alpha * alpha * alpha * alpha * alpha + start;
366 | alpha -= 2;
367 | return end * 0.5f * (alpha * alpha * alpha * alpha * alpha + 2) + start;
368 | }
369 |
370 | static float EaseInSine(float start, float end, float alpha)
371 | {
372 | end -= start;
373 | return -end * std::cos(alpha * (PI * 0.5f)) + end + start;
374 | }
375 |
376 | static float EaseOutSine(float start, float end, float alpha)
377 | {
378 | end -= start;
379 | return end * std::sin(alpha * (PI * 0.5f)) + start;
380 | }
381 |
382 | static float EaseInOutSine(float start, float end, float alpha)
383 | {
384 | end -= start;
385 | return -end * 0.5f * (std::cos(PI * alpha) - 1) + start;
386 | }
387 |
388 | static float EaseInExpo(float start, float end, float alpha)
389 | {
390 | end -= start;
391 | return end * std::pow(2, 10 * (alpha - 1)) + start;
392 | }
393 |
394 | static float EaseOutExpo(float start, float end, float alpha)
395 | {
396 | end -= start;
397 | return end * (-std::pow(2, -10 * alpha) + 1) + start;
398 | }
399 |
400 | static float EaseInOutExpo(float start, float end, float alpha)
401 | {
402 | alpha /= 0.5f;
403 | end -= start;
404 |
405 | if (alpha < 1)
406 | return end * 0.5f * std::pow(2, 10 * (alpha - 1)) + start;
407 |
408 | alpha--;
409 |
410 | return end * 0.5f * (-std::pow(2, -10 * alpha) + 2) + start;
411 | }
412 |
413 | static float EaseInCirc(float start, float end, float alpha)
414 | {
415 | end -= start;
416 | return -end * (std::sqrt(1 - alpha * alpha) - 1) + start;
417 | }
418 |
419 | static float EaseOutCirc(float start, float end, float alpha)
420 | {
421 | alpha--;
422 | end -= start;
423 | return end * std::sqrt(1 - alpha * alpha) + start;
424 | }
425 |
426 | static float EaseInOutCirc(float start, float end, float alpha)
427 | {
428 | alpha /= 0.5f;
429 | end -= start;
430 | if (alpha < 1) return -end * 0.5f * (std::sqrt(1 - alpha * alpha) - 1) + start;
431 | alpha -= 2;
432 | return end * 0.5f * (std::sqrt(1 - alpha * alpha) + 1) + start;
433 | }
434 |
435 | static float EaseOutBounce(float start, float end, float alpha)
436 | {
437 | alpha /= 1.0f;
438 | end -= start;
439 | if (alpha < (1 / 2.75f))
440 | {
441 | return end * (7.5625f * alpha * alpha) + start;
442 | }
443 | else if (alpha < (2 / 2.75f))
444 | {
445 | alpha -= (1.5f / 2.75f);
446 | return end * (7.5625f * (alpha) * alpha + 0.75f) + start;
447 | }
448 | else if (alpha < (2.5 / 2.75))
449 | {
450 | alpha -= (2.25f / 2.75f);
451 | return end * (7.5625f * (alpha) * alpha + .9375f) + start;
452 | }
453 | else
454 | {
455 | alpha -= (2.625f / 2.75f);
456 | return end * (7.5625f * (alpha) * alpha + .984375f) + start;
457 | }
458 | }
459 |
460 | static float EaseInBounce(float start, float end, float alpha)
461 | {
462 | end -= start;
463 | float d = 1.0f;
464 | return end - EaseOutBounce(0, end, d - alpha) + start;
465 | }
466 |
467 | static float EaseInOutBounce(float start, float end, float alpha)
468 | {
469 | end -= start;
470 | float d = 1.0f;
471 | if (alpha < d * 0.5f) return EaseInBounce(0, end, alpha * 2) * 0.5f + start;
472 | else return EaseOutBounce(0, end, alpha * 2 - d) * 0.5f + end * 0.5f + start;
473 | }
474 |
475 | static float EaseInBack(float start, float end, float alpha)
476 | {
477 | end -= start;
478 | alpha /= 1;
479 | float s = 1.70158f;
480 | return end * (alpha) * alpha * ((s + 1) * alpha - s) + start;
481 | }
482 |
483 | static float EaseOutBack(float start, float end, float alpha)
484 | {
485 | float s = 1.70158f;
486 | end -= start;
487 | alpha = (alpha) - 1;
488 | return end * ((alpha) * alpha * ((s + 1) * alpha + s) + 1) + start;
489 | }
490 |
491 | static float EaseInOutBack(float start, float end, float alpha)
492 | {
493 | float s = 1.70158f;
494 | end -= start;
495 | alpha /= 0.5f;
496 | if ((alpha) < 1)
497 | {
498 | s *= (1.525f);
499 | return end * 0.5f * (alpha * alpha * (((s) + 1) * alpha - s)) + start;
500 | }
501 | alpha -= 2;
502 | s *= (1.525f);
503 | return end * 0.5f * ((alpha) * alpha * (((s) + 1) * alpha + s) + 2) + start;
504 | }
505 |
506 | static float EaseInElastic(float start, float end, float alpha)
507 | {
508 | end -= start;
509 |
510 | float d = 1.0f;
511 | float p = d * 0.3f;
512 | float s;
513 | float a = 0;
514 |
515 | if (alpha == 0)
516 | return start;
517 |
518 | if ((alpha /= d) == 1)
519 | return start + end;
520 |
521 | if (a == 0.0f || a < std::abs(end))
522 | {
523 | a = end;
524 | s = p / 4;
525 | }
526 | else
527 | s = p / (2 * PI) * std::asin(end / a);
528 |
529 | return -(a * std::pow(2, 10 * (alpha -= 1)) * std::sin((alpha * d - s) * (2 * PI) / p)) + start;
530 | }
531 |
532 | static float EaseOutElastic(float start, float end, float alpha)
533 | {
534 | end -= start;
535 |
536 | float d = 1.0f;
537 | float p = d * 0.3f;
538 | float s;
539 | float a = 0;
540 |
541 | if (alpha == 0) return start;
542 |
543 | if ((alpha /= d) == 1) return start + end;
544 |
545 | if (a == 0.0f || a < std::abs(end))
546 | {
547 | a = end;
548 | s = p * 0.25f;
549 | }
550 | else
551 | {
552 | s = p / (2 * PI) * std::asin(end / a);
553 | }
554 |
555 | return (a * std::pow(2, -10 * alpha) * std::sin((alpha * d - s) * (2 * PI) / p) + end + start);
556 | }
557 |
558 | static float EaseInOutElastic(float start, float end, float alpha)
559 | {
560 | end -= start;
561 |
562 | float d = 1.0f;
563 | float p = d * 0.3f;
564 | float s;
565 | float a = 0;
566 |
567 | if (alpha == 0) return start;
568 |
569 | if ((alpha /= d * 0.5f) == 2) return start + end;
570 |
571 | if (a == 0.0f || a < std::abs(end))
572 | {
573 | a = end;
574 | s = p / 4;
575 | }
576 | else
577 | {
578 | s = p / (2 * PI) * std::asin(end / a);
579 | }
580 |
581 | if (alpha < 1) return -0.5f * (a * std::pow(2, 10 * (alpha -= 1)) * std::sin((alpha * d - s) * (2 * PI) / p)) + start;
582 | return a * std::pow(2, -10 * (alpha -= 1)) * std::sin((alpha * d - s) * (2 * PI) / p) * 0.5f + end + start;
583 | }
584 |
585 | //
586 | // These are derived functions that the motor can use to get the speed at a specific time.
587 | //
588 | // The easing functions all work with a normalized time (0 to 1) and the returned alpha here
589 | // reflects that. Values returned here should be divided by the actual time.
590 | //
591 | // TODO: These functions have not had the testing they deserve. If there is odd behavior around
592 | // dash speeds then this would be the first place I'd look.
593 |
594 | template
595 | static float LinearD(T start, T end, T alpha)
596 | {
597 | return end - start;
598 | }
599 |
600 | template
601 | static float EaseInQuadD(T start, T end, T alpha)
602 | {
603 | return T(2.0f) * (end - start) * alpha;
604 | }
605 |
606 | template
607 | static float EaseOutQuadD(T start, T end, T alpha)
608 | {
609 | end -= start;
610 | return -end * alpha - end * (alpha - T(2.0f));
611 | }
612 |
613 | static float EaseInOutQuadD(float start, float end, float alpha)
614 | {
615 | alpha /= 0.5f;
616 | end -= start;
617 |
618 | if (alpha < 1)
619 | {
620 | return end * alpha;
621 | }
622 |
623 | alpha--;
624 |
625 | return end * (1 - alpha);
626 | }
627 |
628 | static float EaseInCubicD(float start, float end, float alpha)
629 | {
630 | return 3.0f * (end - start) * alpha * alpha;
631 | }
632 |
633 | static float EaseOutCubicD(float start, float end, float alpha)
634 | {
635 | alpha--;
636 | end -= start;
637 | return 3.0f * end * alpha * alpha;
638 | }
639 |
640 | static float EaseInOutCubicD(float start, float end, float alpha)
641 | {
642 | alpha /= 0.5f;
643 | end -= start;
644 |
645 | if (alpha < 1)
646 | {
647 | return (3.0f / 2.0f) * end * alpha * alpha;
648 | }
649 |
650 | alpha -= 2;
651 |
652 | return (3.0f / 2.0f) * end * alpha * alpha;
653 | }
654 |
655 | static float EaseInQuartD(float start, float end, float alpha)
656 | {
657 | return 4.0f * (end - start) * alpha * alpha * alpha;
658 | }
659 |
660 | static float EaseOutQuartD(float start, float end, float alpha)
661 | {
662 | alpha--;
663 | end -= start;
664 | return -4.0f * end * alpha * alpha * alpha;
665 | }
666 |
667 | static float EaseInOutQuartD(float start, float end, float alpha)
668 | {
669 | alpha /= 0.5f;
670 | end -= start;
671 |
672 | if (alpha < 1)
673 | {
674 | return 2.0f * end * alpha * alpha * alpha;
675 | }
676 |
677 | alpha -= 2;
678 |
679 | return -2.0f * end * alpha * alpha * alpha;
680 | }
681 |
682 | static float EaseInQuintD(float start, float end, float alpha)
683 | {
684 | return 5.0f * (end - start) * alpha * alpha * alpha * alpha;
685 | }
686 |
687 | static float EaseOutQuintD(float start, float end, float alpha)
688 | {
689 | alpha--;
690 | end -= start;
691 | return 5.0f * end * alpha * alpha * alpha * alpha;
692 | }
693 |
694 | static float EaseInOutQuintD(float start, float end, float alpha)
695 | {
696 | alpha /= 0.5f;
697 | end -= start;
698 |
699 | if (alpha < 1)
700 | {
701 | return (5.0f / 2.0f) * end * alpha * alpha * alpha * alpha;
702 | }
703 |
704 | alpha -= 2;
705 |
706 | return (5.0f / 2.0f) * end * alpha * alpha * alpha * alpha;
707 | }
708 |
709 | static float EaseInSineD(float start, float end, float alpha)
710 | {
711 | return (end - start) * 0.5f * PI * std::sin(0.5f * PI * alpha);
712 | }
713 |
714 | static float EaseOutSineD(float start, float end, float alpha)
715 | {
716 | end -= start;
717 | return (PI * 0.5f) * end * std::cos(alpha * (PI * 0.5f));
718 | }
719 |
720 | static float EaseInOutSineD(float start, float end, float alpha)
721 | {
722 | end -= start;
723 | return end * 0.5f * PI * std::sin(PI * alpha);
724 | }
725 |
726 | static float EaseInExpoD(float start, float end, float alpha)
727 | {
728 | return 10.0f * NATURAL_LOG_OF_2 * (end - start) * std::pow(2.0f, 10.0f * (alpha - 1));
729 | }
730 |
731 | static float EaseOutExpoD(float start, float end, float alpha)
732 | {
733 | end -= start;
734 | return 5.0f * NATURAL_LOG_OF_2 * end * std::pow(2.0f, 1.0f - 10.0f * alpha);
735 | }
736 |
737 | static float EaseInOutExpoD(float start, float end, float alpha)
738 | {
739 | alpha /= 0.5f;
740 | end -= start;
741 |
742 | if (alpha < 1)
743 | return 5.0f * NATURAL_LOG_OF_2 * end * std::pow(2.0f, 10.0f * (alpha - 1));
744 |
745 | alpha--;
746 |
747 | return (5.0f * NATURAL_LOG_OF_2 * end) / (std::pow(2.0f, 10.0f * alpha));
748 | }
749 |
750 | static float EaseInCircD(float start, float end, float alpha)
751 | {
752 | return (end - start) * alpha / std::sqrt(1.0f - alpha * alpha);
753 | }
754 |
755 | static float EaseOutCircD(float start, float end, float alpha)
756 | {
757 | alpha--;
758 | end -= start;
759 | return (-end * alpha) / std::sqrt(1.0f - alpha * alpha);
760 | }
761 |
762 | static float EaseInOutCircD(float start, float end, float alpha)
763 | {
764 | alpha /= 0.5f;
765 | end -= start;
766 |
767 | if (alpha < 1)
768 | {
769 | return (end * alpha) / (2.0f * std::sqrt(1.0f - alpha * alpha));
770 | }
771 |
772 | alpha -= 2;
773 |
774 | return (-end * alpha) / (2.0f * std::sqrt(1.0f - alpha * alpha));
775 | }
776 |
777 | static float EaseInBounceD(float start, float end, float alpha)
778 | {
779 | end -= start;
780 | float d = 1.0f;
781 |
782 | return EaseOutBounceD(0, end, d - alpha);
783 | }
784 |
785 | static float EaseOutBounceD(float start, float end, float alpha)
786 | {
787 | alpha /= 1.0f;
788 | end -= start;
789 |
790 | if (alpha < (1 / 2.75f))
791 | {
792 | return 2.0f * end * 7.5625f * alpha;
793 | }
794 | else if (alpha < (2 / 2.75f))
795 | {
796 | alpha -= (1.5f / 2.75f);
797 | return 2.0f * end * 7.5625f * alpha;
798 | }
799 | else if (alpha < (2.5 / 2.75))
800 | {
801 | alpha -= (2.25f / 2.75f);
802 | return 2.0f * end * 7.5625f * alpha;
803 | }
804 | else
805 | {
806 | alpha -= (2.625f / 2.75f);
807 | return 2.0f * end * 7.5625f * alpha;
808 | }
809 | }
810 |
811 | static float EaseInOutBounceD(float start, float end, float alpha)
812 | {
813 | end -= start;
814 | float d = 1.0f;
815 |
816 | return alpha < d * 0.5f ? EaseInBounceD(0, end, alpha * 2) * 0.5f : EaseOutBounceD(0, end, alpha * 2 - d) * 0.5f;
817 | }
818 |
819 | static float EaseInBackD(float start, float end, float alpha)
820 | {
821 | const float s = 1.70158f;
822 | return 3.0f * (s + 1.0f) * (end - start) * alpha * alpha - 2.0f * s * (end - start) * alpha;
823 | }
824 |
825 | static float EaseOutBackD(float start, float end, float alpha)
826 | {
827 | const float s = 1.70158f;
828 | end -= start;
829 | alpha = (alpha) - 1;
830 |
831 | return end * ((s + 1.0f) * alpha * alpha + 2.0f * alpha * ((s + 1.0f) * alpha + s));
832 | }
833 |
834 | static float EaseInOutBackD(float start, float end, float alpha)
835 | {
836 | float s = 1.70158f;
837 | end -= start;
838 | alpha /= 0.5f;
839 |
840 | if ((alpha) < 1)
841 | {
842 | s *= (1.525f);
843 | return 0.5f * end * (s + 1) * alpha * alpha + end * alpha * ((s + 1.0f) * alpha - s);
844 | }
845 |
846 | alpha -= 2;
847 | s *= (1.525f);
848 | return 0.5f * end * ((s + 1) * alpha * alpha + 2.0f * alpha * ((s + 1.0f) * alpha + s));
849 | }
850 |
851 | static float EaseInElasticD(float start, float end, float alpha)
852 | {
853 | return EaseOutElasticD(start, end, 1.0f - alpha);
854 | }
855 |
856 | static float EaseOutElasticD(float start, float end, float alpha)
857 | {
858 | end -= start;
859 |
860 | float d = 1.0f;
861 | float p = d * 0.3f;
862 | float s;
863 | float a = 0;
864 |
865 | if (a == 0.0f || a < std::abs(end))
866 | {
867 | a = end;
868 | s = p * 0.25f;
869 | }
870 | else
871 | {
872 | s = p / (2 * PI) * std::asin(end / a);
873 | }
874 |
875 | return (a * PI * d * std::pow(2.0f, 1.0f - 10.0f * alpha) *
876 | std::cos((2.0f * PI * (d * alpha - s)) / p)) / p - 5.0f * NATURAL_LOG_OF_2 * a *
877 | std::pow(2.0f, 1.0f - 10.0f * alpha) * std::sin((2.0f * PI * (d * alpha - s)) / p);
878 | }
879 |
880 | static float EaseInOutElasticD(float start, float end, float alpha)
881 | {
882 | end -= start;
883 |
884 | float d = 1.0f;
885 | float p = d * 0.3f;
886 | float s;
887 | float a = 0;
888 |
889 | if (a == 0.0f || a < std::abs(end))
890 | {
891 | a = end;
892 | s = p / 4;
893 | }
894 | else
895 | {
896 | s = p / (2 * PI) * std::asin(end / a);
897 | }
898 |
899 | if (alpha < 1)
900 | {
901 | alpha -= 1;
902 |
903 | return -5.0f * NATURAL_LOG_OF_2 * a * std::pow(2.0f, 10.0f * alpha) * std::sin(2 * PI * (d * alpha - 2.0f) / p) -
904 | a * PI * d * std::pow(2.0f, 10.0f * alpha) * std::cos(2 * PI * (d * alpha - s) / p) / p;
905 | }
906 |
907 | alpha -= 1;
908 |
909 | return a * PI * d * std::cos(2.0f * PI * (d * alpha - s) / p) / (p * std::pow(2.0f, 10.0f * alpha)) -
910 | 5.0f * NATURAL_LOG_OF_2 * a * std::sin(2.0f * PI * (d * alpha - s) / p) / (std::pow(2.0f, 10.0f * alpha));
911 | }
912 |
913 | static float SpringD(float start, float end, float alpha)
914 | {
915 | alpha = Clamp(alpha, 0.0f, 1.0f);
916 | end -= start;
917 |
918 | // Damn... Thanks http://www.derivative-calculator.net/
919 | // TODO: And it's a little bit wrong
920 | return end * (6.0f * (1.0f - alpha) / 5.0f + 1.0f) * (-2.0f * std::pow(1.0f - alpha, 1.2f) *
921 | std::sin(PI * alpha * (2.5f * alpha * alpha * alpha + 0.2f)) + std::pow(1.0f - alpha, 2.2f) *
922 | (PI * (2.5f * alpha * alpha * alpha + 0.2f) + 7.5f * PI * alpha * alpha * alpha) *
923 | std::cos(PI * alpha * (2.5f * alpha * alpha * alpha + 0.2f)) + 1.0f) -
924 | 6.0f * end * (std::pow(1 - alpha, 2.2f) * std::sin(PI * alpha * (2.5f * alpha * alpha * alpha + 0.2f)) + alpha
925 | / 5.0f);
926 |
927 | }
928 | };
--------------------------------------------------------------------------------
/native_csharp/EasingFunctions.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Created by C.J. Kimberlin
3 | *
4 | * The MIT License (MIT)
5 | *
6 | * Copyright (c) 2019
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in all
16 | * copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | *
26 | *
27 | * TERMS OF USE - EASING EQUATIONS
28 | * Open source under the BSD License.
29 | * Copyright (c)2001 Robert Penner
30 | * All rights reserved.
31 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
32 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
33 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
34 | * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
35 | *
36 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
37 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
38 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 | *
42 | *
43 | * ============= Description =============
44 | *
45 | * Below is an example of how to use the easing functions in the file. There is a getting function that will return the function
46 | * from an enum. This is useful since the enum can be exposed in the editor and then the function queried during Start().
47 | *
48 | * EasingFunction.Ease ease = EasingFunction.Ease.EaseInOutQuad;
49 | * EasingFunction.EasingFunc func = GetEasingFunction(ease;
50 | *
51 | * float value = func(0, 10, 0.67f);
52 | *
53 | * EasingFunction.EaseingFunc derivativeFunc = GetEasingFunctionDerivative(ease);
54 | *
55 | * float derivativeValue = derivativeFunc(0, 10, 0.67f);
56 | */
57 |
58 | public static class EasingFunction
59 | {
60 | public enum EaseType : byte
61 | {
62 | EaseInQuad = 0,
63 | EaseOutQuad,
64 | EaseInOutQuad,
65 | EaseInCubic,
66 | EaseOutCubic,
67 | EaseInOutCubic,
68 | EaseInQuart,
69 | EaseOutQuart,
70 | EaseInOutQuart,
71 | EaseInQuint,
72 | EaseOutQuint,
73 | EaseInOutQuint,
74 | EaseInSine,
75 | EaseOutSine,
76 | EaseInOutSine,
77 | EaseInExpo,
78 | EaseOutExpo,
79 | EaseInOutExpo,
80 | EaseInCirc,
81 | EaseOutCirc,
82 | EaseInOutCirc,
83 | Linear,
84 | Spring,
85 | EaseInBounce,
86 | EaseOutBounce,
87 | EaseInOutBounce,
88 | EaseInBack,
89 | EaseOutBack,
90 | EaseInOutBack,
91 | EaseInElastic,
92 | EaseOutElastic,
93 | EaseInOutElastic,
94 | }
95 |
96 | private const float NATURAL_LOG_OF_2 = 0.693147181f;
97 |
98 | /// Easing functions ///
99 |
100 | public static float Linear(float start, float end, float value) => Mathf.Lerp(start, end, value);
101 |
102 | public static float Spring(float start, float end, float value)
103 | {
104 | value = Mathf.Clamp01(value);
105 | value = (Mathf.Sin(value * Mathf.PI * (0.2f + 2.5f * value * value * value)) * Mathf.Pow(1f - value, 2.2f) + value) * (1f + (1.2f * (1f - value)));
106 | return start + (end - start) * value;
107 | }
108 |
109 | public static float EaseInQuad(float start, float end, float value)
110 | {
111 | end -= start;
112 | return end * value * value + start;
113 | }
114 |
115 | public static float EaseOutQuad(float start, float end, float value)
116 | {
117 | end -= start;
118 | return -end * value * (value - 2) + start;
119 | }
120 |
121 | public static float EaseInOutQuad(float start, float end, float value)
122 | {
123 | value /= .5f;
124 | end -= start;
125 | if (value < 1) return end * 0.5f * value * value + start;
126 | value--;
127 | return -end * 0.5f * (value * (value - 2) - 1) + start;
128 | }
129 |
130 | public static float EaseInCubic(float start, float end, float value)
131 | {
132 | end -= start;
133 | return end * value * value * value + start;
134 | }
135 |
136 | public static float EaseOutCubic(float start, float end, float value)
137 | {
138 | value--;
139 | end -= start;
140 | return end * (value * value * value + 1) + start;
141 | }
142 |
143 | public static float EaseInOutCubic(float start, float end, float value)
144 | {
145 | value /= .5f;
146 | end -= start;
147 | if (value < 1) return end * 0.5f * value * value * value + start;
148 | value -= 2;
149 | return end * 0.5f * (value * value * value + 2) + start;
150 | }
151 |
152 | public static float EaseInQuart(float start, float end, float value)
153 | {
154 | end -= start;
155 | return end * value * value * value * value + start;
156 | }
157 |
158 | public static float EaseOutQuart(float start, float end, float value)
159 | {
160 | value--;
161 | end -= start;
162 | return -end * (value * value * value * value - 1) + start;
163 | }
164 |
165 | public static float EaseInOutQuart(float start, float end, float value)
166 | {
167 | value /= .5f;
168 | end -= start;
169 | if (value < 1) return end * 0.5f * value * value * value * value + start;
170 | value -= 2;
171 | return -end * 0.5f * (value * value * value * value - 2) + start;
172 | }
173 |
174 | public static float EaseInQuint(float start, float end, float value)
175 | {
176 | end -= start;
177 | return end * value * value * value * value * value + start;
178 | }
179 |
180 | public static float EaseOutQuint(float start, float end, float value)
181 | {
182 | value--;
183 | end -= start;
184 | return end * (value * value * value * value * value + 1) + start;
185 | }
186 |
187 | public static float EaseInOutQuint(float start, float end, float value)
188 | {
189 | value /= .5f;
190 | end -= start;
191 | if (value < 1) return end * 0.5f * value * value * value * value * value + start;
192 | value -= 2;
193 | return end * 0.5f * (value * value * value * value * value + 2) + start;
194 | }
195 |
196 | public static float EaseInSine(float start, float end, float value)
197 | {
198 | end -= start;
199 | return -end * Mathf.Cos(value * (Mathf.PI * 0.5f)) + end + start;
200 | }
201 |
202 | public static float EaseOutSine(float start, float end, float value)
203 | {
204 | end -= start;
205 | return end * Mathf.Sin(value * (Mathf.PI * 0.5f)) + start;
206 | }
207 |
208 | public static float EaseInOutSine(float start, float end, float value)
209 | {
210 | end -= start;
211 | return -end * 0.5f * (Mathf.Cos(Mathf.PI * value) - 1) + start;
212 | }
213 |
214 | public static float EaseInExpo(float start, float end, float value)
215 | {
216 | end -= start;
217 | return end * Mathf.Pow(2, 10 * (value - 1)) + start;
218 | }
219 |
220 | public static float EaseOutExpo(float start, float end, float value)
221 | {
222 | end -= start;
223 | return end * (-Mathf.Pow(2, -10 * value) + 1) + start;
224 | }
225 |
226 | public static float EaseInOutExpo(float start, float end, float value)
227 | {
228 | value /= .5f;
229 | end -= start;
230 |
231 | if (value < 1)
232 | return end * 0.5f * Mathf.Pow(2, 10 * (value - 1)) + start;
233 |
234 | value--;
235 |
236 | return end * 0.5f * (-Mathf.Pow(2, -10 * value) + 2) + start;
237 | }
238 |
239 | public static float EaseInCirc(float start, float end, float value)
240 | {
241 | end -= start;
242 | return -end * (Mathf.Sqrt(1 - value * value) - 1) + start;
243 | }
244 |
245 | public static float EaseOutCirc(float start, float end, float value)
246 | {
247 | value--;
248 | end -= start;
249 | return end * Mathf.Sqrt(1 - value * value) + start;
250 | }
251 |
252 | public static float EaseInOutCirc(float start, float end, float value)
253 | {
254 | value /= .5f;
255 | end -= start;
256 | if (value < 1) return -end * 0.5f * (Mathf.Sqrt(1 - value * value) - 1) + start;
257 | value -= 2;
258 | return end * 0.5f * (Mathf.Sqrt(1 - value * value) + 1) + start;
259 | }
260 |
261 | public static float EaseInBounce(float start, float end, float value)
262 | {
263 | end -= start;
264 | float d = 1f;
265 | return end - EaseOutBounce(0, end, d - value) + start;
266 | }
267 |
268 | public static float EaseOutBounce(float start, float end, float value)
269 | {
270 | value /= 1f;
271 | end -= start;
272 | if (value < (1 / 2.75f))
273 | {
274 | return end * (7.5625f * value * value) + start;
275 | }
276 | else if (value < (2 / 2.75f))
277 | {
278 | value -= (1.5f / 2.75f);
279 | return end * (7.5625f * (value) * value + .75f) + start;
280 | }
281 | else if (value < (2.5 / 2.75))
282 | {
283 | value -= (2.25f / 2.75f);
284 | return end * (7.5625f * (value) * value + .9375f) + start;
285 | }
286 | else
287 | {
288 | value -= (2.625f / 2.75f);
289 | return end * (7.5625f * (value) * value + .984375f) + start;
290 | }
291 | }
292 |
293 | public static float EaseInOutBounce(float start, float end, float value)
294 | {
295 | end -= start;
296 | float d = 1f;
297 | if (value < d * 0.5f) return EaseInBounce(0, end, value * 2) * 0.5f + start;
298 | else return EaseOutBounce(0, end, value * 2 - d) * 0.5f + end * 0.5f + start;
299 | }
300 |
301 | public static float EaseInBack(float start, float end, float value)
302 | {
303 | end -= start;
304 | value /= 1;
305 | float s = 1.70158f;
306 | return end * (value) * value * ((s + 1) * value - s) + start;
307 | }
308 |
309 | public static float EaseOutBack(float start, float end, float value)
310 | {
311 | float s = 1.70158f;
312 | end -= start;
313 | value = (value) - 1;
314 | return end * ((value) * value * ((s + 1) * value + s) + 1) + start;
315 | }
316 |
317 | public static float EaseInOutBack(float start, float end, float value)
318 | {
319 | float s = 1.70158f;
320 | end -= start;
321 | value /= .5f;
322 | if ((value) < 1)
323 | {
324 | s *= (1.525f);
325 | return end * 0.5f * (value * value * (((s) + 1) * value - s)) + start;
326 | }
327 | value -= 2;
328 | s *= (1.525f);
329 | return end * 0.5f * ((value) * value * (((s) + 1) * value + s) + 2) + start;
330 | }
331 |
332 | public static float EaseInElastic(float start, float end, float value)
333 | {
334 | end -= start;
335 |
336 | float d = 1f;
337 | float p = d * .3f;
338 | float s;
339 | float a = 0;
340 |
341 | if (value == 0)
342 | return start;
343 |
344 | if ((value /= d) == 1)
345 | return start + end;
346 |
347 | if (a == 0f || a < Mathf.Abs(end))
348 | {
349 | a = end;
350 | s = p / 4;
351 | }
352 | else
353 | s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
354 |
355 | return -(a * Mathf.Pow(2, 10 * (value -= 1)) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p)) + start;
356 | }
357 |
358 | public static float EaseOutElastic(float start, float end, float value)
359 | {
360 | end -= start;
361 |
362 | float d = 1f;
363 | float p = d * .3f;
364 | float s;
365 | float a = 0;
366 |
367 | if (value == 0) return start;
368 |
369 | if ((value /= d) == 1) return start + end;
370 |
371 | if (a == 0f || a < Mathf.Abs(end))
372 | {
373 | a = end;
374 | s = p * 0.25f;
375 | }
376 | else
377 | {
378 | s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
379 | }
380 |
381 | return (a * Mathf.Pow(2, -10 * value) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p) + end + start);
382 | }
383 |
384 | public static float EaseInOutElastic(float start, float end, float value)
385 | {
386 | end -= start;
387 |
388 | float d = 1f;
389 | float p = d * .3f;
390 | float s;
391 | float a = 0;
392 |
393 | if (value == 0) return start;
394 |
395 | if ((value /= d * 0.5f) == 2) return start + end;
396 |
397 | if (a == 0f || a < Mathf.Abs(end))
398 | {
399 | a = end;
400 | s = p / 4;
401 | }
402 | else
403 | {
404 | s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
405 | }
406 |
407 | if (value < 1) return -0.5f * (a * Mathf.Pow(2, 10 * (value -= 1)) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p)) + start;
408 | return a * Mathf.Pow(2, -10 * (value -= 1)) * Mathf.Sin((value * d - s) * (2 * Mathf.PI) / p) * 0.5f + end + start;
409 | }
410 |
411 | //
412 | // These are derived functions that the motor can use to get the speed at a specific time.
413 | //
414 | // The easing functions all work with a normalized time (0 to 1) and the returned value here
415 | // reflects that. Values returned here should be divided by the actual time.
416 | //
417 | // TODO: These functions have not had the testing they deserve. If there is odd behavior around
418 | // dash speeds then this would be the first place I'd look.
419 |
420 | public static float LinearD(float start, float end, float value) => end - start;
421 |
422 | public static float EaseInQuadD(float start, float end, float value) => 2f * (end - start) * value;
423 |
424 | public static float EaseOutQuadD(float start, float end, float value)
425 | {
426 | end -= start;
427 | return -end * value - end * (value - 2);
428 | }
429 |
430 | public static float EaseInOutQuadD(float start, float end, float value)
431 | {
432 | value /= .5f;
433 | end -= start;
434 |
435 | if (value < 1)
436 | {
437 | return end * value;
438 | }
439 |
440 | value--;
441 |
442 | return end * (1 - value);
443 | }
444 |
445 | public static float EaseInCubicD(float start, float end, float value) => 3f * (end - start) * value * value;
446 |
447 | public static float EaseOutCubicD(float start, float end, float value)
448 | {
449 | value--;
450 | end -= start;
451 | return 3f * end * value * value;
452 | }
453 |
454 | public static float EaseInOutCubicD(float start, float end, float value)
455 | {
456 | value /= .5f;
457 | end -= start;
458 |
459 | if (value < 1)
460 | {
461 | return (3f / 2f) * end * value * value;
462 | }
463 |
464 | value -= 2;
465 |
466 | return (3f / 2f) * end * value * value;
467 | }
468 |
469 | public static float EaseInQuartD(float start, float end, float value)
470 | {
471 | return 4f * (end - start) * value * value * value;
472 | }
473 |
474 | public static float EaseOutQuartD(float start, float end, float value)
475 | {
476 | value--;
477 | end -= start;
478 | return -4f * end * value * value * value;
479 | }
480 |
481 | public static float EaseInOutQuartD(float start, float end, float value)
482 | {
483 | value /= .5f;
484 | end -= start;
485 |
486 | if (value < 1)
487 | {
488 | return 2f * end * value * value * value;
489 | }
490 |
491 | value -= 2;
492 |
493 | return -2f * end * value * value * value;
494 | }
495 |
496 | public static float EaseInQuintD(float start, float end, float value)
497 | {
498 | return 5f * (end - start) * value * value * value * value;
499 | }
500 |
501 | public static float EaseOutQuintD(float start, float end, float value)
502 | {
503 | value--;
504 | end -= start;
505 | return 5f * end * value * value * value * value;
506 | }
507 |
508 | public static float EaseInOutQuintD(float start, float end, float value)
509 | {
510 | value /= .5f;
511 | end -= start;
512 |
513 | if (value < 1)
514 | {
515 | return (5f / 2f) * end * value * value * value * value;
516 | }
517 |
518 | value -= 2;
519 |
520 | return (5f / 2f) * end * value * value * value * value;
521 | }
522 |
523 | public static float EaseInSineD(float start, float end, float value)
524 | {
525 | return (end - start) * 0.5f * Mathf.PI * Mathf.Sin(0.5f * Mathf.PI * value);
526 | }
527 |
528 | public static float EaseOutSineD(float start, float end, float value)
529 | {
530 | end -= start;
531 | return (Mathf.PI * 0.5f) * end * Mathf.Cos(value * (Mathf.PI * 0.5f));
532 | }
533 |
534 | public static float EaseInOutSineD(float start, float end, float value)
535 | {
536 | end -= start;
537 | return end * 0.5f * Mathf.PI * Mathf.Sin(Mathf.PI * value);
538 | }
539 |
540 | public static float EaseInExpoD(float start, float end, float value) => 10f * NATURAL_LOG_OF_2 * (end - start) * Mathf.Pow(2f, 10f * (value - 1));
541 |
542 | public static float EaseOutExpoD(float start, float end, float value)
543 | {
544 | end -= start;
545 | return 5f * NATURAL_LOG_OF_2 * end * Mathf.Pow(2f, 1f - 10f * value);
546 | }
547 |
548 | public static float EaseInOutExpoD(float start, float end, float value)
549 | {
550 | value /= .5f;
551 | end -= start;
552 |
553 | if (value < 1)
554 | return 5f * NATURAL_LOG_OF_2 * end * Mathf.Pow(2f, 10f * (value - 1));
555 |
556 | value--;
557 |
558 | return (5f * NATURAL_LOG_OF_2 * end) / (Mathf.Pow(2f, 10f * value));
559 | }
560 |
561 | public static float EaseInCircD(float start, float end, float value) => (end - start) * value / Mathf.Sqrt(1f - value * value);
562 |
563 | public static float EaseOutCircD(float start, float end, float value)
564 | {
565 | value--;
566 | end -= start;
567 | return (-end * value) / Mathf.Sqrt(1f - value * value);
568 | }
569 |
570 | public static float EaseInOutCircD(float start, float end, float value)
571 | {
572 | value /= .5f;
573 | end -= start;
574 |
575 | if (value < 1)
576 | {
577 | return (end * value) / (2f * Mathf.Sqrt(1f - value * value));
578 | }
579 |
580 | value -= 2;
581 |
582 | return (-end * value) / (2f * Mathf.Sqrt(1f - value * value));
583 | }
584 |
585 | public static float EaseInBounceD(float start, float end, float value)
586 | {
587 | end -= start;
588 | float d = 1f;
589 |
590 | return EaseOutBounceD(0, end, d - value);
591 | }
592 |
593 | public static float EaseOutBounceD(float start, float end, float value)
594 | {
595 | value /= 1f;
596 | end -= start;
597 |
598 | if (value < (1 / 2.75f))
599 | {
600 | return 2f * end * 7.5625f * value;
601 | }
602 | else if (value < (2 / 2.75f))
603 | {
604 | value -= (1.5f / 2.75f);
605 | return 2f * end * 7.5625f * value;
606 | }
607 | else if (value < (2.5 / 2.75))
608 | {
609 | value -= (2.25f / 2.75f);
610 | return 2f * end * 7.5625f * value;
611 | }
612 | else
613 | {
614 | value -= (2.625f / 2.75f);
615 | return 2f * end * 7.5625f * value;
616 | }
617 | }
618 |
619 | public static float EaseInOutBounceD(float start, float end, float value)
620 | {
621 | end -= start;
622 | float d = 1f;
623 |
624 | return value < d * 0.5f ? EaseInBounceD(0, end, value * 2) * 0.5f : EaseOutBounceD(0, end, value * 2 - d) * 0.5f;
625 | }
626 |
627 | public static float EaseInBackD(float start, float end, float value)
628 | {
629 | const float s = 1.70158f;
630 | return 3f * (s + 1f) * (end - start) * value * value - 2f * s * (end - start) * value;
631 | }
632 |
633 | public static float EaseOutBackD(float start, float end, float value)
634 | {
635 | const float s = 1.70158f;
636 | end -= start;
637 | value = (value) - 1;
638 |
639 | return end * ((s + 1f) * value * value + 2f * value * ((s + 1f) * value + s));
640 | }
641 |
642 | public static float EaseInOutBackD(float start, float end, float value)
643 | {
644 | float s = 1.70158f;
645 | end -= start;
646 | value /= .5f;
647 |
648 | if ((value) < 1)
649 | {
650 | s *= (1.525f);
651 | return 0.5f * end * (s + 1) * value * value + end * value * ((s + 1f) * value - s);
652 | }
653 |
654 | value -= 2;
655 | s *= (1.525f);
656 | return 0.5f * end * ((s + 1) * value * value + 2f * value * ((s + 1f) * value + s));
657 | }
658 |
659 | public static float EaseInElasticD(float start, float end, float value)
660 | {
661 | return EaseOutElasticD(start, end, 1f - value);
662 | }
663 |
664 | public static float EaseOutElasticD(float start, float end, float value)
665 | {
666 | end -= start;
667 |
668 | float d = 1f;
669 | float p = d * .3f;
670 | float s;
671 | float a = 0;
672 |
673 | if (a == 0f || a < Mathf.Abs(end))
674 | {
675 | a = end;
676 | s = p * 0.25f;
677 | }
678 | else
679 | {
680 | s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
681 | }
682 |
683 | return (a * Mathf.PI * d * Mathf.Pow(2f, 1f - 10f * value) *
684 | Mathf.Cos((2f * Mathf.PI * (d * value - s)) / p)) / p - 5f * NATURAL_LOG_OF_2 * a *
685 | Mathf.Pow(2f, 1f - 10f * value) * Mathf.Sin((2f * Mathf.PI * (d * value - s)) / p);
686 | }
687 |
688 | public static float EaseInOutElasticD(float start, float end, float value)
689 | {
690 | end -= start;
691 |
692 | float d = 1f;
693 | float p = d * .3f;
694 | float s;
695 | float a = 0;
696 |
697 | if (a == 0f || a < Mathf.Abs(end))
698 | {
699 | a = end;
700 | s = p / 4;
701 | }
702 | else
703 | {
704 | s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
705 | }
706 |
707 | if (value < 1)
708 | {
709 | value -= 1;
710 |
711 | return -5f * NATURAL_LOG_OF_2 * a * Mathf.Pow(2f, 10f * value) * Mathf.Sin(2 * Mathf.PI * (d * value - 2f) / p) -
712 | a * Mathf.PI * d * Mathf.Pow(2f, 10f * value) * Mathf.Cos(2 * Mathf.PI * (d * value - s) / p) / p;
713 | }
714 |
715 | value -= 1;
716 |
717 | return a * Mathf.PI * d * Mathf.Cos(2f * Mathf.PI * (d * value - s) / p) / (p * Mathf.Pow(2f, 10f * value)) -
718 | 5f * NATURAL_LOG_OF_2 * a * Mathf.Sin(2f * Mathf.PI * (d * value - s) / p) / (Mathf.Pow(2f, 10f * value));
719 | }
720 |
721 | public static float SpringD(float start, float end, float value)
722 | {
723 | value = Mathf.Clamp01(value);
724 | end -= start;
725 |
726 | // Damn... Thanks http://www.derivative-calculator.net/
727 | // TODO: And it's a little bit wrong
728 | return end * (6f * (1f - value) / 5f + 1f) * (-2.2f * Mathf.Pow(1f - value, 1.2f) *
729 | Mathf.Sin(Mathf.PI * value * (2.5f * value * value * value + 0.2f)) + Mathf.Pow(1f - value, 2.2f) *
730 | (Mathf.PI * (2.5f * value * value * value + 0.2f) + 7.5f * Mathf.PI * value * value * value) *
731 | Mathf.Cos(Mathf.PI * value * (2.5f * value * value * value + 0.2f)) + 1f) -
732 | 6f * end * (Mathf.Pow(1 - value, 2.2f) * Mathf.Sin(Mathf.PI * value * (2.5f * value * value * value + 0.2f)) + value
733 | / 5f);
734 |
735 | }
736 |
737 | public delegate float Function(float start, float end, float value);
738 |
739 | ///
740 | /// Returns the function associated to the easingFunction enum. This value returned should be cached as it allocates memory
741 | /// to return.
742 | ///
743 | /// The enum associated with the easing function.
744 | /// The easing function
745 | public static Function GetEasingFunction(EaseType type) => type switch
746 | {
747 | EaseType.EaseInQuad => EaseInQuad,
748 | EaseType.EaseOutQuad => EaseOutQuad,
749 | EaseType.EaseInOutQuad => EaseInOutQuad,
750 | EaseType.EaseInCubic => EaseInCubic,
751 | EaseType.EaseOutCubic => EaseOutCubic,
752 | EaseType.EaseInOutCubic => EaseInOutCubic,
753 | EaseType.EaseInQuart => EaseInQuart,
754 | EaseType.EaseOutQuart => EaseOutQuart,
755 | EaseType.EaseInOutQuart => EaseInOutQuart,
756 | EaseType.EaseInQuint => EaseInQuint,
757 | EaseType.EaseOutQuint => EaseOutQuint,
758 | EaseType.EaseInOutQuint => EaseInOutQuint,
759 | EaseType.EaseInSine => EaseInSine,
760 | EaseType.EaseOutSine => EaseOutSine,
761 | EaseType.EaseInOutSine => EaseInOutSine,
762 | EaseType.EaseInExpo => EaseInExpo,
763 | EaseType.EaseOutExpo => EaseOutExpo,
764 | EaseType.EaseInOutExpo => EaseInOutExpo,
765 | EaseType.EaseInCirc => EaseInCirc,
766 | EaseType.EaseOutCirc => EaseOutCirc,
767 | EaseType.EaseInOutCirc => EaseInOutCirc,
768 | EaseType.Linear => Linear,
769 | EaseType.Spring => Spring,
770 | EaseType.EaseInBounce => EaseInBounce,
771 | EaseType.EaseOutBounce => EaseOutBounce,
772 | EaseType.EaseInOutBounce => EaseInOutBounce,
773 | EaseType.EaseInBack => EaseInBack,
774 | EaseType.EaseOutBack => EaseOutBack,
775 | EaseType.EaseInOutBack => EaseInOutBack,
776 | EaseType.EaseInElastic => EaseInElastic,
777 | EaseType.EaseOutElastic => EaseOutElastic,
778 | EaseType.EaseInOutElastic => EaseInOutElastic,
779 | _ => null,
780 | };
781 |
782 | ///
783 | /// Gets the derivative function of the appropriate easing function. If you use an easing function for position then this
784 | /// function can get you the speed at a given time (normalized).
785 | ///
786 | ///
787 | /// The derivative function
788 | public static Function GetEasingFunctionDerivative(EaseType type) => type switch
789 | {
790 | EaseType.EaseInQuad => EaseInQuadD,
791 | EaseType.EaseOutQuad => EaseOutQuadD,
792 | EaseType.EaseInOutQuad => EaseInOutQuadD,
793 | EaseType.EaseInCubic => EaseInCubicD,
794 | EaseType.EaseOutCubic => EaseOutCubicD,
795 | EaseType.EaseInOutCubic => EaseInOutCubicD,
796 | EaseType.EaseInQuart => EaseInQuartD,
797 | EaseType.EaseOutQuart => EaseOutQuartD,
798 | EaseType.EaseInOutQuart => EaseInOutQuartD,
799 | EaseType.EaseInQuint => EaseInQuintD,
800 | EaseType.EaseOutQuint => EaseOutQuintD,
801 | EaseType.EaseInOutQuint => EaseInOutQuintD,
802 | EaseType.EaseInSine => EaseInSineD,
803 | EaseType.EaseOutSine => EaseOutSineD,
804 | EaseType.EaseInOutSine => EaseInOutSineD,
805 | EaseType.EaseInExpo => EaseInExpoD,
806 | EaseType.EaseOutExpo => EaseOutExpoD,
807 | EaseType.EaseInOutExpo => EaseInOutExpoD,
808 | EaseType.EaseInCirc => EaseInCircD,
809 | EaseType.EaseOutCirc => EaseOutCircD,
810 | EaseType.EaseInOutCirc => EaseInOutCircD,
811 | EaseType.Linear => LinearD,
812 | EaseType.Spring => SpringD,
813 | EaseType.EaseInBounce => EaseInBounceD,
814 | EaseType.EaseOutBounce => EaseOutBounceD,
815 | EaseType.EaseInOutBounce => EaseInOutBounceD,
816 | EaseType.EaseInBack => EaseInBackD,
817 | EaseType.EaseOutBack => EaseOutBackD,
818 | EaseType.EaseInOutBack => EaseInOutBackD,
819 | EaseType.EaseInElastic => EaseInElasticD,
820 | EaseType.EaseOutElastic => EaseOutElasticD,
821 | EaseType.EaseInOutElastic => EaseInOutElasticD,
822 | _ => null,
823 | };
824 | }
--------------------------------------------------------------------------------
/native_python/EasingFunctions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | """
4 | Easing Functions that can be used in animations, video games, and other scenarios.
5 | The library includes a set of easing functions mainly: lerp, ease in, ease out, etc.
6 | """
7 |
8 | from enum import Enum
9 | import math
10 |
11 | class EasingFunctions:
12 | """
13 | Class that contains all easing functions.
14 | """
15 |
16 | class EaseType(Enum):
17 | """
18 | Types of eases methods
19 | """
20 | Linear = 0
21 | Spring = 1
22 | EaseInQuad = 2
23 | EaseOutQuad = 3
24 | EaseInOutQuad = 4
25 | EaseInCubic = 5
26 | EaseOutCubic = 6
27 | EaseInOutCubic = 7
28 | EaseInQuart = 8
29 | EaseOutQuart = 9
30 | EaseInOutQuart = 10
31 | EaseInQuint = 11
32 | EaseOutQuint = 12
33 | EaseInOutQuint = 13
34 | EaseInSine = 14
35 | EaseOutSine = 15
36 | EaseInOutSine = 16
37 | EaseInExpo = 17
38 | EaseOutExpo = 18
39 | EaseInOutExpo = 19
40 | EaseInCirc = 20
41 | EaseOutCirc = 21
42 | EaseInOutCirc = 22
43 | EaseInBounce = 23
44 | EaseOutBounce = 24
45 | EaseInOutBounce = 25
46 | EaseInBack = 26
47 | EaseOutBack = 27
48 | EaseInOutBack = 28
49 | EaseInElastic = 29
50 | EaseOutElastic = 30
51 | EaseInOutElastic = 31
52 |
53 | @staticmethod
54 | def epsilon() -> float:
55 | """
56 | Returns the smallest representable positive number such that
57 | 1.0 + epsilon != 1.0.
58 |
59 | This value is often used as a threshold for determining whether
60 | a float is zero or not.
61 | """
62 | import sys
63 | return sys.float_info.epsilon
64 |
65 | @staticmethod
66 | def clamp(value: float, min_value: float = 0.0, max_value: float = 1.0) -> float:
67 | return min(max(value, min_value), max_value)
68 |
69 | @staticmethod
70 | def ease(type: EaseType, a: float, b: float, t: float) -> float:
71 | """
72 | Ease between a and b using the t and the given type.
73 | """
74 | return {
75 | EasingFunctions.EaseType.Linear: EasingFunctions.lerp,
76 | EasingFunctions.EaseType.Spring: EasingFunctions.spring,
77 | EasingFunctions.EaseType.EaseInQuad: EasingFunctions.ease_in_quad,
78 | EasingFunctions.EaseType.EaseOutQuad: EasingFunctions.ease_out_quad,
79 | EasingFunctions.EaseType.EaseInOutQuad: EasingFunctions.ease_in_out_quad,
80 | EasingFunctions.EaseType.EaseInCubic: EasingFunctions.ease_in_cubic,
81 | EasingFunctions.EaseType.EaseOutCubic: EasingFunctions.ease_out_cubic,
82 | EasingFunctions.EaseType.EaseInOutCubic: EasingFunctions.ease_in_out_cubic,
83 | EasingFunctions.EaseType.EaseInQuart: EasingFunctions.ease_in_quart,
84 | EasingFunctions.EaseType.EaseOutQuart: EasingFunctions.ease_out_quart,
85 | EasingFunctions.EaseType.EaseInOutQuart: EasingFunctions.ease_in_out_quart,
86 | EasingFunctions.EaseType.EaseInQuint: EasingFunctions.ease_in_quint,
87 | EasingFunctions.EaseType.EaseOutQuint: EasingFunctions.ease_out_quint,
88 | EasingFunctions.EaseType.EaseInOutQuint: EasingFunctions.ease_in_out_quint,
89 | EasingFunctions.EaseType.EaseInSine: EasingFunctions.ease_in_sine,
90 | EasingFunctions.EaseType.EaseOutSine: EasingFunctions.ease_out_sine,
91 | EasingFunctions.EaseType.EaseInOutSine: EasingFunctions.ease_in_out_sine,
92 | EasingFunctions.EaseType.EaseInExpo: EasingFunctions.ease_in_expo,
93 | EasingFunctions.EaseType.EaseOutExpo: EasingFunctions.ease_out_expo,
94 | EasingFunctions.EaseType.EaseInOutExpo: EasingFunctions.ease_in_out_expo,
95 | EasingFunctions.EaseType.EaseInCirc: EasingFunctions.ease_in_circ,
96 | EasingFunctions.EaseType.EaseOutCirc: EasingFunctions.ease_out_circ,
97 | EasingFunctions.EaseType.EaseInOutCirc: EasingFunctions.ease_in_out_circ,
98 | EasingFunctions.EaseType.EaseInBounce: EasingFunctions.ease_in_bounce,
99 | EasingFunctions.EaseType.EaseOutBounce: EasingFunctions.ease_out_bounce,
100 | EasingFunctions.EaseType.EaseInOutBounce: EasingFunctions.ease_in_out_bounce,
101 | EasingFunctions.EaseType.EaseInBack: EasingFunctions.ease_in_back,
102 | EasingFunctions.EaseType.EaseOutBack: EasingFunctions.ease_out_back,
103 | EasingFunctions.EaseType.EaseInOutBack: EasingFunctions.ease_in_out_back,
104 | EasingFunctions.EaseType.EaseInElastic: EasingFunctions.ease_in_elastic,
105 | EasingFunctions.EaseType.EaseOutElastic: EasingFunctions.ease_out_elastic,
106 | EasingFunctions.EaseType.EaseInOutElastic: EasingFunctions.ease_in_out_elastic,
107 | }[type](a, b, t)
108 |
109 | @staticmethod
110 | def lerp(a: float, b: float, t: float, clamp: bool = True) -> float:
111 | """
112 | Linear interpolation between a and b using t.
113 |
114 | The function returns a value between a and b,
115 | inclusive. If clamp is True, the function clamps
116 | t to the range [0.0, 1.0].
117 | """
118 | if clamp:
119 | t = EasingFunctions.clamp(t)
120 |
121 | return (b - a) * t + a
122 |
123 | @staticmethod
124 | def spring(start: float, end: float, t: float, clamp: bool = True) -> float:
125 | """
126 | Spring easing function.
127 |
128 | The function starts and ends at 0.0, and accelerates
129 | towards the desired value. The function is clamped,
130 | so the return value will always be between start and
131 | end, inclusive.
132 | """
133 | if clamp:
134 | t = EasingFunctions.clamp(t)
135 |
136 | value = (math.sin(t * math.pi * (0.2 + 2.5 * t * t * t)) *
137 | math.pow(1 - t, 2.2) + t) * (1 + (1.2 * (1 - t)))
138 |
139 | return start + (end - start) * value
140 |
141 | @staticmethod
142 | def ease_in_quad(start: float, end: float, t: float, clamp: bool = True) -> float:
143 | """
144 | Eases in using a quadratic function.
145 |
146 | The function starts at 0.0, and accelerates towards
147 | the desired value. The function is clamped, so the
148 | return value will always be between start and end,
149 | inclusive.
150 | """
151 | if clamp:
152 | t = EasingFunctions.clamp(t)
153 |
154 | end -= start
155 | return end * t ** 2 + start
156 |
157 | @staticmethod
158 | def ease_out_quad(start: float, end: float, t: float, clamp: bool = True) -> float:
159 | """
160 | Eases out using a quadratic function.
161 |
162 | The function starts at the desired value, and decelerates
163 | to 0.0. The function is clamped, so the return value will
164 | always be between start and end, inclusive.
165 | """
166 | if clamp:
167 | t = EasingFunctions.clamp(t)
168 |
169 | end -= start
170 | return -end * t * (t - 2.0) + start
171 |
172 | @staticmethod
173 | def ease_in_out_quad(start: float, end: float, t: float, clamp: bool = True) -> float:
174 | """
175 | Eases in and out using a quadratic function.
176 |
177 | The function starts and ends at 0.0, and accelerates
178 | towards the desired value. The function is clamped,
179 | so the return value will always be between start and
180 | end, inclusive.
181 |
182 | The function takes the starting value, ending value,
183 | and time from 0.0 to 1.0 as input, and returns the
184 | interpolated value at that time.
185 | """
186 | if clamp:
187 | t = EasingFunctions.clamp(t)
188 |
189 | t /= 0.5
190 | end -= start
191 |
192 | if t < 1.0:
193 | return end * 0.5 * t * t + start
194 |
195 | t = t - 1.0
196 |
197 | return -end * 0.5 * (t * (t - 2.0) - 1.0) + start
198 |
199 | @staticmethod
200 | def ease_in_cubic(start: float, end: float, t: float, clamp: bool = True) -> float:
201 | """
202 | Eases in using a cubic function.
203 |
204 | The function starts at 0.0 and accelerates quickly to
205 | the desired value. The function is clamped, so the return
206 | value will always be between start and end, inclusive.
207 |
208 | The function takes the starting value, ending value,
209 | and time from 0.0 to 1.0 as input, and returns the
210 | interpolated value at that time.
211 | """
212 | if clamp:
213 | t = EasingFunctions.clamp(t)
214 |
215 | end -= start
216 | return end * t ** 3 + start
217 |
218 | @staticmethod
219 | def ease_out_cubic(start: float, end: float, t: float, clamp: bool = True) -> float:
220 | """
221 | Eases out using a cubic function.
222 |
223 | The function starts at the desired value and decelerates
224 | slowly towards 0.0. The function is clamped, so the return
225 | value will always be between start and 0.0, inclusive.
226 |
227 | The function takes the starting value, ending value,
228 | and time from 0.0 to 1.0 as input, and returns the
229 | interpolated value at that time.
230 | """
231 | if clamp:
232 | t = EasingFunctions.clamp(t)
233 |
234 | t = t - 1.0
235 | end -= start
236 | return end * (t ** 3 + 1.0) + start
237 |
238 | @staticmethod
239 | def ease_in_out_cubic(start: float, end: float, t: float, clamp: bool = True) -> float:
240 | """
241 | Eases in and out using a cubic function.
242 |
243 | The function starts and ends at 0.0, and accelerates
244 | towards the desired value. The function is clamped,
245 | so the return value will always be between start and
246 | end, inclusive.
247 |
248 | The function takes the starting value, ending value,
249 | and time from 0.0 to 1.0 as input, and returns the
250 | interpolated value at that time.
251 | """
252 | if clamp:
253 | t = EasingFunctions.clamp(t)
254 |
255 | t /= 0.5
256 | end -= start
257 |
258 | if t < 1.0:
259 | return end * 0.5 * t ** 3 + start
260 |
261 | t -= 2.0
262 | return end * 0.5 * (t ** 3 + 2) + start
263 |
264 | @staticmethod
265 | def ease_in_quart(start: float, end: float, t: float, clamp: bool = True) -> float:
266 | """
267 | Eases in using a quartic function.
268 |
269 | The function starts at 0.0, accelerates towards the
270 | desired value, and ends at the desired value.
271 |
272 | The function takes the starting value, ending value,
273 | and time from 0.0 to 1.0 as input, and returns the
274 | interpolated value at that time.
275 | """
276 | if clamp:
277 | t = EasingFunctions.clamp(t)
278 |
279 | end -= start
280 | return end * t ** 4 + start
281 |
282 | @staticmethod
283 | def ease_out_quart(start: float, end: float, t: float, clamp: bool = True) -> float:
284 | """
285 | Eases out using a quartic function.
286 |
287 | The function starts at the desired value, decelerates
288 | towards 0.0, and ends at 0.0. The function is clamped,
289 | so the return value will always be between start and
290 | 0.0, inclusive.
291 |
292 | The function takes the starting value, ending value,
293 | and time from 0.0 to 1.0 as input, and returns the
294 | interpolated value at that time.
295 | """
296 | if clamp:
297 | t = EasingFunctions.clamp(t)
298 |
299 | t = t - 1
300 | end -= start
301 | return -end * (t ** 4 - 1) + start
302 |
303 | @staticmethod
304 | def ease_in_out_quart(start: float, end: float, t: float, clamp: bool = True) -> float:
305 | """
306 | Eases in and out using a quartic function.
307 |
308 | The function starts and ends at 0.0, and accelerates
309 | towards the desired value. The function is clamped,
310 | so the return value will always be between start and
311 | end, inclusive.
312 |
313 | The function takes the starting value, ending value,
314 | and time from 0.0 to 1.0 as input, and returns the
315 | interpolated value at that time.
316 | """
317 | if clamp:
318 | t = EasingFunctions.clamp(t)
319 |
320 | t /= 0.5
321 | end -= start
322 |
323 | if t < 1.0:
324 | return end * 0.5 * t ** 4 + start
325 |
326 | t -= 2.0
327 | return -end * 0.5 * (t ** 4 - 2) + start
328 |
329 | @staticmethod
330 | def ease_in_quint(start: float, end: float, t: float, clamp: bool = True) -> float:
331 | """
332 | Eases in using a quintic function.
333 |
334 | The function starts at 0.0, accelerates towards the
335 | desired value, and ends at the desired value.
336 |
337 | The function takes the starting value, ending value,
338 | and time from 0.0 to 1.0 as input, and returns the
339 | interpolated value at that time.
340 | """
341 | if clamp:
342 | t = EasingFunctions.clamp(t)
343 |
344 | end -= start
345 | return end * t ** 5 + start
346 |
347 | @staticmethod
348 | def ease_out_quint(start: float, end: float, t: float, clamp: bool = True) -> float:
349 | """
350 | Eases out using a quintic function.
351 |
352 | The function starts at the desired value, decelerates
353 | towards 0.0, and ends at 0.0. The function is clamped,
354 | so the return value will always be between start and
355 | 0.0, inclusive.
356 |
357 | The function takes the starting value, ending value,
358 | and time from 0.0 to 1.0 as input, and returns the
359 | interpolated value at that time.
360 | """
361 | if clamp:
362 | t = EasingFunctions.clamp(t)
363 |
364 | t = t - 1.0
365 | end -= start
366 | return end * (t ** 5 + 1) + start
367 |
368 | @staticmethod
369 | def ease_in_out_quint(start: float, end: float, t: float, clamp: bool = True) -> float:
370 | """
371 | Eases in and out using a quintic function.
372 |
373 | The function starts and ends at 0.0, and accelerates
374 | towards the desired value. The function is clamped,
375 | so the return value will always be between start and
376 | end, inclusive.
377 |
378 | The function takes the starting value, ending value,
379 | and time from 0.0 to 1.0 as input, and returns the
380 | interpolated value at that time.
381 | """
382 | if clamp:
383 | t = EasingFunctions.clamp(t)
384 |
385 | t /= 0.5
386 | end -= start
387 | if t < 1.0:
388 | return end * 0.5 * t ** 5 + start
389 | t -= 2.0
390 | return end * 0.5 * (t ** 5 + 2) + start
391 |
392 | @staticmethod
393 | def ease_in_sine(start: float, end: float, t: float, clamp: bool = True) -> float:
394 | """
395 | Eases in using a sine wave.
396 |
397 | The function starts at 0.0, and accelerates towards
398 | the desired value. The function is clamped, so the
399 | return value will always be between start and end,
400 | inclusive.
401 |
402 | The function takes the starting value, ending value,
403 | and time from 0.0 to 1.0 as input, and returns the
404 | interpolated value at that time.
405 | """
406 | if clamp:
407 | t = EasingFunctions.clamp(t)
408 |
409 | end -= start
410 | return -end * math.cos(t * (math.pi * 0.5)) + end + start
411 |
412 | @staticmethod
413 | def ease_out_sine(start: float, end: float, t: float, clamp: bool = True) -> float:
414 | """
415 | Eases out using a sine wave.
416 |
417 | The function starts at the desired value, decelerates
418 | towards 0.0, and ends at 0.0. The function is clamped,
419 | so the return value will always be between start and
420 | 0.0, inclusive.
421 |
422 | The function takes the starting value, ending value,
423 | and time from 0.0 to 1.0 as input, and returns the
424 | interpolated value at that time.
425 | """
426 | if clamp:
427 | t = EasingFunctions.clamp(t)
428 |
429 | end -= start
430 | return end * math.sin(t * (math.pi * 0.5)) + start
431 |
432 | @staticmethod
433 | def ease_in_out_sine(start: float, end: float, t: float, clamp: bool = True) -> float:
434 | """
435 | Eases in and out using a sine wave.
436 |
437 | The function starts and ends at 0.0, and accelerates
438 | towards the desired value using a sine wave. The
439 | function is clamped, so the return value will always
440 | be between start and end, inclusive.
441 |
442 | The function takes the starting value, ending value,
443 | and time from 0.0 to 1.0 as input, and returns the
444 | interpolated value at that time.
445 | """
446 | if clamp:
447 | t = EasingFunctions.clamp(t)
448 |
449 | end -= start
450 | return -end * 0.5 * (math.cos(math.pi * t) - 1.0) + start
451 |
452 | @staticmethod
453 | def ease_in_expo(start: float, end: float, t: float, clamp: bool = True) -> float:
454 | """
455 | Eases in using an exponential function.
456 |
457 | The function starts at 0.0, and accelerates towards
458 | the desired value. The function is clamped, so the
459 | return value will always be between start and end,
460 | inclusive.
461 |
462 | The function takes the starting value, ending value,
463 | and time from 0.0 to 1.0 as input, and returns the
464 | interpolated value at that time.
465 | """
466 | if clamp:
467 | t = EasingFunctions.clamp(t)
468 |
469 | end -= start
470 | return end * math.pow(2.0, 10.0 * (t - 1.0)) + start
471 |
472 | @staticmethod
473 | def ease_out_expo(start: float, end: float, t: float, clamp: bool = True) -> float:
474 | """
475 | Eases out using an exponential function.
476 |
477 | The function starts at the desired value, decelerates
478 | towards 0.0, and ends at 0.0. The function is clamped,
479 | so the return value will always be between start and
480 | 0.0, inclusive.
481 |
482 | The function takes the starting value, ending value,
483 | and time from 0.0 to 1.0 as input, and returns the
484 | interpolated value at that time.
485 | """
486 | if clamp:
487 | t = EasingFunctions.clamp(t)
488 |
489 | end -= start
490 | return end * (-math.pow(2.0, -10.0 * t) + 1.0) + start
491 |
492 | @staticmethod
493 | def ease_in_out_expo(start: float, end: float, t: float, clamp: bool = True) -> float:
494 | """
495 | Eases in and out using an exponential function.
496 |
497 | The function starts and ends at 0.0, and accelerates
498 | towards the desired value using an exponential
499 | function. The function is clamped, so the return value
500 | will always be between start and end, inclusive.
501 |
502 | The function takes the starting value, ending value,
503 | and time from 0.0 to 1.0 as input, and returns the
504 | interpolated value at that time.
505 | """
506 | if clamp:
507 | t = EasingFunctions.clamp(t)
508 |
509 | t /= 0.5
510 | end -= start
511 |
512 | if t < 1.0:
513 | return end * 0.5 * math.pow(2.0, 10.0 * (t - 1.0)) + start
514 |
515 | t = t - 1
516 | return end * 0.5 * (-math.pow(2.0, -10.0 * t) + 2.0) + start
517 |
518 | @staticmethod
519 | def ease_in_circ(start: float, end: float, t: float, clamp: bool = True) -> float:
520 | """
521 | Eases in using a circular function.
522 |
523 | The function starts at 0.0, and accelerates towards
524 | the desired value. The function is clamped, so the
525 | return value will always be between start and end,
526 | inclusive.
527 |
528 | The function takes the starting value, ending value,
529 | and time from 0.0 to 1.0 as input, and returns the
530 | interpolated value at that time.
531 | """
532 | if clamp:
533 | t = EasingFunctions.clamp(t)
534 |
535 | end -= start
536 | return -end * (math.sqrt(1.0 - t * t) - 1.0) + start
537 |
538 | @staticmethod
539 | def ease_out_circ(start: float, end: float, t: float, clamp: bool = True) -> float:
540 | """
541 | Eases out using a circular function.
542 |
543 | The function starts at the desired value, decelerates
544 | towards 0.0, and ends at 0.0. The function is clamped,
545 | so the return value will always be between start and
546 | 0.0, inclusive.
547 |
548 | The function takes the starting value, ending value,
549 | and time from 0.0 to 1.0 as input, and returns the
550 | interpolated value at that time.
551 | """
552 | if clamp:
553 | t = EasingFunctions.clamp(t)
554 |
555 | t = t - 1.0
556 | end -= start
557 | return end * math.sqrt(1.0 - t * t) + start
558 |
559 | @staticmethod
560 | def ease_in_out_circ(start: float, end: float, t: float, clamp: bool = True) -> float:
561 | """
562 | Eases in and out using a circular function.
563 |
564 | The function starts and ends at 0.0, and accelerates
565 | towards the desired value using a circular function.
566 | The function is clamped, so the return value will always
567 | be between start and end, inclusive.
568 |
569 | The function takes the starting value, ending value,
570 | and time from 0.0 to 1.0 as input, and returns the
571 | interpolated value at that time.
572 | """
573 | if clamp:
574 | t = EasingFunctions.clamp(t)
575 |
576 | t /= 0.5
577 | end -= start
578 |
579 | if t < 1.0:
580 | return -end * 0.5 * (math.sqrt(1.0 - t * t) - 1.0) + start
581 |
582 | t -= 2.0
583 |
584 | return end * 0.5 * (math.sqrt(1.0 - t * t) + 1) + start
585 |
586 | @staticmethod
587 | def ease_in_bounce(start: float, end: float, t: float, clamp: bool = True) -> float:
588 | """
589 | Eases in using a bounce function.
590 |
591 | The function starts at 0.0, and accelerates towards
592 | the desired value. The function is clamped, so the
593 | return value will always be between start and
594 | end, inclusive. The function takes the starting
595 | value, ending value, and time from 0.0 to 1.0 as
596 | input, and returns the interpolated value at that time.
597 | """
598 | if clamp:
599 | t = EasingFunctions.clamp(t)
600 |
601 | end -= start
602 | return end - EasingFunctions.ease_out_bounce(0, end, 1.0 - t) + t
603 |
604 | @staticmethod
605 | def ease_out_bounce(start: float, end: float, t: float, clamp: bool = True) -> float:
606 | """
607 | Eases out using a bounce function.
608 |
609 | The function starts at the desired value, decelerates
610 | towards 0.0, and ends at 0.0. The function is clamped,
611 | so the return value will always be between start and
612 | 0.0, inclusive. The function takes the starting value,
613 | ending value, and time from 0.0 to 1.0 as input,
614 | and returns the interpolated value at that time.
615 | """
616 | if clamp:
617 | t = EasingFunctions.clamp(t)
618 |
619 | t /= 1.0
620 | end -= start
621 |
622 | if t < (1.0 / 2.75):
623 | return end * (7.5625 * t * t) + start
624 |
625 | if t < (2.0 / 2.75):
626 | t -= 1.5 / 2.75
627 | return end * (7.5625 * t * t + 0.75) + start
628 |
629 | if t < (2.5 / 2.75):
630 | t -= 2.25 / 2.75
631 | return end * (7.5625 * t * t + 0.9375) + start
632 |
633 | t -= 2.625 / 2.75
634 | return end * (7.5625 * t * t + 0.984375) + start
635 |
636 | @staticmethod
637 | def ease_in_out_bounce(start: float, end: float, t: float, clamp: bool = True) -> float:
638 | """
639 | Eases in and out using a bounce function.
640 |
641 | The function starts and ends at 0.0, and accelerates
642 | towards the desired value using a bounce function.
643 | The function is clamped, so the return value will always
644 | be between start and end, inclusive. The function takes
645 | the starting value, ending value, and time from 0.0 to
646 | 1.0 as input, and returns the interpolated value at
647 | that time.
648 | """
649 | if clamp:
650 | t = EasingFunctions.clamp(t)
651 |
652 | end -= start
653 |
654 | if t < 1.0 * 0.5:
655 | return EasingFunctions.ease_in_bounce(0, end, t * 2.0) * 0.5 + start
656 |
657 | return EasingFunctions.ease_out_bounce(0, end, t * 2.0 - 1.0) * 0.5 + end * 0.5 + start
658 |
659 | @staticmethod
660 | def ease_in_back(start: float, end: float, t: float, clamp: bool = True) -> float:
661 | """
662 | Eases in using a back function.
663 |
664 | The function starts at 0.0, and accelerates towards
665 | the desired value using a back function. The function
666 | is clamped, so the return value will always be between
667 | start and end, inclusive. The function takes the
668 | starting value, ending value, and time from 0.0 to
669 | 1.0 as input, and returns the interpolated value at
670 | that time.
671 | """
672 | if clamp:
673 | t = EasingFunctions.clamp(t)
674 |
675 | end -= start
676 | t /= 1.0
677 |
678 | # The strength of the back function. Higher values
679 | # result in a steeper ease-in.
680 | s = 1.70158
681 | return end * t ** 2 * ((s + 1.0) * t - s) + start
682 |
683 | @staticmethod
684 | def ease_out_back(start: float, end: float, t: float, clamp: bool = True) -> float:
685 | """
686 | Eases out using a back function.
687 |
688 | The function starts at the desired value, and
689 | decelerates towards 0.0 using a back function. The
690 | function is clamped, so the return value will always
691 | be between start and end, inclusive. The function
692 | takes the starting value, ending value, and time from
693 | 0.0 to 1.0 as input, and returns the interpolated
694 | value at that time.
695 | """
696 | if clamp:
697 | t = EasingFunctions.clamp(t)
698 |
699 | end -= start
700 | t -= 1.0
701 |
702 | s = 1.70158
703 | return end * ((t) * t * ((s + 1.0) * t + s) + 1.0) + start
704 |
705 | @staticmethod
706 | def ease_in_out_back(start: float, end: float, t: float, clamp: bool = True) -> float:
707 | """
708 | Eases in and out using a back function.
709 |
710 | The function starts and ends at 0.0, and accelerates
711 | towards the desired value using a back function.
712 | The function is clamped, so the return value will
713 | always be between start and end, inclusive. The
714 | function takes the starting value, ending value,
715 | and time from 0.0 to 1.0 as input, and returns the
716 | interpolated value at that time.
717 | """
718 | if clamp:
719 | t = EasingFunctions.clamp(t)
720 |
721 | end -= start
722 | t /= 0.5
723 |
724 | s = 1.70158
725 |
726 | if t < 1.0:
727 | s *= 1.525
728 | return end * 0.5 * (t ** 2 * (((s) + 1.0) * t - s)) + start
729 |
730 | t -= 2.0
731 | s *= 1.525
732 |
733 | return end * 0.5 * ((t) * t * (((s) + 1.0) * t + s) + 2.0) + start
734 |
735 | @staticmethod
736 | def ease_in_elastic(start: float, end: float, t: float, clamp: bool = True) -> float:
737 | """
738 | Eases in using an elastic function.
739 |
740 | The function starts at 0.0, accelerates towards the
741 | desired value using a parabolic function, and ends at
742 | the desired value. The function is clamped, so the
743 | return value will always be between start and end,
744 | inclusive. The function takes the starting value,
745 | ending value, and time from 0.0 to 1.0 as input, and
746 | returns the interpolated value at that time.
747 | """
748 | if clamp:
749 | t = EasingFunctions.clamp(t)
750 |
751 | # Constants
752 | d = 1.0
753 | p = d * 0.3
754 |
755 | # Precompute a few values for the function
756 | end -= start
757 |
758 | # The function is linear for t close to 0.0
759 | if abs(t) < EasingFunctions.epsilon():
760 | return start
761 |
762 | # Scale time to 0.0 - 1.0
763 | t /= d
764 |
765 | # The function is linear for t close to 1.0
766 | if abs(t - 1.0) < EasingFunctions.epsilon():
767 | return start + end
768 |
769 | # Amplitude and period
770 | a = 0.0
771 | s = 0.0
772 |
773 | # If the amplitude is 0.0 or less or greater than the
774 | # change in value, we use the change in value directly
775 | if abs(a) < EasingFunctions.epsilon() or a < abs(end):
776 | a = end
777 | s = p * 0.2
778 | else:
779 | s = p / (2.0 * math.pi) * math.asin(end / a)
780 |
781 | # Decrement time
782 | t -= 1.0
783 |
784 | # Return the interpolated value
785 | return -(a * math.pow(2.0, 10.0 * (t)) * math.sin((t * d - s) * (2.0 * math.pi) / p)) + start
786 |
787 | @staticmethod
788 | def ease_out_elastic(start: float, end: float, t: float, clamp: bool = True) -> float:
789 | """
790 | Eases out using an elastic function.
791 |
792 | The function starts at the desired value, decelerates
793 | towards 0.0, and ends at 0.0. The function is clamped,
794 | so the return value will always be between start and
795 | 0.0, inclusive. The function takes the starting value,
796 | ending value, and time from 0.0 to 1.0 as input, and
797 | returns the interpolated value at that time.
798 | """
799 | if clamp:
800 | t = EasingFunctions.clamp(t)
801 |
802 | # Constants
803 | d = 1.0
804 | p = d * 0.3
805 |
806 | # Precompute a few values for the function
807 | end -= start
808 |
809 | # The function is linear for t close to 0.0
810 | if abs(t) < EasingFunctions.epsilon():
811 | return start
812 |
813 | # Scale time to 0.0 - 1.0
814 | t /= d
815 |
816 | # The function is linear for t close to 1.0
817 | if abs(t - 1.0) < EasingFunctions.epsilon():
818 | return start + end
819 |
820 | # Amplitude and period
821 | a = 0.0
822 | s = 0.0
823 |
824 | # If the amplitude is 0.0 or less or greater than the
825 | # change in value, we use the change in value directly
826 | if abs(a) < EasingFunctions.epsilon() or a < abs(end):
827 | a = end
828 | s = p * 0.25
829 | else:
830 | s = p / (2.0 * math.pi) * math.asin(end / a)
831 |
832 | # Return the interpolated value
833 | return a * math.pow(2.0, -10.0 * t) * math.sin((t * d - s) * (2.0 * math.pi) / p) + end + start
834 |
835 | @staticmethod
836 | def ease_in_out_elastic(start: float, end: float, t: float, clamp: bool = True) -> float:
837 | """
838 | Eases in and out using an elastic function.
839 |
840 | The function starts and ends at the desired value,
841 | accelerates towards the end value using a parabolic
842 | function, and decelerates towards the start value
843 | using a parabolic function. The function is clamped,
844 | so the return value will always be between start and
845 | end, inclusive. The function takes the starting value,
846 | ending value, and time from 0.0 to 1.0 as input, and
847 | returns the interpolated value at that time.
848 | """
849 | if clamp:
850 | t = EasingFunctions.clamp(t)
851 |
852 | # Constants
853 | d = 1.0
854 | p = d * 0.3
855 |
856 | # Precompute a few values for the function
857 | s = 0.0
858 | a = 0.0
859 |
860 | end -= start
861 |
862 | # The function is linear for t close to 0.0
863 | if abs(t) < EasingFunctions.epsilon():
864 | return start
865 |
866 | t /= d * 0.5
867 |
868 | # The function is linear for t close to 1.0
869 | if abs(t - 2.0) < EasingFunctions.epsilon():
870 | return start + end
871 |
872 | # Amplitude and period
873 | if abs(a) < EasingFunctions.epsilon() or a < abs(end):
874 | a = end
875 | s = p * 0.2
876 | else:
877 | s = p / (2 * math.pi) * math.asin(end / a)
878 |
879 | # The first half of the elastic function
880 | if t < 1.0:
881 | t -= 1
882 | return -0.5 * (a * math.pow(2.0, 10.0 * t) * math.sin((t * d - s) *
883 | (2.0 * math.pi) / p)) + start
884 |
885 | # The second half of the elastic function
886 | t -= 1
887 | return a * math.pow(2, -10.0 * t) * math.sin((t * d - s) *
888 | (2 * math.pi) / p) * 0.5 + end + start
889 |
--------------------------------------------------------------------------------
/tests/NativeCpp_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
--------------------------------------------------------------------------------
/tests/NativeCsharp_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
--------------------------------------------------------------------------------
/tests/NativePython_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from native_python.EasingFunctions import EasingFunctions as ef
4 |
5 | import pytest
6 |
7 | def approx_equal(a, b, places=3):
8 | """
9 | Approximate the equality of two floats.
10 |
11 | Args:
12 | a (float): The first float.
13 | b (float): The second float.
14 | places (int, optional): The number of decimal places to compare. Defaults to 3.
15 |
16 | Returns:
17 | bool: True if the two floats are approximately equal, False otherwise.
18 | """
19 | return round(a, places) == round(b, places)
20 |
21 | @pytest.mark.parametrize("start, end, t, expected", [
22 | (0.0, 1.0, 0.0, 0.0),
23 | (0.0, 1.0, 1.0, 1.0),
24 | (0.0, 1.0, 0.5, 0.5),
25 | ])
26 | def test_ease(start, end, t, expected):
27 | assert approx_equal(ef.ease(ef.EaseType.Linear, start, end, t), expected)
28 |
29 | @pytest.mark.parametrize("start, end, t, expected", [
30 | (0.0, 1.0, 0.0, 0.0),
31 | (0.0, 1.0, 1.0, 1.0),
32 | (0.0, 1.0, 0.5, 0.5),
33 | ])
34 | def test_lerp(start, end, t, expected):
35 | assert approx_equal(ef.lerp(start, end, t), expected)
36 |
37 | @pytest.mark.parametrize("start, end, t, expected", [
38 | (0.0, 1.0, 0.0, 0.0),
39 | (0.0, 1.0, 1.0, 1.0),
40 | (0.0, 1.0, 0.5, 1.0510158018655051),
41 | ])
42 | def test_spring(start, end, t, expected):
43 | assert approx_equal(ef.spring(start, end, t), expected)
44 |
45 | @pytest.mark.parametrize("start, end, t, expected", [
46 | (0.0, 1.0, 0.0, 0.0),
47 | (0.0, 1.0, 1.0, 1.0),
48 | (0.0, 1.0, 0.5, 0.25),
49 | ])
50 | def test_ease_in_quad(start, end, t, expected):
51 | assert approx_equal(ef.ease_in_quad(start, end, t), expected)
52 |
53 | @pytest.mark.parametrize("start, end, t, expected", [
54 | (0.0, 1.0, 0.0, 0.0),
55 | (0.0, 1.0, 1.0, 1.0),
56 | (0.0, 1.0, 0.5, 0.5),
57 | ])
58 | def test_ease_in_out_quad(start, end, t, expected):
59 | assert approx_equal(ef.ease_in_out_quad(start, end, t), expected)
60 |
61 | @pytest.mark.parametrize("start, end, t, expected", [
62 | (0.0, 1.0, 0.0, 0.0),
63 | (0.0, 1.0, 1.0, 1.0),
64 | (0.0, 1.0, 0.5, 0.125),
65 | ])
66 | def test_ease_in_cubic(start, end, t, expected):
67 | assert approx_equal(ef.ease_in_cubic(start, end, t), expected)
68 |
69 | @pytest.mark.parametrize("start, end, t, expected", [
70 | (0.0, 1.0, 0.0, 0.0),
71 | (0.0, 1.0, 1.0, 1.0),
72 | (0.0, 1.0, 0.5, 0.875),
73 | ])
74 | def test_ease_out_cubic(start, end, t, expected):
75 | assert approx_equal(ef.ease_out_cubic(start, end, t), expected)
76 |
77 | @pytest.mark.parametrize("start, end, t, expected", [
78 | (0.0, 1.0, 0.0, 0.0),
79 | (0.0, 1.0, 1.0, 1.0),
80 | (0.0, 1.0, 0.5, 0.5),
81 | ])
82 | def test_ease_in_out_cubic(start, end, t, expected):
83 | assert approx_equal(ef.ease_in_out_cubic(start, end, t), expected)
84 |
85 | @pytest.mark.parametrize("start, end, t, expected", [
86 | (0.0, 1.0, 0.0, 0.0),
87 | (0.0, 1.0, 1.0, 1.0),
88 | (0.0, 1.0, 0.5, 0.0625),
89 | ])
90 | def test_ease_in_quart(start, end, t, expected):
91 | assert approx_equal(ef.ease_in_quart(start, end, t), expected)
92 |
93 | @pytest.mark.parametrize("start, end, t, expected", [
94 | (0.0, 1.0, 0.0, 0.0),
95 | (0.0, 1.0, 1.0, 1.0),
96 | (0.0, 1.0, 0.5, 0.9375),
97 | ])
98 | def test_ease_out_quart(start, end, t, expected):
99 | assert approx_equal(ef.ease_out_quart(start, end, t), expected)
100 |
101 | @pytest.mark.parametrize("start, end, t, expected", [
102 | (0.0, 1.0, 0.0, 0.0),
103 | (0.0, 1.0, 1.0, 1.0),
104 | (0.0, 1.0, 0.5, 0.5),
105 | ])
106 | def test_ease_in_out_quart(start, end, t, expected):
107 | assert approx_equal(ef.ease_in_out_quart(start, end, t), expected)
108 |
109 | @pytest.mark.parametrize("start, end, t, expected", [
110 | (0.0, 1.0, 0.0, 0.0),
111 | (0.0, 1.0, 1.0, 1.0),
112 | (0.0, 1.0, 0.5, 0.03125),
113 | ])
114 | def test_ease_in_quint(start, end, t, expected):
115 | assert approx_equal(ef.ease_in_quint(start, end, t), expected)
116 |
117 | @pytest.mark.parametrize("start, end, t, expected", [
118 | (0.0, 1.0, 0.0, 0.0),
119 | (0.0, 1.0, 1.0, 1.0),
120 | (0.0, 1.0, 0.5, 0.96875),
121 | ])
122 | def test_ease_out_quint(start, end, t, expected):
123 | assert approx_equal(ef.ease_out_quint(start, end, t), expected)
124 |
125 | @pytest.mark.parametrize("start, end, t, expected", [
126 | (0.0, 1.0, 0.0, 0.0),
127 | (0.0, 1.0, 1.0, 1.0),
128 | (0.0, 1.0, 0.5, 0.2928932188134524),
129 | ])
130 | def test_ease_in_sine(start, end, t, expected):
131 | assert approx_equal(ef.ease_in_sine(start, end, t), expected)
132 |
133 | @pytest.mark.parametrize("start, end, t, expected", [
134 | (0.0, 1.0, 0.0, 0.0),
135 | (0.0, 1.0, 1.0, 1.0),
136 | (0.0, 1.0, 0.5, 0.7071067811865476),
137 | ])
138 | def test_ease_out_sine(start, end, t, expected):
139 | assert approx_equal(ef.ease_out_sine(start, end, t), expected)
140 |
141 | @pytest.mark.parametrize("start, end, t, expected", [
142 | (0.0, 1.0, 0.0, 0.0),
143 | (0.0, 1.0, 1.0, 1.0),
144 | (0.0, 1.0, 0.5, 0.49999999999999994),
145 | ])
146 | def test_ease_in_out_sine(start, end, t, expected):
147 | assert approx_equal(ef.ease_in_out_sine(start, end, t), expected)
148 |
149 | @pytest.mark.parametrize("start, end, t, expected", [
150 | (0.0, 1.0, 0.0, 0.0009765625),
151 | (0.0, 1.0, 1.0, 1.0),
152 | (0.0, 1.0, 0.5, 0.03125),
153 | ])
154 | def test_ease_in_expo(start, end, t, expected):
155 | assert approx_equal(ef.ease_in_expo(start, end, t), expected)
156 |
157 | @pytest.mark.parametrize("start, end, t, expected", [
158 | (0.0, 1.0, 0.0, 0.0),
159 | (0.0, 1.0, 1.0, 0.9990234375),
160 | (0.0, 1.0, 0.5, 0.96875),
161 | ])
162 | def test_ease_out_expo(start, end, t, expected):
163 | assert approx_equal(ef.ease_out_expo(start, end, t), expected)
164 |
165 | @pytest.mark.parametrize("start, end, t, expected", [
166 | (0.0, 1.0, 0.0, 0.0),
167 | (0.0, 1.0, 1.0, 1.0),
168 | (0.0, 1.0, 0.5, 0.1339745962155614),
169 | ])
170 | def test_ease_in_circ(start, end, t, expected):
171 | assert approx_equal(ef.ease_in_circ(start, end, t), expected)
172 |
173 | @pytest.mark.parametrize("start, end, t, expected", [
174 | (0.0, 1.0, 0.0, 0.0),
175 | (0.0, 1.0, 1.0, 1.0),
176 | (0.0, 1.0, 0.5, 0.8660254037844386),
177 | ])
178 | def test_ease_out_circ(start, end, t, expected):
179 | assert approx_equal(ef.ease_out_circ(start, end, t), expected)
180 |
181 | @pytest.mark.parametrize("start, end, t, expected", [
182 | (0.0, 1.0, 0.0, 0.0),
183 | (0.0, 1.0, 1.0, 1.0),
184 | (0.0, 1.0, 0.5, 0.5),
185 | ])
186 | def test_ease_in_out_circ(start, end, t, expected):
187 | assert approx_equal(ef.ease_in_out_circ(start, end, t), expected)
188 |
189 | @pytest.mark.parametrize("start, end, t, expected", [
190 | (0.0, 1.0, 0.0, 0.0),
191 | (0.0, 1.0, 1.0, 1.0),
192 | (0.0, 1.0, 0.5, 0.5),
193 | ])
194 | def test_ease_in_out_expo(start, end, t, expected):
195 | assert approx_equal(ef.ease_in_out_expo(start, end, t), expected)
196 |
197 | @pytest.mark.parametrize("start, end, t, expected", [
198 | (0.0, 1.0, 0.0, 0.0),
199 | (0.0, 1.0, 1.0, 2.0),
200 | (0.0, 1.0, 0.5, 0.734375),
201 | ])
202 | def test_ease_in_bounce(start, end, t, expected):
203 | assert approx_equal(ef.ease_in_bounce(start, end, t), expected)
204 |
205 | @pytest.mark.parametrize("start, end, t, expected", [
206 | (0.0, 1.0, 0.0, 0.0),
207 | (0.0, 1.0, 1.0, 1.0),
208 | (0.0, 1.0, 0.5, 0.765625),
209 | ])
210 | def test_ease_out_bounce(start, end, t, expected):
211 | assert approx_equal(ef.ease_out_bounce(start, end, t), expected)
212 |
213 | @pytest.mark.parametrize("start, end, t, expected", [
214 | (0.0, 1.0, 0.0, 0.0),
215 | (0.0, 1.0, 1.0, 1.0),
216 | (0.0, 1.0, 0.5, 0.5),
217 | ])
218 | def test_ease_in_out_bounce(start, end, t, expected):
219 | assert approx_equal(ef.ease_in_out_bounce(start, end, t), expected)
220 |
221 | @pytest.mark.parametrize("start, end, t, expected", [
222 | (0.0, 1.0, 0.0, 0.0),
223 | (0.0, 1.0, 1.0, 1.0),
224 | (0.0, 1.0, 0.5, -0.08769750000000004),
225 | ])
226 | def test_ease_in_back(start, end, t, expected):
227 | assert approx_equal(ef.ease_in_back(start, end, t), expected)
228 |
229 | @pytest.mark.parametrize("start, end, t, expected", [
230 | (0.0, 1.0, 0.0, 0.0),
231 | (0.0, 1.0, 1.0, 1.0),
232 | (0.0, 1.0, 0.5, 1.0876975),
233 | ])
234 | def test_ease_out_back(start, end, t, expected):
235 | assert approx_equal(ef.ease_out_back(start, end, t), expected)
236 |
237 | @pytest.mark.parametrize("start, end, t, expected", [
238 | (0.0, 1.0, 0.0, 0.0),
239 | (0.0, 1.0, 1.0, 1.0),
240 | (0.0, 1.0, 0.5, 0.5),
241 | ])
242 | def test_ease_in_out_back(start, end, t, expected):
243 | assert approx_equal(ef.ease_in_out_back(start, end, t), expected)
244 |
245 | @pytest.mark.parametrize("start, end, t, expected", [
246 | (0.0, 1.0, 0.0, 0.0),
247 | (0.0, 1.0, 1.0, 1.0),
248 | (0.0, 1.0, 0.5, -0.023223275796168532),
249 | ])
250 | def test_ease_in_elastic(start, end, t, expected):
251 | assert approx_equal(ef.ease_in_elastic(start, end, t), expected)
252 |
253 | @pytest.mark.parametrize("start, end, t, expected", [
254 | (0.0, 1.0, 0.0, 0.0),
255 | (0.0, 1.0, 1.0, 1.0),
256 | (0.0, 1.0, 0.5, 1.015625),
257 | ])
258 | def test_ease_out_elastic(start, end, t, expected):
259 | assert approx_equal(ef.ease_out_elastic(start, end, t), expected)
260 |
261 | @pytest.mark.parametrize("start, end, t, expected", [
262 | (0.0, 1.0, 0.0, 0.0),
263 | (0.0, 1.0, 1.0, 1.0),
264 | (0.0, 1.0, 0.5, 0.5244717418524232),
265 | ])
266 | def test_ease_in_out_elastic(start, end, t, expected):
267 | assert approx_equal(ef.ease_in_out_elastic(start, end, t), expected)
268 |
--------------------------------------------------------------------------------
/unreal_engine/CommonEasingLibrary.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2023 MrRobin. All Rights Reserved.
2 |
3 | #include "Library/CommonEasingLibrary.h"
4 |
5 | float UCommonEasingLibrary::GetEaseFromType(EEaseType EaseType, float Start, float End, float Alpha)
6 | {
7 | switch (EaseType)
8 | {
9 | default:
10 | return 0.0f;
11 |
12 | case EEaseType::Linear:
13 | return EaseLinear(Start, End, Alpha);
14 |
15 | case EEaseType::Spring:
16 | return EaseSpring(Start, End, Alpha);
17 |
18 | case EEaseType::EaseInQuad:
19 | return EaseInQuad(Start, End, Alpha);
20 |
21 | case EEaseType::EaseOutQuad:
22 | return EaseOutQuad(Start, End, Alpha);
23 |
24 | case EEaseType::EaseInOutQuad:
25 | return EaseInOutQuad(Start, End, Alpha);
26 |
27 | case EEaseType::EaseInCubic:
28 | return EaseInCubic(Start, End, Alpha);
29 |
30 | case EEaseType::EaseOutCubic:
31 | return EaseOutCubic(Start, End, Alpha);
32 |
33 | case EEaseType::EaseInOutCubic:
34 | return EaseInOutCubic(Start, End, Alpha);
35 |
36 | case EEaseType::EaseInQuart:
37 | return EaseInQuart(Start, End, Alpha);
38 |
39 | case EEaseType::EaseOutQuart:
40 | return EaseOutQuart(Start, End, Alpha);
41 |
42 | case EEaseType::EaseInOutQuart:
43 | return EaseInOutQuart(Start, End, Alpha);
44 |
45 | case EEaseType::EaseInQuint:
46 | return EaseInQuint(Start, End, Alpha);
47 |
48 | case EEaseType::EaseOutQuint:
49 | return EaseOutQuint(Start, End, Alpha);
50 |
51 | case EEaseType::EaseInOutQuint:
52 | return EaseInOutQuint(Start, End, Alpha);
53 |
54 | case EEaseType::EaseInSine:
55 | return EaseInSine(Start, End, Alpha);
56 |
57 | case EEaseType::EaseOutSine:
58 | return EaseOutSine(Start, End, Alpha);
59 |
60 | case EEaseType::EaseInOutSine:
61 | return EaseInOutSine(Start, End, Alpha);
62 |
63 | case EEaseType::EaseInExpo:
64 | return EaseInExpo(Start, End, Alpha);
65 |
66 | case EEaseType::EaseOutExpo:
67 | return EaseOutExpo(Start, End, Alpha);
68 |
69 | case EEaseType::EaseInOutExpo:
70 | return EaseInOutExpo(Start, End, Alpha);
71 |
72 | case EEaseType::EaseInCirc:
73 | return EaseInCirc(Start, End, Alpha);
74 |
75 | case EEaseType::EaseOutCirc:
76 | return EaseOutCirc(Start, End, Alpha);
77 |
78 | case EEaseType::EaseInOutCirc:
79 | return EaseInOutCirc(Start, End, Alpha);
80 |
81 | case EEaseType::EaseInBounce:
82 | return EaseInBounce(Start, End, Alpha);
83 |
84 | case EEaseType::EaseOutBounce:
85 | return EaseOutBounce(Start, End, Alpha);
86 |
87 | case EEaseType::EaseInOutBounce:
88 | return EaseInOutBounce(Start, End, Alpha);
89 |
90 | case EEaseType::EaseInBack:
91 | return EaseInBack(Start, End, Alpha);
92 |
93 | case EEaseType::EaseOutBack:
94 | return EaseOutBack(Start, End, Alpha);
95 |
96 | case EEaseType::EaseInOutBack:
97 | return EaseInOutBack(Start, End, Alpha);
98 |
99 | case EEaseType::EaseInElastic:
100 | return EaseInElastic(Start, End, Alpha);
101 |
102 | case EEaseType::EaseOutElastic:
103 | return EaseOutElastic(Start, End, Alpha);
104 |
105 | case EEaseType::EaseInOutElastic:
106 | return EaseInOutElastic(Start, End, Alpha);
107 | }
108 | }
109 |
110 | float UCommonEasingLibrary::EaseLinear(float Start, float End, float Alpha)
111 | {
112 | return FMath::Lerp(Start, End, Alpha);
113 | }
114 |
115 | float UCommonEasingLibrary::EaseSpring(float Start, float End, float Alpha)
116 | {
117 | Alpha = FMath::Clamp(Alpha, 0.0f, 1.0f);
118 |
119 | Alpha = (FMath::Sin(Alpha * PI * (0.2f + 2.5f * Alpha * Alpha * Alpha)) * FMath::Pow(1.0f - Alpha, 2.2f) + Alpha) * (1.0f + (1.2f * (1.0f - Alpha)));
120 |
121 | return Start + (End - Start) * Alpha;
122 | }
123 |
124 | float UCommonEasingLibrary::EaseInQuad(float Start, float End, float Alpha)
125 | {
126 | End -= Start;
127 | return End * Alpha * Alpha + Start;
128 | }
129 |
130 | float UCommonEasingLibrary::EaseOutQuad(float Start, float End, float Alpha)
131 | {
132 | End -= Start;
133 | return -End * Alpha * (Alpha - 2.0f) + Start;
134 | }
135 |
136 | float UCommonEasingLibrary::EaseInOutQuad(float Start, float End, float Alpha)
137 | {
138 | Alpha /= 0.5f;
139 | End -= Start;
140 |
141 | if (Alpha < 1.0f)
142 | return End * 0.5f * Alpha * Alpha + Start;
143 |
144 | Alpha--;
145 |
146 | return -End * 0.5f * (Alpha * (Alpha - 2.0f) - 1.0f) + Start;
147 | }
148 |
149 | float UCommonEasingLibrary::EaseInCubic(float Start, float End, float Alpha)
150 | {
151 | End -= Start;
152 | return End * Alpha * Alpha * Alpha + Start;
153 | }
154 |
155 | float UCommonEasingLibrary::EaseOutCubic(float Start, float End, float Alpha)
156 | {
157 | Alpha--;
158 | End -= Start;
159 |
160 | return End * (Alpha * Alpha * Alpha + 1.0f) + Start;
161 | }
162 |
163 | float UCommonEasingLibrary::EaseInOutCubic(float Start, float End, float Alpha)
164 | {
165 | Alpha /= 0.5f;
166 | End -= Start;
167 |
168 | if (Alpha < 1.0f)
169 | return End * 0.5f * Alpha * Alpha * Alpha + Start;
170 |
171 | Alpha -= 2.0f;
172 | return End * 0.5f * (Alpha * Alpha * Alpha + 2.0f) + Start;
173 | }
174 |
175 | float UCommonEasingLibrary::EaseInQuart(float Start, float End, float Alpha)
176 | {
177 | End -= Start;
178 | return End * Alpha * Alpha * Alpha * Alpha + Start;
179 | }
180 |
181 | float UCommonEasingLibrary::EaseOutQuart(float Start, float End, float Alpha)
182 | {
183 | Alpha--;
184 | End -= Start;
185 | return -End * (Alpha * Alpha * Alpha * Alpha - 1.0f) + Start;
186 | }
187 |
188 | float UCommonEasingLibrary::EaseInOutQuart(float Start, float End, float Alpha)
189 | {
190 | Alpha /= .5f;
191 | End -= Start;
192 | if (Alpha < 1) return End * 0.5f * Alpha * Alpha * Alpha * Alpha + Start;
193 | Alpha -= 2;
194 | return -End * 0.5f * (Alpha * Alpha * Alpha * Alpha - 2) + Start;
195 | }
196 |
197 | float UCommonEasingLibrary::EaseInQuint(float Start, float End, float Alpha)
198 | {
199 | End -= Start;
200 | return End * Alpha * Alpha * Alpha * Alpha * Alpha + Start;
201 | }
202 |
203 | float UCommonEasingLibrary::EaseOutQuint(float Start, float End, float Alpha)
204 | {
205 | Alpha--;
206 | End -= Start;
207 | return End * (Alpha * Alpha * Alpha * Alpha * Alpha + 1) + Start;
208 | }
209 |
210 | float UCommonEasingLibrary::EaseInOutQuint(float Start, float End, float Alpha)
211 | {
212 | Alpha /= .5f;
213 | End -= Start;
214 | if (Alpha < 1) return End * 0.5f * Alpha * Alpha * Alpha * Alpha * Alpha + Start;
215 | Alpha -= 2;
216 | return End * 0.5f * (Alpha * Alpha * Alpha * Alpha * Alpha + 2) + Start;
217 | }
218 |
219 | float UCommonEasingLibrary::EaseInSine(float Start, float End, float Alpha)
220 | {
221 | End -= Start;
222 | return -End * FMath::Cos(Alpha * (PI * 0.5f)) + End + Start;
223 | }
224 |
225 | float UCommonEasingLibrary::EaseOutSine(float Start, float End, float Alpha)
226 | {
227 | End -= Start;
228 | return End * FMath::Sin(Alpha * (PI * 0.5f)) + Start;
229 | }
230 |
231 | float UCommonEasingLibrary::EaseInOutSine(float Start, float End, float Alpha)
232 | {
233 | End -= Start;
234 | return -End * 0.5f * (FMath::Cos(PI * Alpha) - 1) + Start;
235 | }
236 |
237 | float UCommonEasingLibrary::EaseInExpo(float Start, float End, float Alpha)
238 | {
239 | End -= Start;
240 | return End * FMath::Pow(2, 10 * (Alpha - 1)) + Start;
241 | }
242 |
243 | float UCommonEasingLibrary::EaseOutExpo(float Start, float End, float Alpha)
244 | {
245 | End -= Start;
246 | return End * (-FMath::Pow(2, -10 * Alpha) + 1) + Start;
247 | }
248 |
249 | float UCommonEasingLibrary::EaseInOutExpo(float Start, float End, float Alpha)
250 | {
251 | Alpha /= .5f;
252 | End -= Start;
253 |
254 | if (Alpha < 1)
255 | return End * 0.5f * FMath::Pow(2, 10 * (Alpha - 1)) + Start;
256 |
257 | Alpha--;
258 |
259 | return End * 0.5f * (-FMath::Pow(2, -10 * Alpha) + 2) + Start;
260 | }
261 |
262 | float UCommonEasingLibrary::EaseInCirc(float Start, float End, float Alpha)
263 | {
264 | End -= Start;
265 | return -End * (FMath::Sqrt(1 - Alpha * Alpha) - 1) + Start;
266 | }
267 |
268 | float UCommonEasingLibrary::EaseOutCirc(float Start, float End, float Alpha)
269 | {
270 | Alpha--;
271 | End -= Start;
272 | return End * FMath::Sqrt(1 - Alpha * Alpha) + Start;
273 | }
274 |
275 | float UCommonEasingLibrary::EaseInOutCirc(float Start, float End, float Alpha)
276 | {
277 | Alpha /= .5f;
278 | End -= Start;
279 | if (Alpha < 1) return -End * 0.5f * (FMath::Sqrt(1 - Alpha * Alpha) - 1) + Start;
280 | Alpha -= 2;
281 | return End * 0.5f * (FMath::Sqrt(1 - Alpha * Alpha) + 1) + Start;
282 | }
283 |
284 | float UCommonEasingLibrary::EaseInBounce(float Start, float End, float Alpha)
285 | {
286 | End -= Start;
287 | float d = 1.0f;
288 | return End - EaseOutBounce(0, End, d - Alpha) + Start;
289 | }
290 |
291 | float UCommonEasingLibrary::EaseOutBounce(float Start, float End, float Alpha)
292 | {
293 | Alpha /= 1.0f;
294 | End -= Start;
295 | if (Alpha < (1 / 2.75f))
296 | {
297 | return End * (7.5625f * Alpha * Alpha) + Start;
298 | }
299 | else if (Alpha < (2 / 2.75f))
300 | {
301 | Alpha -= (1.5f / 2.75f);
302 | return End * (7.5625f * (Alpha)*Alpha + .75f) + Start;
303 | }
304 | else if (Alpha < (2.5 / 2.75))
305 | {
306 | Alpha -= (2.25f / 2.75f);
307 | return End * (7.5625f * (Alpha)*Alpha + .9375f) + Start;
308 | }
309 | else
310 | {
311 | Alpha -= (2.625f / 2.75f);
312 | return End * (7.5625f * (Alpha)*Alpha + .984375f) + Start;
313 | }
314 | }
315 |
316 | float UCommonEasingLibrary::EaseInOutBounce(float Start, float End, float Alpha)
317 | {
318 | End -= Start;
319 | float d = 1.0f;
320 | if (Alpha < d * 0.5f) return EaseInBounce(0, End, Alpha * 2) * 0.5f + Start;
321 | else return EaseOutBounce(0, End, Alpha * 2 - d) * 0.5f + End * 0.5f + Start;
322 | }
323 |
324 | float UCommonEasingLibrary::EaseInBack(float Start, float End, float Alpha)
325 | {
326 | End -= Start;
327 | Alpha /= 1;
328 | float s = 1.70158f;
329 | return End * (Alpha)*Alpha * ((s + 1) * Alpha - s) + Start;
330 | }
331 |
332 | float UCommonEasingLibrary::EaseOutBack(float Start, float End, float Alpha)
333 | {
334 | float s = 1.70158f;
335 | End -= Start;
336 | Alpha = (Alpha)-1;
337 | return End * ((Alpha)*Alpha * ((s + 1) * Alpha + s) + 1) + Start;
338 | }
339 |
340 | float UCommonEasingLibrary::EaseInOutBack(float Start, float End, float Alpha)
341 | {
342 | float s = 1.70158f;
343 | End -= Start;
344 | Alpha /= .5f;
345 | if ((Alpha) < 1)
346 | {
347 | s *= (1.525f);
348 | return End * 0.5f * (Alpha * Alpha * (((s)+1) * Alpha - s)) + Start;
349 | }
350 | Alpha -= 2;
351 | s *= (1.525f);
352 | return End * 0.5f * ((Alpha)*Alpha * (((s)+1) * Alpha + s) + 2) + Start;
353 | }
354 |
355 | float UCommonEasingLibrary::EaseInElastic(float Start, float End, float Alpha)
356 | {
357 | End -= Start;
358 |
359 | float d = 1.0f;
360 | float p = d * .3f;
361 | float s;
362 | float a = 0;
363 |
364 | if (Alpha == 0)
365 | return Start;
366 |
367 | if ((Alpha /= d) == 1)
368 | return Start + End;
369 |
370 | if (a == 0.0f || a < FMath::Abs(End))
371 | {
372 | a = End;
373 | s = p / 4;
374 | }
375 | else
376 | s = p / (2 * PI) * FMath::Asin(End / a);
377 |
378 | return -(a * FMath::Pow(2, 10 * (Alpha -= 1)) * FMath::Sin((Alpha * d - s) * (2 * PI) / p)) + Start;
379 | }
380 |
381 | float UCommonEasingLibrary::EaseOutElastic(float Start, float End, float Alpha)
382 | {
383 | End -= Start;
384 |
385 | float d = 1.0f;
386 | float p = d * .3f;
387 | float s;
388 | float a = 0;
389 |
390 | if (Alpha == 0) return Start;
391 |
392 | if ((Alpha /= d) == 1) return Start + End;
393 |
394 | if (a == 0.0f || a < FMath::Abs(End))
395 | {
396 | a = End;
397 | s = p * 0.25f;
398 | }
399 | else
400 | {
401 | s = p / (2 * PI) * FMath::Asin(End / a);
402 | }
403 |
404 | return (a * FMath::Pow(2, -10 * Alpha) * FMath::Sin((Alpha * d - s) * (2 * PI) / p) + End + Start);
405 | }
406 |
407 | float UCommonEasingLibrary::EaseInOutElastic(float Start, float End, float Alpha)
408 | {
409 | End -= Start;
410 |
411 | float d = 1.0f;
412 | float p = d * .3f;
413 | float s;
414 | float a = 0;
415 |
416 | if (Alpha == 0) return Start;
417 |
418 | if ((Alpha /= d * 0.5f) == 2) return Start + End;
419 |
420 | if (a == 0.0f || a < FMath::Abs(End))
421 | {
422 | a = End;
423 | s = p / 4;
424 | }
425 | else
426 | {
427 | s = p / (2 * PI) * FMath::Asin(End / a);
428 | }
429 |
430 | if (Alpha < 1) return -0.5f * (a * FMath::Pow(2, 10 * (Alpha -= 1)) * FMath::Sin((Alpha * d - s) * (2 * PI) / p)) + Start;
431 | return a * FMath::Pow(2, -10 * (Alpha -= 1)) * FMath::Sin((Alpha * d - s) * (2 * PI) / p) * 0.5f + End + Start;
432 | }
--------------------------------------------------------------------------------
/unreal_engine/CommonEasingLibrary.h:
--------------------------------------------------------------------------------
1 | // Copyright 2023 MrRobin. All Rights Reserved.
2 |
3 | #pragma once
4 |
5 | #include "CoreMinimal.h"
6 | #include "Kismet/BlueprintFunctionLibrary.h"
7 | #include "CommonEasingLibrary.generated.h"
8 |
9 | UENUM(BlueprintType)
10 | enum class EEaseType : uint8
11 | {
12 | Linear = 0,
13 | Spring,
14 | EaseInQuad,
15 | EaseOutQuad,
16 | EaseInOutQuad,
17 | EaseInCubic,
18 | EaseOutCubic,
19 | EaseInOutCubic,
20 | EaseInQuart,
21 | EaseOutQuart,
22 | EaseInOutQuart,
23 | EaseInQuint,
24 | EaseOutQuint,
25 | EaseInOutQuint,
26 | EaseInSine,
27 | EaseOutSine,
28 | EaseInOutSine,
29 | EaseInExpo,
30 | EaseOutExpo,
31 | EaseInOutExpo,
32 | EaseInCirc,
33 | EaseOutCirc,
34 | EaseInOutCirc,
35 | EaseInBounce,
36 | EaseOutBounce,
37 | EaseInOutBounce,
38 | EaseInBack,
39 | EaseOutBack,
40 | EaseInOutBack,
41 | EaseInElastic,
42 | EaseOutElastic,
43 | EaseInOutElastic
44 | };
45 |
46 | UCLASS()
47 | class COMMONLIBRARY_API UCommonEasingLibrary : public UBlueprintFunctionLibrary
48 | {
49 | GENERATED_BODY()
50 |
51 | public:
52 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
53 | static float GetEaseFromType(EEaseType EaseType, float Start, float End, float Alpha);
54 |
55 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
56 | static float EaseLinear(float Start, float End, float Alpha);
57 |
58 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
59 | static float EaseSpring(float Start, float End, float Alpha);
60 |
61 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
62 | static float EaseInQuad(float Start, float End, float Alpha);
63 |
64 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
65 | static float EaseOutQuad(float Start, float End, float Alpha);
66 |
67 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
68 | static float EaseInOutQuad(float Start, float End, float Alpha);
69 |
70 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
71 | static float EaseInCubic(float Start, float End, float Alpha);
72 |
73 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
74 | static float EaseOutCubic(float Start, float End, float Alpha);
75 |
76 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
77 | static float EaseInOutCubic(float Start, float End, float Alpha);
78 |
79 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
80 | static float EaseInQuart(float Start, float End, float Alpha);
81 |
82 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
83 | static float EaseOutQuart(float Start, float End, float Alpha);
84 |
85 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
86 | static float EaseInOutQuart(float Start, float End, float Alpha);
87 |
88 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
89 | static float EaseInQuint(float Start, float End, float Alpha);
90 |
91 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
92 | static float EaseOutQuint(float Start, float End, float Alpha);
93 |
94 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
95 | static float EaseInOutQuint(float Start, float End, float Alpha);
96 |
97 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
98 | static float EaseInSine(float Start, float End, float Alpha);
99 |
100 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
101 | static float EaseOutSine(float Start, float End, float Alpha);
102 |
103 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
104 | static float EaseInOutSine(float Start, float End, float Alpha);
105 |
106 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
107 | static float EaseInExpo(float Start, float End, float Alpha);
108 |
109 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
110 | static float EaseOutExpo(float Start, float End, float Alpha);
111 |
112 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
113 | static float EaseInOutExpo(float Start, float End, float Alpha);
114 |
115 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
116 | static float EaseInCirc(float Start, float End, float Alpha);
117 |
118 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
119 | static float EaseOutCirc(float Start, float End, float Alpha);
120 |
121 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
122 | static float EaseInOutCirc(float Start, float End, float Alpha);
123 |
124 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
125 | static float EaseInBounce(float Start, float End, float Alpha);
126 |
127 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
128 | static float EaseOutBounce(float Start, float End, float Alpha);
129 |
130 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
131 | static float EaseInOutBounce(float Start, float End, float Alpha);
132 |
133 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
134 | static float EaseInBack(float Start, float End, float Alpha);
135 |
136 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
137 | static float EaseOutBack(float Start, float End, float Alpha);
138 |
139 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
140 | static float EaseInOutBack(float Start, float End, float Alpha);
141 |
142 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
143 | static float EaseInElastic(float Start, float End, float Alpha);
144 |
145 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
146 | static float EaseOutElastic(float Start, float End, float Alpha);
147 |
148 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Easing")
149 | static float EaseInOutElastic(float Start, float End, float Alpha);
150 | };
151 |
--------------------------------------------------------------------------------