easings_example.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*******************************************************************************************
  2. *
  3. * raylib [easings] example
  4. *
  5. * This example has been created using raylib 2.5 (www.raylib.com)
  6. * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
  7. *
  8. * Copyright (c) 2019 Juan Miguel López
  9. *
  10. ********************************************************************************************/
  11. #include <raylib.h>
  12. #include "easings.h"
  13. // Application constants
  14. #define SCR_WIDTH 800
  15. #define SCR_HEIGHT 450
  16. #define BALL_RADIUS 16.0f
  17. #define BALL_COLOR MAROON
  18. #define PAD 80.0f
  19. #define START_X (0.0f + (BALL_RADIUS) + (PAD))
  20. #define END_X ((SCR_WIDTH) - ((BALL_RADIUS) + (PAD)))
  21. #define START_Y (0.0f + (BALL_RADIUS) + (PAD))
  22. #define END_Y ((SCR_HEIGHT) - ((BALL_RADIUS) + (PAD)))
  23. #define T_ADVANCE 1.0f
  24. #define D_DFT 300.0f
  25. #define TARGET_FPS 60
  26. #define BG_COLOR RAYWHITE
  27. #define TEXT_COLOR LIGHTGRAY
  28. #define FONT_SIZE 20
  29. #define D_STEP 20.0f
  30. #define D_STEP_FINE 2.0f
  31. #define D_MIN 1.0f
  32. #define D_MAX 10000.0f
  33. // Application control keys
  34. #define KEY_NEXT_EASE_X KEY_RIGHT
  35. #define KEY_PREV_EASE_X KEY_LEFT
  36. #define KEY_NEXT_EASE_Y KEY_DOWN
  37. #define KEY_PREV_EASE_Y KEY_UP
  38. #define KEY_INCR_D_STEP KEY_W
  39. #define KEY_DECR_D_STEP KEY_Q
  40. #define KEY_INCR_D_FINE KEY_S
  41. #define KEY_DECR_D_FINE KEY_A
  42. #define KEY_PLAY_PAUSE KEY_ENTER
  43. #define KEY_RESTART KEY_SPACE
  44. #define KEY_TOGGLE_UNBOUNDED_T KEY_T
  45. // Easing types
  46. enum EasingTypes {
  47. EASE_LINEAR_NONE,
  48. EASE_LINEAR_IN,
  49. EASE_LINEAR_OUT,
  50. EASE_LINEAR_IN_OUT,
  51. EASE_SINE_IN,
  52. EASE_SINE_OUT,
  53. EASE_SINE_IN_OUT,
  54. EASE_CIRC_IN,
  55. EASE_CIRC_OUT,
  56. EASE_CIRC_IN_OUT,
  57. EASE_CUBIC_IN,
  58. EASE_CUBIC_OUT,
  59. EASE_CUBIC_IN_OUT,
  60. EASE_QUAD_IN,
  61. EASE_QUAD_OUT,
  62. EASE_QUAD_IN_OUT,
  63. EASE_EXPO_IN,
  64. EASE_EXPO_OUT,
  65. EASE_EXPO_IN_OUT,
  66. EASE_BACK_IN,
  67. EASE_BACK_OUT,
  68. EASE_BACK_IN_OUT,
  69. EASE_BOUNCE_OUT,
  70. EASE_BOUNCE_IN,
  71. EASE_BOUNCE_IN_OUT,
  72. EASE_ELASTIC_IN,
  73. EASE_ELASTIC_OUT,
  74. EASE_ELASTIC_IN_OUT,
  75. NUM_EASING_TYPES,
  76. EASING_NONE = NUM_EASING_TYPES
  77. };
  78. static float NoEase(float t, float b, float c, float d); // NoEase function declaration, function used when "no easing" is selected for any axis
  79. // Easing functions reference data
  80. static const struct {
  81. const char *name;
  82. float (*func)(float, float, float, float);
  83. } Easings[] = {
  84. [EASE_LINEAR_NONE] = {
  85. .name = "EaseLinearNone",
  86. .func = EaseLinearNone,
  87. },
  88. [EASE_LINEAR_IN] = {
  89. .name = "EaseLinearIn",
  90. .func = EaseLinearIn,
  91. },
  92. [EASE_LINEAR_OUT] = {
  93. .name = "EaseLinearOut",
  94. .func = EaseLinearOut,
  95. },
  96. [EASE_LINEAR_IN_OUT] = {
  97. .name = "EaseLinearInOut",
  98. .func = EaseLinearInOut,
  99. },
  100. [EASE_SINE_IN] = {
  101. .name = "EaseSineIn",
  102. .func = EaseSineIn,
  103. },
  104. [EASE_SINE_OUT] = {
  105. .name = "EaseSineOut",
  106. .func = EaseSineOut,
  107. },
  108. [EASE_SINE_IN_OUT] = {
  109. .name = "EaseSineInOut",
  110. .func = EaseSineInOut,
  111. },
  112. [EASE_CIRC_IN] = {
  113. .name = "EaseCircIn",
  114. .func = EaseCircIn,
  115. },
  116. [EASE_CIRC_OUT] = {
  117. .name = "EaseCircOut",
  118. .func = EaseCircOut,
  119. },
  120. [EASE_CIRC_IN_OUT] = {
  121. .name = "EaseCircInOut",
  122. .func = EaseCircInOut,
  123. },
  124. [EASE_CUBIC_IN] = {
  125. .name = "EaseCubicIn",
  126. .func = EaseCubicIn,
  127. },
  128. [EASE_CUBIC_OUT] = {
  129. .name = "EaseCubicOut",
  130. .func = EaseCubicOut,
  131. },
  132. [EASE_CUBIC_IN_OUT] = {
  133. .name = "EaseCubicInOut",
  134. .func = EaseCubicInOut,
  135. },
  136. [EASE_QUAD_IN] = {
  137. .name = "EaseQuadIn",
  138. .func = EaseQuadIn,
  139. },
  140. [EASE_QUAD_OUT] = {
  141. .name = "EaseQuadOut",
  142. .func = EaseQuadOut,
  143. },
  144. [EASE_QUAD_IN_OUT] = {
  145. .name = "EaseQuadInOut",
  146. .func = EaseQuadInOut,
  147. },
  148. [EASE_EXPO_IN] = {
  149. .name = "EaseExpoIn",
  150. .func = EaseExpoIn,
  151. },
  152. [EASE_EXPO_OUT] = {
  153. .name = "EaseExpoOut",
  154. .func = EaseExpoOut,
  155. },
  156. [EASE_EXPO_IN_OUT] = {
  157. .name = "EaseExpoInOut",
  158. .func = EaseExpoInOut,
  159. },
  160. [EASE_BACK_IN] = {
  161. .name = "EaseBackIn",
  162. .func = EaseBackIn,
  163. },
  164. [EASE_BACK_OUT] = {
  165. .name = "EaseBackOut",
  166. .func = EaseBackOut,
  167. },
  168. [EASE_BACK_IN_OUT] = {
  169. .name = "EaseBackInOut",
  170. .func = EaseBackInOut,
  171. },
  172. [EASE_BOUNCE_OUT] = {
  173. .name = "EaseBounceOut",
  174. .func = EaseBounceOut,
  175. },
  176. [EASE_BOUNCE_IN] = {
  177. .name = "EaseBounceIn",
  178. .func = EaseBounceIn,
  179. },
  180. [EASE_BOUNCE_IN_OUT] = {
  181. .name = "EaseBounceInOut",
  182. .func = EaseBounceInOut,
  183. },
  184. [EASE_ELASTIC_IN] = {
  185. .name = "EaseElasticIn",
  186. .func = EaseElasticIn,
  187. },
  188. [EASE_ELASTIC_OUT] = {
  189. .name = "EaseElasticOut",
  190. .func = EaseElasticOut,
  191. },
  192. [EASE_ELASTIC_IN_OUT] = {
  193. .name = "EaseElasticInOut",
  194. .func = EaseElasticInOut,
  195. },
  196. [EASING_NONE] = {
  197. .name = "None",
  198. .func = NoEase,
  199. },
  200. };
  201. int main(void)
  202. {
  203. // Initialization
  204. //--------------------------------------------------------------------------------------
  205. Vector2 ballPos = { .x = START_X, .y = START_Y };
  206. float t = 0.0f; // Current time (in any unit measure, but same unit as duration)
  207. float d = D_DFT; // Total time it should take to complete (duration)
  208. bool paused = true;
  209. bool boundedT = true; // If true, t will stop when d >= td, otherwise t will keep adding td to its value every loop
  210. enum EasingTypes easingX = EASING_NONE; // Easing selected for x axis
  211. enum EasingTypes easingY = EASING_NONE; // Easing selected for y axis
  212. InitWindow(SCR_WIDTH, SCR_HEIGHT, "raylib [easings] example");
  213. SetTargetFPS(TARGET_FPS);
  214. //--------------------------------------------------------------------------------------
  215. // Main game loop
  216. while (!WindowShouldClose()) // Detect window close button or ESC key
  217. {
  218. // Update
  219. //----------------------------------------------------------------------------------
  220. if (IsKeyPressed(KEY_TOGGLE_UNBOUNDED_T))
  221. boundedT = 1 - boundedT;
  222. // Choose easing for the X axis
  223. if (IsKeyPressed(KEY_NEXT_EASE_X))
  224. {
  225. ++easingX;
  226. if (easingX > EASING_NONE)
  227. easingX = 0;
  228. }
  229. else if (IsKeyPressed(KEY_PREV_EASE_X))
  230. {
  231. if (easingX == 0)
  232. easingX = EASING_NONE;
  233. else
  234. --easingX;
  235. }
  236. // Choose easing for the Y axis
  237. if (IsKeyPressed(KEY_NEXT_EASE_Y))
  238. {
  239. ++easingY;
  240. if (easingY > EASING_NONE)
  241. easingY = 0;
  242. }
  243. else if (IsKeyPressed(KEY_PREV_EASE_Y))
  244. {
  245. if (easingY == 0)
  246. easingY = EASING_NONE;
  247. else
  248. --easingY;
  249. }
  250. // Change d (duration) value
  251. if (IsKeyPressed(KEY_INCR_D_STEP) && d < D_MAX - D_STEP)
  252. d += D_STEP;
  253. else if (IsKeyPressed(KEY_DECR_D_STEP) && d > D_MIN + D_STEP)
  254. d -= D_STEP;
  255. if (IsKeyDown(KEY_INCR_D_FINE) && d < D_MAX - D_STEP_FINE)
  256. d += D_STEP_FINE;
  257. else if (IsKeyDown(KEY_DECR_D_FINE) && d > D_MIN + D_STEP_FINE)
  258. d -= D_STEP_FINE;
  259. // Play, pause and restart controls
  260. if (IsKeyPressed(KEY_RESTART) ||
  261. IsKeyPressed(KEY_NEXT_EASE_X) || IsKeyPressed(KEY_PREV_EASE_X) ||
  262. IsKeyPressed(KEY_NEXT_EASE_Y) || IsKeyPressed(KEY_PREV_EASE_Y) ||
  263. IsKeyPressed(KEY_INCR_D_STEP) || IsKeyPressed(KEY_DECR_D_STEP) ||
  264. IsKeyPressed(KEY_TOGGLE_UNBOUNDED_T) ||
  265. IsKeyDown(KEY_INCR_D_FINE) || IsKeyDown(KEY_DECR_D_FINE) ||
  266. (IsKeyPressed(KEY_PLAY_PAUSE) && boundedT == true && t >= d))
  267. {
  268. t = 0.0f;
  269. ballPos.x = START_X;
  270. ballPos.y = START_Y;
  271. paused = true;
  272. }
  273. if (IsKeyPressed(KEY_PLAY_PAUSE))
  274. paused = 1 - paused;
  275. // Movement computation
  276. if ((paused == false) &&
  277. ((boundedT == true && t < d) || boundedT == false))
  278. {
  279. ballPos.x = Easings[easingX].func(t, START_X, END_X - START_X, d);
  280. ballPos.y = Easings[easingY].func(t, START_Y, END_Y - START_Y, d);
  281. t += T_ADVANCE;
  282. }
  283. //----------------------------------------------------------------------------------
  284. // Draw
  285. //----------------------------------------------------------------------------------
  286. BeginDrawing();
  287. ClearBackground(BG_COLOR);
  288. // Draw information text
  289. int line = 0;
  290. DrawText(TextFormat("Easing x: %s", Easings[easingX].name), 0, FONT_SIZE * (line++), FONT_SIZE, TEXT_COLOR);
  291. DrawText(TextFormat("Easing y: %s", Easings[easingY].name), 0, FONT_SIZE * (line++), FONT_SIZE, TEXT_COLOR);
  292. DrawText(TextFormat("t (%c) = %.2f d = %.2f", (boundedT == true)? 'b' : 'u', t, d),
  293. 0, FONT_SIZE * (line++), FONT_SIZE, TEXT_COLOR);
  294. // Draw instructions text
  295. line = 1;
  296. DrawText("Use ENTER to play or pause movement, use SPACE to restart", 0, SCR_HEIGHT - FONT_SIZE * (line++), FONT_SIZE, TEXT_COLOR);
  297. DrawText("Use D and W or A and S keys to change duration", 0, SCR_HEIGHT - FONT_SIZE * (line++), FONT_SIZE, TEXT_COLOR);
  298. DrawText("Use LEFT or RIGHT keys to choose easing for the x axis", 0, SCR_HEIGHT - FONT_SIZE * (line++), FONT_SIZE, TEXT_COLOR);
  299. DrawText("Use UP or DOWN keys to choose easing for the y axis", 0, SCR_HEIGHT - FONT_SIZE * (line++), FONT_SIZE, TEXT_COLOR);
  300. // Draw ball
  301. DrawCircleV(ballPos, BALL_RADIUS, BALL_COLOR);
  302. EndDrawing();
  303. //----------------------------------------------------------------------------------
  304. }
  305. // De-Initialization
  306. //--------------------------------------------------------------------------------------
  307. CloseWindow();
  308. //--------------------------------------------------------------------------------------
  309. return 0;
  310. }
  311. // NoEase function, used when "no easing" is selected for any axis. It just ignores all parameters besides b.
  312. static float NoEase(float t, float b, float c, float d)
  313. {
  314. float burn = t + b + c + d; // Hack to avoid compiler warning (about unused variables)
  315. d += burn;
  316. return b;
  317. }