ScriptedEntityTweenerMath.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Math/MathUtils.h>
  9. namespace ScriptedEntityTweener
  10. {
  11. ////////////////////////////////////////////////////////////////////////////////////////////////////
  12. //! A collection of common easing/tweening equations.
  13. class EasingEquations
  14. {
  15. public:
  16. template <typename T>
  17. static T GetEasingResult(EasingMethod easeMethod, EasingType easeType, float timeActive, float duration, T valueInitial, T valueTarget)
  18. {
  19. switch (easeMethod)
  20. {
  21. case EasingMethod::Linear:
  22. return valueInitial + (valueTarget - valueInitial) * (timeActive / duration);
  23. case EasingMethod::Quad:
  24. switch (easeType)
  25. {
  26. case EasingType::In:
  27. return GetEasingResultCombinedIn(static_cast<float>(easeMethod), timeActive, duration, valueInitial, valueTarget);
  28. case EasingType::InOut:
  29. return GetEasingResultInOutQuad(timeActive, duration, valueInitial, valueTarget);
  30. default: //EasingType::Out:
  31. return GetEasingResultOutQuad(timeActive, duration, valueInitial, valueTarget);
  32. }
  33. break;
  34. case EasingMethod::Cubic:
  35. switch (easeType)
  36. {
  37. case EasingType::In:
  38. return GetEasingResultCombinedIn(static_cast<float>(easeMethod), timeActive, duration, valueInitial, valueTarget);
  39. case EasingType::InOut:
  40. return GetEasingResultInOutCubic(timeActive, duration, valueInitial, valueTarget);
  41. default: //EasingType::Out:
  42. return GetEasingResultOutCubic(timeActive, duration, valueInitial, valueTarget);
  43. }
  44. break;
  45. case EasingMethod::Quart:
  46. switch (easeType)
  47. {
  48. case EasingType::In:
  49. return GetEasingResultCombinedIn(static_cast<float>(easeMethod), timeActive, duration, valueInitial, valueTarget);
  50. case EasingType::InOut:
  51. return GetEasingResultInOutQuart(timeActive, duration, valueInitial, valueTarget);
  52. default: //EasingType::Out:
  53. return GetEasingResultOutQuart(timeActive, duration, valueInitial, valueTarget);
  54. }
  55. break;
  56. case EasingMethod::Quint:
  57. switch (easeType)
  58. {
  59. case EasingType::In:
  60. return GetEasingResultCombinedIn(static_cast<float>(easeMethod), timeActive, duration, valueInitial, valueTarget);
  61. case EasingType::InOut:
  62. return GetEasingResultInOutQuint(timeActive, duration, valueInitial, valueTarget);
  63. default: //EasingType::Out:
  64. return GetEasingResultOutQuint(timeActive, duration, valueInitial, valueTarget);
  65. }
  66. break;
  67. case EasingMethod::Sine:
  68. switch (easeType)
  69. {
  70. case EasingType::In:
  71. return GetEasingResultInSine(timeActive, duration, valueInitial, valueTarget);
  72. case EasingType::InOut:
  73. return GetEasingResultInOutSine(timeActive, duration, valueInitial, valueTarget);
  74. default: //EasingType::Out:
  75. return GetEasingResultOutSine(timeActive, duration, valueInitial, valueTarget);
  76. }
  77. break;
  78. case EasingMethod::Expo:
  79. switch (easeType)
  80. {
  81. case EasingType::In:
  82. return GetEasingResultInExpo(timeActive, duration, valueInitial, valueTarget);
  83. case EasingType::InOut:
  84. return GetEasingResultInOutExpo(timeActive, duration, valueInitial, valueTarget);
  85. default: //EasingType::Out:
  86. return GetEasingResultOutExpo(timeActive, duration, valueInitial, valueTarget);
  87. }
  88. break;
  89. case EasingMethod::Circ:
  90. switch (easeType)
  91. {
  92. case EasingType::In:
  93. return GetEasingResultInCirc(timeActive, duration, valueInitial, valueTarget);
  94. case EasingType::InOut:
  95. return GetEasingResultInOutCirc(timeActive, duration, valueInitial, valueTarget);
  96. default: //EasingType::Out:
  97. return GetEasingResultOutCirc(timeActive, duration, valueInitial, valueTarget);
  98. }
  99. break;
  100. case EasingMethod::Elastic:
  101. switch (easeType)
  102. {
  103. case EasingType::In:
  104. return GetEasingResultInElastic(timeActive, duration, valueInitial, valueTarget);
  105. case EasingType::InOut:
  106. return GetEasingResultInOutElastic(timeActive, duration, valueInitial, valueTarget);
  107. default: //EasingType::Out:
  108. return GetEasingResultOutElastic(timeActive, duration, valueInitial, valueTarget);
  109. }
  110. break;
  111. case EasingMethod::Back:
  112. switch (easeType)
  113. {
  114. case EasingType::In:
  115. return GetEasingResultInBack(timeActive, duration, valueInitial, valueTarget);
  116. case EasingType::InOut:
  117. return GetEasingResultInOutBack(timeActive, duration, valueInitial, valueTarget);
  118. default: //EasingType::Out:
  119. return GetEasingResultOutBack(timeActive, duration, valueInitial, valueTarget);
  120. }
  121. break;
  122. case EasingMethod::Bounce:
  123. switch (easeType)
  124. {
  125. case EasingType::In:
  126. return GetEasingResultInBounce(timeActive, duration, valueInitial, valueTarget);
  127. case EasingType::InOut:
  128. return GetEasingResultInOutBounce(timeActive, duration, valueInitial, valueTarget);
  129. default: //EasingType::Out:
  130. return GetEasingResultOutBounce(timeActive, duration, valueInitial, valueTarget);
  131. }
  132. break;
  133. }
  134. AZ_Warning("ScriptedEntityTweener", false, "ScriptedEntityTweenerMath::GetEasingResult - Trying to animate with an invalid easing function [%i, %i]", static_cast<int>(easeMethod), static_cast<int>(easeType));
  135. return valueInitial;
  136. }
  137. //!Helper method to get EaseIn results for Quad, Cubic, Quart, and Quint since they all follow the same equation besides from how many times to multiply progressPercent.
  138. template <typename T>
  139. static T GetEasingResultCombinedIn(float expo, float timeActive, float duration, T valueInitial, T valueTarget)
  140. {
  141. float progressPercent = timeActive / duration;
  142. return valueInitial + ((valueTarget - valueInitial) * pow(progressPercent, 1.0f + expo));
  143. }
  144. template <typename T>
  145. static T GetEasingResultInSine(float timeActive, float duration, T valueInitial, T valueTarget)
  146. {
  147. return -(valueTarget - valueInitial) * cos(timeActive / duration * AZ::Constants::HalfPi) + (valueTarget - valueInitial) + valueInitial;
  148. }
  149. template <typename T>
  150. static T GetEasingResultInExpo(float timeActive, float duration, T valueInitial, T valueTarget)
  151. {
  152. return (valueTarget - valueInitial) * pow(2.0f, 10.0f * (timeActive / duration - 1.0f)) + valueInitial;
  153. }
  154. template <typename T>
  155. static T GetEasingResultInCirc(float timeActive, float duration, T valueInitial, T valueTarget)
  156. {
  157. timeActive = timeActive / duration;
  158. return -(valueTarget - valueInitial) * (sqrt(1.0f - timeActive * timeActive) - 1.0f) + valueInitial;
  159. }
  160. template <typename T>
  161. static T GetEasingResultInElastic(float timeActive, float duration, T valueInitial, T valueTarget)
  162. {
  163. float progressPercent = timeActive / duration;
  164. if (progressPercent == 0.0f)
  165. {
  166. return valueInitial;
  167. }
  168. if (progressPercent == 1.0f)
  169. {
  170. return valueTarget;
  171. }
  172. T position = (valueTarget - valueInitial) * pow(2.0f, 10.0f * (progressPercent -= 1.0f));
  173. float elasticAmplitude = 0.3f / 4.0f;
  174. /*
  175. if (amplitudeOverride != 0.0f)
  176. {
  177. elasticAmplitude = amplitudeOverride * elasticAmplitude;
  178. }
  179. */
  180. return valueInitial - (position * sin((progressPercent - elasticAmplitude) * 2.0f * AZ::Constants::Pi / 0.3f));
  181. }
  182. template <typename T>
  183. static T GetEasingResultInBack(float timeActive, float duration, T valueInitial, T valueTarget)
  184. {
  185. float backAmplitude = 1.7337f;
  186. float progressPercent = timeActive / duration;
  187. /*if (amplitudeOverride != 0.0f)
  188. {
  189. backAmplitude = amplitudeOverride;
  190. }
  191. */
  192. return (valueTarget - valueInitial) * progressPercent * progressPercent * ((backAmplitude + 1.0f) * progressPercent - backAmplitude) + valueInitial;
  193. }
  194. template <typename T>
  195. static T GetEasingResultInBounce(float timeActive, float duration, T valueInitial, T valueTarget)
  196. {
  197. const float bounceFullAmplitude = 7.1337f;
  198. float progressPercent = timeActive / duration;
  199. float bounceAmplitudeModifier = 0.0f;
  200. if (progressPercent < (1.0f / 2.75f))
  201. {
  202. bounceAmplitudeModifier = 0.0f;
  203. }
  204. else if (progressPercent < (2.0f / 2.75f))
  205. {
  206. progressPercent -= (1.5f / 2.75f);
  207. bounceAmplitudeModifier = 0.75f;
  208. }
  209. else if (progressPercent < (2.5f / 2.75f))
  210. {
  211. progressPercent -= (2.25f / 2.75f);
  212. bounceAmplitudeModifier = 0.9375f;
  213. }
  214. else
  215. {
  216. progressPercent -= (2.625f / 2.75f);
  217. bounceAmplitudeModifier = 0.984375f;
  218. }
  219. return valueInitial + (valueTarget - valueInitial) * (bounceFullAmplitude * progressPercent * progressPercent + bounceAmplitudeModifier);
  220. }
  221. //EASE OUT VARIANTS
  222. template <typename T>
  223. static T GetEasingResultOutQuad(float timeActive, float duration, T valueInitial, T valueTarget)
  224. {
  225. timeActive = timeActive / duration;
  226. return -(valueTarget - valueInitial) * timeActive * (timeActive - 2.0f) + valueInitial;
  227. }
  228. template <typename T>
  229. static T GetEasingResultOutCubic(float timeActive, float duration, T valueInitial, T valueTarget)
  230. {
  231. timeActive = timeActive / duration;
  232. timeActive--;
  233. return (valueTarget - valueInitial) * (timeActive * timeActive * timeActive + 1.0f) + valueInitial;
  234. }
  235. template <typename T>
  236. static T GetEasingResultOutQuart(float timeActive, float duration, T valueInitial, T valueTarget)
  237. {
  238. timeActive = timeActive / duration;
  239. timeActive--;
  240. return -(valueTarget - valueInitial) * (pow(timeActive, 4) - 1.0f) + valueInitial;
  241. }
  242. template <typename T>
  243. static T GetEasingResultOutQuint(float timeActive, float duration, T valueInitial, T valueTarget)
  244. {
  245. timeActive = timeActive / duration;
  246. timeActive--;
  247. return (valueTarget - valueInitial) * (pow(timeActive, 5) + 1.0f) + valueInitial;
  248. }
  249. template <typename T>
  250. static T GetEasingResultOutSine(float timeActive, float duration, T valueInitial, T valueTarget)
  251. {
  252. return (valueTarget - valueInitial) * sin(timeActive / duration * AZ::Constants::HalfPi) + valueInitial;
  253. }
  254. template <typename T>
  255. static T GetEasingResultOutExpo(float timeActive, float duration, T valueInitial, T valueTarget)
  256. {
  257. return (valueTarget - valueInitial) * (-pow(2.0f, -10.0f * timeActive / duration) + 1.0f) + valueInitial;
  258. }
  259. template <typename T>
  260. static T GetEasingResultOutCirc(float timeActive, float duration, T valueInitial, T valueTarget)
  261. {
  262. timeActive = timeActive / duration;
  263. timeActive--;
  264. return (valueTarget - valueInitial) * sqrt(1.0f - timeActive * timeActive) + valueInitial;
  265. }
  266. template <typename T>
  267. static T GetEasingResultOutElastic(float timeActive, float duration, T valueInitial, T valueTarget)
  268. {
  269. float progressPercent = timeActive / duration;
  270. if (progressPercent == 0.0f)
  271. {
  272. return valueInitial;
  273. }
  274. if (progressPercent == 1.0f)
  275. {
  276. return valueTarget;
  277. }
  278. T distance = valueTarget - valueInitial;
  279. T positionFix = distance * pow(2.0f, -10.0f * progressPercent);
  280. float constant = 0.3f / 4.0f;
  281. /*
  282. if (amplitudeOverride != -1)
  283. constant = amplitudeOverride*constant;
  284. */
  285. return positionFix * sin((progressPercent - constant) * 2.0f * AZ::Constants::Pi / 0.3f) + valueTarget;
  286. }
  287. template <typename T>
  288. static T GetEasingResultOutBack(float timeActive, float duration, T valueInitial, T valueTarget)
  289. {
  290. float progressPercent = timeActive / duration;
  291. float constant = 1.7337f;
  292. /*
  293. if (amplitudeOverride != -1)
  294. constant = amplitudeOverride;
  295. */
  296. progressPercent--;
  297. return (valueTarget - valueInitial) * (progressPercent * progressPercent * ((constant + 1.0f) * progressPercent + constant) + 1.0f) + valueInitial;
  298. }
  299. template <typename T>
  300. static T GetEasingResultOutBounce(float timeActive, float duration, T valueInitial, T valueTarget)
  301. {
  302. float progressPercent = timeActive / duration;
  303. if (progressPercent < (1.0f / 2.75f))
  304. {
  305. return (valueTarget - valueInitial) * (7.5625f * progressPercent * progressPercent) + valueInitial;
  306. }
  307. else if (progressPercent < (2.0f / 2.75f))
  308. {
  309. progressPercent -= (1.5f / 2.75f);
  310. return (valueTarget - valueInitial) * (7.5625f * progressPercent * progressPercent + 0.75f) + valueInitial;
  311. }
  312. else if (progressPercent < (2.5f / 2.75f))
  313. {
  314. progressPercent -= (2.25f / 2.75f);
  315. return (valueTarget - valueInitial) * (7.5625f * progressPercent * progressPercent + 0.9375f) + valueInitial;
  316. }
  317. else
  318. {
  319. progressPercent -= (2.625f / 2.75f);
  320. return (valueTarget - valueInitial) * (7.5625f * progressPercent * progressPercent + 0.984375f) + valueInitial;
  321. }
  322. }
  323. //EASE IN OUT VARIANTS
  324. template <typename T>
  325. static T GetEasingResultInOutQuad(float timeActive, float duration, T valueInitial, T valueTarget)
  326. {
  327. timeActive /= duration / 2.0f;
  328. if (timeActive < 1.0f)
  329. {
  330. return (valueTarget - valueInitial) / 2.0f * timeActive * timeActive + valueInitial;
  331. }
  332. timeActive--;
  333. return -(valueTarget - valueInitial) / 2.0f * (timeActive * (timeActive - 2.0f) - 1) + valueInitial;
  334. }
  335. template <typename T>
  336. static T GetEasingResultInOutCubic(float timeActive, float duration, T valueInitial, T valueTarget)
  337. {
  338. timeActive /= duration / 2.0f;
  339. if (timeActive < 1.0f)
  340. {
  341. return (valueTarget - valueInitial) / 2.0f * timeActive * timeActive * timeActive + valueInitial;
  342. }
  343. timeActive -= 2.0f;
  344. return (valueTarget - valueInitial) / 2.0f * (timeActive * timeActive * timeActive + 2.0f) + valueInitial;
  345. }
  346. template <typename T>
  347. static T GetEasingResultInOutQuart(float timeActive, float duration, T valueInitial, T valueTarget)
  348. {
  349. timeActive /= duration / 2.0f;
  350. if (timeActive < 1.0f)
  351. {
  352. return (valueTarget - valueInitial) / 2.0f * timeActive * timeActive * timeActive * timeActive + valueInitial;
  353. }
  354. timeActive -= 2.0f;
  355. return -(valueTarget - valueInitial) / 2.0f * (timeActive * timeActive * timeActive * timeActive - 2.0f) + valueInitial;
  356. }
  357. template <typename T>
  358. static T GetEasingResultInOutQuint(float timeActive, float duration, T valueInitial, T valueTarget)
  359. {
  360. timeActive /= duration / 2.0f;
  361. if (timeActive < 1.0f)
  362. {
  363. return (valueTarget - valueInitial) / 2.0f * timeActive * timeActive * timeActive * timeActive * timeActive + valueInitial;
  364. }
  365. timeActive -= 2.0f;
  366. return (valueTarget - valueInitial) / 2.0f * (timeActive * timeActive * timeActive * timeActive * timeActive + 2.0f) + valueInitial;
  367. }
  368. template <typename T>
  369. static T GetEasingResultInOutSine(float timeActive, float duration, T valueInitial, T valueTarget)
  370. {
  371. return -(valueTarget - valueInitial) / 2.0f * (cos(AZ::Constants::Pi * timeActive / duration) - 1.0f) + valueInitial;
  372. }
  373. template <typename T>
  374. static T GetEasingResultInOutExpo(float timeActive, float duration, T valueInitial, T valueTarget)
  375. {
  376. timeActive /= duration / 2.0f;
  377. if (timeActive < 1.0f)
  378. {
  379. return (valueTarget - valueInitial) / 2.0f * pow(2.0f, 10.0f * (timeActive - 1.0f)) + valueInitial;
  380. }
  381. timeActive--;
  382. return (valueTarget - valueInitial) / 2.0f * (-pow(2.0f, -10.0f * timeActive) + 2.0f) + valueInitial;
  383. }
  384. template <typename T>
  385. static T GetEasingResultInOutCirc(float timeActive, float duration, T valueInitial, T valueTarget)
  386. {
  387. timeActive /= duration / 2.0f;
  388. if (timeActive < 1.0f)
  389. {
  390. return -(valueTarget - valueInitial) / 2.0f * (sqrt(1.0f - timeActive * timeActive) - 1.0f) + valueInitial;
  391. }
  392. timeActive -= 2.0f;
  393. return (valueTarget - valueInitial) / 2.0f * (sqrt(1.0f - timeActive * timeActive) - 1.0f) + valueInitial;
  394. }
  395. template <typename T>
  396. static T GetEasingResultInOutElastic(float timeActive, float duration, T valueInitial, T valueTarget)
  397. {
  398. float progressPercent = timeActive / duration;
  399. progressPercent *= 2.0f;
  400. if (progressPercent == 0.0f)
  401. {
  402. return valueInitial;
  403. }
  404. if (progressPercent == 2.0f)
  405. {
  406. return valueTarget;
  407. }
  408. T distance = valueTarget - valueInitial;
  409. float constant = .3f * 1.5f;
  410. /*
  411. if (amplitudeOverride != -1)
  412. constant = amplitudeOverride*constant;
  413. */
  414. if (progressPercent < 1.0f)
  415. {
  416. T positionFix = distance * pow(2.0f, 10.0f * (progressPercent -= 1.0f));
  417. return (positionFix * sin((progressPercent - (constant / 4.0f)) * 2.0f * AZ::Constants::Pi / constant)) * (-0.5f) + valueInitial;
  418. }
  419. else
  420. {
  421. T positionFix = distance * pow(2.0f, -10.0f * (progressPercent -= 1.0f));
  422. return positionFix * sin((progressPercent - constant / 4.0f) * 2.0f * AZ::Constants::Pi / constant) * 0.5f + valueTarget;
  423. }
  424. }
  425. template <typename T>
  426. static T GetEasingResultInOutBack(float timeActive, float duration, T valueInitial, T valueTarget)
  427. {
  428. float progressPercent = timeActive / duration;
  429. float constant = 1.7337f;
  430. /*
  431. if (amplitudeOverride != -1)
  432. constant = amplitudeOverride;
  433. */
  434. progressPercent *= 2.0f;
  435. if (progressPercent < 1.0f)
  436. {
  437. constant = constant * 1.525f;
  438. return (valueTarget - valueInitial) / 2.0f * (progressPercent * progressPercent * ((constant + 1.0f) * progressPercent - constant)) + valueInitial;
  439. }
  440. progressPercent -= 2.0f;
  441. constant = constant * 1.525f;
  442. return (valueTarget - valueInitial) / 2.0f * (progressPercent * progressPercent * ((constant + 1.0f) * progressPercent + constant) + 2.0f) + valueInitial;
  443. }
  444. template <typename T>
  445. static T GetEasingResultInOutBounce(float timeActive, float duration, T valueInitial, T valueTarget)
  446. {
  447. float progressPercent = timeActive / duration;
  448. T zero = valueInitial - valueInitial;
  449. if (progressPercent < 0.5f)
  450. {
  451. return GetEasingResultInBounce(timeActive, duration / 2.0f, zero, (valueTarget - valueInitial)) * 0.5f + valueInitial;
  452. }
  453. else
  454. {
  455. return GetEasingResultOutBounce(timeActive - (duration / 2.0f), duration / 2.0f, zero, (valueTarget - valueInitial)) * 0.5f + (valueTarget - valueInitial) * 0.5f + valueInitial;
  456. }
  457. }
  458. };
  459. }