├── .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 | Easing Functions logo 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 | [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/mrrobinofficial/easing/blob/HEAD/LICENSE.txt) 19 | ![maintenance-status](https://img.shields.io/badge/maintenance-as--is-yellow.svg) 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 | --------------------------------------------------------------------------------