1 | /******************************************************************************************* |
2 | * |
3 | * raylib [easings] example - Easings Testbed |
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 | * Example contributed by Juan Miguel López (@flashback-fx) and reviewed by Ramon Santamaria (@raysan5) |
9 | * |
10 | * Copyright (c) 2019 Juan Miguel López (@flashback-fx ) and Ramon Santamaria (@raysan5) |
11 | * |
12 | ********************************************************************************************/ |
13 | |
14 | #include <raylib.h> |
15 | |
16 | #include "easings.h" |
17 | |
18 | #define FONT_SIZE 20 |
19 | |
20 | #define D_STEP 20.0f |
21 | #define D_STEP_FINE 2.0f |
22 | #define D_MIN 1.0f |
23 | #define D_MAX 10000.0f |
24 | |
25 | // Easing types |
26 | enum EasingTypes { |
27 | EASE_LINEAR_NONE = 0, |
28 | EASE_LINEAR_IN, |
29 | EASE_LINEAR_OUT, |
30 | EASE_LINEAR_IN_OUT, |
31 | EASE_SINE_IN, |
32 | EASE_SINE_OUT, |
33 | EASE_SINE_IN_OUT, |
34 | EASE_CIRC_IN, |
35 | EASE_CIRC_OUT, |
36 | EASE_CIRC_IN_OUT, |
37 | EASE_CUBIC_IN, |
38 | EASE_CUBIC_OUT, |
39 | EASE_CUBIC_IN_OUT, |
40 | EASE_QUAD_IN, |
41 | EASE_QUAD_OUT, |
42 | EASE_QUAD_IN_OUT, |
43 | EASE_EXPO_IN, |
44 | EASE_EXPO_OUT, |
45 | EASE_EXPO_IN_OUT, |
46 | EASE_BACK_IN, |
47 | EASE_BACK_OUT, |
48 | EASE_BACK_IN_OUT, |
49 | EASE_BOUNCE_OUT, |
50 | EASE_BOUNCE_IN, |
51 | EASE_BOUNCE_IN_OUT, |
52 | EASE_ELASTIC_IN, |
53 | EASE_ELASTIC_OUT, |
54 | EASE_ELASTIC_IN_OUT, |
55 | NUM_EASING_TYPES, |
56 | EASING_NONE = NUM_EASING_TYPES |
57 | }; |
58 | |
59 | |
60 | static float NoEase(float t, float b, float c, float d); // NoEase function declaration, function used when "no easing" is selected for any axis |
61 | |
62 | |
63 | // Easing functions reference data |
64 | static const struct { |
65 | const char *name; |
66 | float (*func)(float, float, float, float); |
67 | } Easings[] = { |
68 | [EASE_LINEAR_NONE] = { .name = "EaseLinearNone" , .func = EaseLinearNone }, |
69 | [EASE_LINEAR_IN] = { .name = "EaseLinearIn" , .func = EaseLinearIn }, |
70 | [EASE_LINEAR_OUT] = { .name = "EaseLinearOut" , .func = EaseLinearOut }, |
71 | [EASE_LINEAR_IN_OUT] = { .name = "EaseLinearInOut" , .func = EaseLinearInOut }, |
72 | [EASE_SINE_IN] = { .name = "EaseSineIn" , .func = EaseSineIn }, |
73 | [EASE_SINE_OUT] = { .name = "EaseSineOut" , .func = EaseSineOut }, |
74 | [EASE_SINE_IN_OUT] = { .name = "EaseSineInOut" , .func = EaseSineInOut }, |
75 | [EASE_CIRC_IN] = { .name = "EaseCircIn" , .func = EaseCircIn }, |
76 | [EASE_CIRC_OUT] = { .name = "EaseCircOut" , .func = EaseCircOut }, |
77 | [EASE_CIRC_IN_OUT] = { .name = "EaseCircInOut" , .func = EaseCircInOut }, |
78 | [EASE_CUBIC_IN] = { .name = "EaseCubicIn" , .func = EaseCubicIn }, |
79 | [EASE_CUBIC_OUT] = { .name = "EaseCubicOut" , .func = EaseCubicOut }, |
80 | [EASE_CUBIC_IN_OUT] = { .name = "EaseCubicInOut" , .func = EaseCubicInOut }, |
81 | [EASE_QUAD_IN] = { .name = "EaseQuadIn" , .func = EaseQuadIn }, |
82 | [EASE_QUAD_OUT] = { .name = "EaseQuadOut" , .func = EaseQuadOut }, |
83 | [EASE_QUAD_IN_OUT] = { .name = "EaseQuadInOut" , .func = EaseQuadInOut }, |
84 | [EASE_EXPO_IN] = { .name = "EaseExpoIn" , .func = EaseExpoIn }, |
85 | [EASE_EXPO_OUT] = { .name = "EaseExpoOut" , .func = EaseExpoOut }, |
86 | [EASE_EXPO_IN_OUT] = { .name = "EaseExpoInOut" , .func = EaseExpoInOut }, |
87 | [EASE_BACK_IN] = { .name = "EaseBackIn" , .func = EaseBackIn }, |
88 | [EASE_BACK_OUT] = { .name = "EaseBackOut" , .func = EaseBackOut }, |
89 | [EASE_BACK_IN_OUT] = { .name = "EaseBackInOut" , .func = EaseBackInOut }, |
90 | [EASE_BOUNCE_OUT] = { .name = "EaseBounceOut" , .func = EaseBounceOut }, |
91 | [EASE_BOUNCE_IN] = { .name = "EaseBounceIn" , .func = EaseBounceIn }, |
92 | [EASE_BOUNCE_IN_OUT] = { .name = "EaseBounceInOut" , .func = EaseBounceInOut }, |
93 | [EASE_ELASTIC_IN] = { .name = "EaseElasticIn" , .func = EaseElasticIn }, |
94 | [EASE_ELASTIC_OUT] = { .name = "EaseElasticOut" , .func = EaseElasticOut }, |
95 | [EASE_ELASTIC_IN_OUT] = { .name = "EaseElasticInOut" , .func = EaseElasticInOut }, |
96 | [EASING_NONE] = { .name = "None" , .func = NoEase }, |
97 | }; |
98 | |
99 | |
100 | int main(void) |
101 | { |
102 | // Initialization |
103 | //-------------------------------------------------------------------------------------- |
104 | const int screenWidth = 800; |
105 | const int screenHeight = 450; |
106 | |
107 | InitWindow(screenWidth, screenHeight, "raylib [easings] example - easings testbed" ); |
108 | |
109 | Vector2 ballPosition = { 100.0f, 200.0f }; |
110 | |
111 | float t = 0.0f; // Current time (in any unit measure, but same unit as duration) |
112 | float d = 300.0f; // Total time it should take to complete (duration) |
113 | bool paused = true; |
114 | bool boundedT = true; // If true, t will stop when d >= td, otherwise t will keep adding td to its value every loop |
115 | |
116 | int easingX = EASING_NONE; // Easing selected for x axis |
117 | int easingY = EASING_NONE; // Easing selected for y axis |
118 | |
119 | SetTargetFPS(60); |
120 | //-------------------------------------------------------------------------------------- |
121 | |
122 | // Main game loop |
123 | while (!WindowShouldClose()) // Detect window close button or ESC key |
124 | { |
125 | // Update |
126 | //---------------------------------------------------------------------------------- |
127 | if (IsKeyPressed(KEY_T)) boundedT = !boundedT; |
128 | |
129 | // Choose easing for the X axis |
130 | if (IsKeyPressed(KEY_RIGHT)) |
131 | { |
132 | easingX++; |
133 | |
134 | if (easingX > EASING_NONE) easingX = 0; |
135 | } |
136 | else if (IsKeyPressed(KEY_LEFT)) |
137 | { |
138 | if (easingX == 0) easingX = EASING_NONE; |
139 | else easingX--; |
140 | } |
141 | |
142 | // Choose easing for the Y axis |
143 | if (IsKeyPressed(KEY_DOWN)) |
144 | { |
145 | easingY++; |
146 | |
147 | if (easingY > EASING_NONE) easingY = 0; |
148 | } |
149 | else if (IsKeyPressed(KEY_UP)) |
150 | { |
151 | if (easingY == 0) easingY = EASING_NONE; |
152 | else easingY--; |
153 | } |
154 | |
155 | // Change d (duration) value |
156 | if (IsKeyPressed(KEY_W) && d < D_MAX - D_STEP) d += D_STEP; |
157 | else if (IsKeyPressed(KEY_Q) && d > D_MIN + D_STEP) d -= D_STEP; |
158 | |
159 | if (IsKeyDown(KEY_S) && d < D_MAX - D_STEP_FINE) d += D_STEP_FINE; |
160 | else if (IsKeyDown(KEY_A) && d > D_MIN + D_STEP_FINE) d -= D_STEP_FINE; |
161 | |
162 | // Play, pause and restart controls |
163 | if (IsKeyPressed(KEY_SPACE) || IsKeyPressed(KEY_T) || |
164 | IsKeyPressed(KEY_RIGHT) || IsKeyPressed(KEY_LEFT) || |
165 | IsKeyPressed(KEY_DOWN) || IsKeyPressed(KEY_UP) || |
166 | IsKeyPressed(KEY_W) || IsKeyPressed(KEY_Q) || |
167 | IsKeyDown(KEY_S) || IsKeyDown(KEY_A) || |
168 | (IsKeyPressed(KEY_ENTER) && (boundedT == true) && (t >= d))) |
169 | { |
170 | t = 0.0f; |
171 | ballPosition.x = 100.0f; |
172 | ballPosition.y = 100.0f; |
173 | paused = true; |
174 | } |
175 | |
176 | if (IsKeyPressed(KEY_ENTER)) paused = !paused; |
177 | |
178 | // Movement computation |
179 | if (!paused && ((boundedT && t < d) || !boundedT)) |
180 | { |
181 | ballPosition.x = Easings[easingX].func(t, 100.0f, 700.0f - 100.0f, d); |
182 | ballPosition.y = Easings[easingY].func(t, 100.0f, 400.0f - 100.0f, d); |
183 | t += 1.0f; |
184 | } |
185 | //---------------------------------------------------------------------------------- |
186 | |
187 | // Draw |
188 | //---------------------------------------------------------------------------------- |
189 | BeginDrawing(); |
190 | |
191 | ClearBackground(RAYWHITE); |
192 | |
193 | // Draw information text |
194 | DrawText(TextFormat("Easing x: %s" , Easings[easingX].name), 0, FONT_SIZE*2, FONT_SIZE, LIGHTGRAY); |
195 | DrawText(TextFormat("Easing y: %s" , Easings[easingY].name), 0, FONT_SIZE*3, FONT_SIZE, LIGHTGRAY); |
196 | DrawText(TextFormat("t (%c) = %.2f d = %.2f" , (boundedT == true)? 'b' : 'u', t, d), 0, FONT_SIZE*4, FONT_SIZE, LIGHTGRAY); |
197 | |
198 | // Draw instructions text |
199 | DrawText("Use ENTER to play or pause movement, use SPACE to restart" , 0, GetScreenHeight() - FONT_SIZE*2, FONT_SIZE, LIGHTGRAY); |
200 | DrawText("Use D and W or A and S keys to change duration" , 0, GetScreenHeight() - FONT_SIZE*3, FONT_SIZE, LIGHTGRAY); |
201 | DrawText("Use LEFT or RIGHT keys to choose easing for the x axis" , 0, GetScreenHeight() - FONT_SIZE*4, FONT_SIZE, LIGHTGRAY); |
202 | DrawText("Use UP or DOWN keys to choose easing for the y axis" , 0, GetScreenHeight() - FONT_SIZE*5, FONT_SIZE, LIGHTGRAY); |
203 | |
204 | // Draw ball |
205 | DrawCircleV(ballPosition, 16.0f, MAROON); |
206 | |
207 | EndDrawing(); |
208 | //---------------------------------------------------------------------------------- |
209 | } |
210 | |
211 | // De-Initialization |
212 | //-------------------------------------------------------------------------------------- |
213 | CloseWindow(); |
214 | //-------------------------------------------------------------------------------------- |
215 | |
216 | return 0; |
217 | } |
218 | |
219 | |
220 | // NoEase function, used when "no easing" is selected for any axis. It just ignores all parameters besides b. |
221 | static float NoEase(float t, float b, float c, float d) |
222 | { |
223 | float burn = t + b + c + d; // Hack to avoid compiler warning (about unused variables) |
224 | d += burn; |
225 | |
226 | return b; |
227 | } |