1 | /******************************************************************************************* |
2 | * |
3 | * raylib - sample game: gorilas |
4 | * |
5 | * Sample game Marc Palau and Ramon Santamaria |
6 | * |
7 | * This game has been created using raylib v1.3 (www.raylib.com) |
8 | * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) |
9 | * |
10 | * Copyright (c) 2015 Ramon Santamaria (@raysan5) |
11 | * |
12 | ********************************************************************************************/ |
13 | |
14 | #include "raylib.h" |
15 | |
16 | #include <stdio.h> |
17 | #include <stdlib.h> |
18 | #include <time.h> |
19 | #include <math.h> |
20 | |
21 | #if defined(PLATFORM_WEB) |
22 | #include <emscripten/emscripten.h> |
23 | #endif |
24 | |
25 | //---------------------------------------------------------------------------------- |
26 | // Some Defines |
27 | //---------------------------------------------------------------------------------- |
28 | #define MAX_BUILDINGS 15 |
29 | #define MAX_EXPLOSIONS 200 |
30 | #define MAX_PLAYERS 2 |
31 | |
32 | #define BUILDING_RELATIVE_ERROR 30 // Building size random range % |
33 | #define BUILDING_MIN_RELATIVE_HEIGHT 20 // Minimum height in % of the screenHeight |
34 | #define BUILDING_MAX_RELATIVE_HEIGHT 60 // Maximum height in % of the screenHeight |
35 | #define BUILDING_MIN_GRAYSCALE_COLOR 120 // Minimum gray color for the buildings |
36 | #define BUILDING_MAX_GRAYSCALE_COLOR 200 // Maximum gray color for the buildings |
37 | |
38 | #define MIN_PLAYER_POSITION 5 // Minimum x position % |
39 | #define MAX_PLAYER_POSITION 20 // Maximum x position % |
40 | |
41 | #define GRAVITY 9.81f |
42 | #define DELTA_FPS 60 |
43 | |
44 | //---------------------------------------------------------------------------------- |
45 | // Types and Structures Definition |
46 | //---------------------------------------------------------------------------------- |
47 | typedef struct Player { |
48 | Vector2 position; |
49 | Vector2 size; |
50 | |
51 | Vector2 aimingPoint; |
52 | int aimingAngle; |
53 | int aimingPower; |
54 | |
55 | Vector2 previousPoint; |
56 | int previousAngle; |
57 | int previousPower; |
58 | |
59 | Vector2 impactPoint; |
60 | |
61 | bool isLeftTeam; // This player belongs to the left or to the right team |
62 | bool isPlayer; // If is a player or an AI |
63 | bool isAlive; |
64 | } Player; |
65 | |
66 | typedef struct Building { |
67 | Rectangle rectangle; |
68 | Color color; |
69 | } Building; |
70 | |
71 | typedef struct Explosion { |
72 | Vector2 position; |
73 | int radius; |
74 | bool active; |
75 | } Explosion; |
76 | |
77 | typedef struct Ball { |
78 | Vector2 position; |
79 | Vector2 speed; |
80 | int radius; |
81 | bool active; |
82 | } Ball; |
83 | |
84 | //------------------------------------------------------------------------------------ |
85 | // Global Variables Declaration |
86 | //------------------------------------------------------------------------------------ |
87 | static const int screenWidth = 800; |
88 | static const int screenHeight = 450; |
89 | |
90 | static bool gameOver = false; |
91 | static bool pause = false; |
92 | |
93 | static Player player[MAX_PLAYERS] = { 0 }; |
94 | static Building building[MAX_BUILDINGS] = { 0 }; |
95 | static Explosion explosion[MAX_EXPLOSIONS] = { 0 }; |
96 | static Ball ball = { 0 }; |
97 | |
98 | static int playerTurn = 0; |
99 | static bool ballOnAir = false; |
100 | |
101 | //------------------------------------------------------------------------------------ |
102 | // Module Functions Declaration (local) |
103 | //------------------------------------------------------------------------------------ |
104 | static void InitGame(void); // Initialize game |
105 | static void UpdateGame(void); // Update game (one frame) |
106 | static void DrawGame(void); // Draw game (one frame) |
107 | static void UnloadGame(void); // Unload game |
108 | static void UpdateDrawFrame(void); // Update and Draw (one frame) |
109 | |
110 | // Additional module functions |
111 | static void InitBuildings(void); |
112 | static void InitPlayers(void); |
113 | static bool UpdatePlayer(int playerTurn); |
114 | static bool UpdateBall(int playerTurn); |
115 | |
116 | //------------------------------------------------------------------------------------ |
117 | // Program main entry point |
118 | //------------------------------------------------------------------------------------ |
119 | int main(void) |
120 | { |
121 | // Initialization (Note windowTitle is unused on Android) |
122 | //--------------------------------------------------------- |
123 | InitWindow(screenWidth, screenHeight, "sample game: gorilas" ); |
124 | |
125 | InitGame(); |
126 | |
127 | #if defined(PLATFORM_WEB) |
128 | emscripten_set_main_loop(UpdateDrawFrame, 0, 1); |
129 | #else |
130 | |
131 | SetTargetFPS(60); |
132 | //-------------------------------------------------------------------------------------- |
133 | |
134 | // Main game loop |
135 | while (!WindowShouldClose()) // Detect window close button or ESC key |
136 | { |
137 | // Update and Draw |
138 | //---------------------------------------------------------------------------------- |
139 | UpdateDrawFrame(); |
140 | //---------------------------------------------------------------------------------- |
141 | } |
142 | #endif |
143 | |
144 | // De-Initialization |
145 | //-------------------------------------------------------------------------------------- |
146 | UnloadGame(); // Unload loaded data (textures, sounds, models...) |
147 | |
148 | CloseWindow(); // Close window and OpenGL context |
149 | //-------------------------------------------------------------------------------------- |
150 | |
151 | return 0; |
152 | } |
153 | |
154 | //------------------------------------------------------------------------------------ |
155 | // Module Functions Definitions (local) |
156 | //------------------------------------------------------------------------------------ |
157 | |
158 | // Initialize game variables |
159 | void InitGame(void) |
160 | { |
161 | // Init shoot |
162 | ball.radius = 10; |
163 | ballOnAir = false; |
164 | ball.active = false; |
165 | |
166 | InitBuildings(); |
167 | InitPlayers(); |
168 | |
169 | // Init explosions |
170 | for (int i = 0; i < MAX_EXPLOSIONS; i++) |
171 | { |
172 | explosion[i].position = (Vector2){ 0.0f, 0.0f }; |
173 | explosion[i].radius = 30; |
174 | explosion[i].active = false; |
175 | } |
176 | } |
177 | |
178 | // Update game (one frame) |
179 | void UpdateGame(void) |
180 | { |
181 | if (!gameOver) |
182 | { |
183 | if (IsKeyPressed('P')) pause = !pause; |
184 | |
185 | if (!pause) |
186 | { |
187 | if (!ballOnAir) ballOnAir = UpdatePlayer(playerTurn); // If we are aiming |
188 | else |
189 | { |
190 | if (UpdateBall(playerTurn)) // If collision |
191 | { |
192 | // Game over logic |
193 | bool leftTeamAlive = false; |
194 | bool rightTeamAlive = false; |
195 | |
196 | for (int i = 0; i < MAX_PLAYERS; i++) |
197 | { |
198 | if (player[i].isAlive) |
199 | { |
200 | if (player[i].isLeftTeam) leftTeamAlive = true; |
201 | if (!player[i].isLeftTeam) rightTeamAlive = true; |
202 | } |
203 | } |
204 | |
205 | if (leftTeamAlive && rightTeamAlive) |
206 | { |
207 | ballOnAir = false; |
208 | ball.active = false; |
209 | |
210 | playerTurn++; |
211 | |
212 | if (playerTurn == MAX_PLAYERS) playerTurn = 0; |
213 | } |
214 | else |
215 | { |
216 | gameOver = true; |
217 | |
218 | // if (leftTeamAlive) left team wins |
219 | // if (rightTeamAlive) right team wins |
220 | } |
221 | } |
222 | } |
223 | } |
224 | } |
225 | else |
226 | { |
227 | if (IsKeyPressed(KEY_ENTER)) |
228 | { |
229 | InitGame(); |
230 | gameOver = false; |
231 | } |
232 | } |
233 | } |
234 | |
235 | // Draw game (one frame) |
236 | void DrawGame(void) |
237 | { |
238 | BeginDrawing(); |
239 | |
240 | ClearBackground(RAYWHITE); |
241 | |
242 | if (!gameOver) |
243 | { |
244 | // Draw buildings |
245 | for (int i = 0; i < MAX_BUILDINGS; i++) DrawRectangleRec(building[i].rectangle, building[i].color); |
246 | |
247 | // Draw explosions |
248 | for (int i = 0; i < MAX_EXPLOSIONS; i++) |
249 | { |
250 | if (explosion[i].active) DrawCircle(explosion[i].position.x, explosion[i].position.y, explosion[i].radius, RAYWHITE); |
251 | } |
252 | |
253 | // Draw players |
254 | for (int i = 0; i < MAX_PLAYERS; i++) |
255 | { |
256 | if (player[i].isAlive) |
257 | { |
258 | if (player[i].isLeftTeam) DrawRectangle(player[i].position.x - player[i].size.x/2, player[i].position.y - player[i].size.y/2, |
259 | player[i].size.x, player[i].size.y, BLUE); |
260 | else DrawRectangle(player[i].position.x - player[i].size.x/2, player[i].position.y - player[i].size.y/2, |
261 | player[i].size.x, player[i].size.y, RED); |
262 | } |
263 | } |
264 | |
265 | // Draw ball |
266 | if (ball.active) DrawCircle(ball.position.x, ball.position.y, ball.radius, MAROON); |
267 | |
268 | // Draw the angle and the power of the aim, and the previous ones |
269 | if (!ballOnAir) |
270 | { |
271 | // Draw shot information |
272 | /* |
273 | if (player[playerTurn].isLeftTeam) |
274 | { |
275 | DrawText(TextFormat("Previous Point %i, %i", (int)player[playerTurn].previousPoint.x, (int)player[playerTurn].previousPoint.y), 20, 20, 20, DARKBLUE); |
276 | DrawText(TextFormat("Previous Angle %i", player[playerTurn].previousAngle), 20, 50, 20, DARKBLUE); |
277 | DrawText(TextFormat("Previous Power %i", player[playerTurn].previousPower), 20, 80, 20, DARKBLUE); |
278 | DrawText(TextFormat("Aiming Point %i, %i", (int)player[playerTurn].aimingPoint.x, (int)player[playerTurn].aimingPoint.y), 20, 110, 20, DARKBLUE); |
279 | DrawText(TextFormat("Aiming Angle %i", player[playerTurn].aimingAngle), 20, 140, 20, DARKBLUE); |
280 | DrawText(TextFormat("Aiming Power %i", player[playerTurn].aimingPower), 20, 170, 20, DARKBLUE); |
281 | } |
282 | else |
283 | { |
284 | DrawText(TextFormat("Previous Point %i, %i", (int)player[playerTurn].previousPoint.x, (int)player[playerTurn].previousPoint.y), screenWidth*3/4, 20, 20, DARKBLUE); |
285 | DrawText(TextFormat("Previous Angle %i", player[playerTurn].previousAngle), screenWidth*3/4, 50, 20, DARKBLUE); |
286 | DrawText(TextFormat("Previous Power %i", player[playerTurn].previousPower), screenWidth*3/4, 80, 20, DARKBLUE); |
287 | DrawText(TextFormat("Aiming Point %i, %i", (int)player[playerTurn].aimingPoint.x, (int)player[playerTurn].aimingPoint.y), screenWidth*3/4, 110, 20, DARKBLUE); |
288 | DrawText(TextFormat("Aiming Angle %i", player[playerTurn].aimingAngle), screenWidth*3/4, 140, 20, DARKBLUE); |
289 | DrawText(TextFormat("Aiming Power %i", player[playerTurn].aimingPower), screenWidth*3/4, 170, 20, DARKBLUE); |
290 | } |
291 | */ |
292 | |
293 | // Draw aim |
294 | if (player[playerTurn].isLeftTeam) |
295 | { |
296 | // Previous aiming |
297 | DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 }, |
298 | (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 }, |
299 | player[playerTurn].previousPoint, GRAY); |
300 | |
301 | // Actual aiming |
302 | DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 }, |
303 | (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 }, |
304 | player[playerTurn].aimingPoint, DARKBLUE); |
305 | } |
306 | else |
307 | { |
308 | // Previous aiming |
309 | DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 }, |
310 | (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 }, |
311 | player[playerTurn].previousPoint, GRAY); |
312 | |
313 | // Actual aiming |
314 | DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 }, |
315 | (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 }, |
316 | player[playerTurn].aimingPoint, MAROON); |
317 | } |
318 | } |
319 | |
320 | if (pause) DrawText("GAME PAUSED" , screenWidth/2 - MeasureText("GAME PAUSED" , 40)/2, screenHeight/2 - 40, 40, GRAY); |
321 | } |
322 | else DrawText("PRESS [ENTER] TO PLAY AGAIN" , GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN" , 20)/2, GetScreenHeight()/2 - 50, 20, GRAY); |
323 | |
324 | EndDrawing(); |
325 | } |
326 | |
327 | // Unload game variables |
328 | void UnloadGame(void) |
329 | { |
330 | // TODO: Unload all dynamic loaded data (textures, sounds, models...) |
331 | } |
332 | |
333 | // Update and Draw (one frame) |
334 | void UpdateDrawFrame(void) |
335 | { |
336 | UpdateGame(); |
337 | DrawGame(); |
338 | } |
339 | |
340 | //-------------------------------------------------------------------------------------- |
341 | // Additional module functions |
342 | //-------------------------------------------------------------------------------------- |
343 | static void InitBuildings(void) |
344 | { |
345 | // Horizontal generation |
346 | int currentWidth = 0; |
347 | |
348 | // We make sure the absolute error randomly generated for each building, has as a minimum value the screenWidth. |
349 | // This way all the screen will be filled with buildings. Each building will have a different, random width. |
350 | |
351 | float relativeWidth = 100/(100 - BUILDING_RELATIVE_ERROR); |
352 | float buildingWidthMean = (screenWidth*relativeWidth/MAX_BUILDINGS) + 1; // We add one to make sure we will cover the whole screen. |
353 | |
354 | // Vertical generation |
355 | int currentHeighth = 0; |
356 | int grayLevel; |
357 | |
358 | // Creation |
359 | for (int i = 0; i < MAX_BUILDINGS; i++) |
360 | { |
361 | // Horizontal |
362 | building[i].rectangle.x = currentWidth; |
363 | building[i].rectangle.width = GetRandomValue(buildingWidthMean*(100 - BUILDING_RELATIVE_ERROR/2)/100 + 1, buildingWidthMean*(100 + BUILDING_RELATIVE_ERROR)/100); |
364 | |
365 | currentWidth += building[i].rectangle.width; |
366 | |
367 | // Vertical |
368 | currentHeighth = GetRandomValue(BUILDING_MIN_RELATIVE_HEIGHT, BUILDING_MAX_RELATIVE_HEIGHT); |
369 | building[i].rectangle.y = screenHeight - (screenHeight*currentHeighth/100); |
370 | building[i].rectangle.height = screenHeight*currentHeighth/100 + 1; |
371 | |
372 | // Color |
373 | grayLevel = GetRandomValue(BUILDING_MIN_GRAYSCALE_COLOR, BUILDING_MAX_GRAYSCALE_COLOR); |
374 | building[i].color = (Color){ grayLevel, grayLevel, grayLevel, 255 }; |
375 | } |
376 | } |
377 | |
378 | static void InitPlayers(void) |
379 | { |
380 | for (int i = 0; i < MAX_PLAYERS; i++) |
381 | { |
382 | player[i].isAlive = true; |
383 | |
384 | // Decide the team of this player |
385 | if (i % 2 == 0) player[i].isLeftTeam = true; |
386 | else player[i].isLeftTeam = false; |
387 | |
388 | // Now there is no AI |
389 | player[i].isPlayer = true; |
390 | |
391 | // Set size, by default by now |
392 | player[i].size = (Vector2){ 40, 40 }; |
393 | |
394 | // Set position |
395 | if (player[i].isLeftTeam) player[i].position.x = GetRandomValue(screenWidth*MIN_PLAYER_POSITION/100, screenWidth*MAX_PLAYER_POSITION/100); |
396 | else player[i].position.x = screenWidth - GetRandomValue(screenWidth*MIN_PLAYER_POSITION/100, screenWidth*MAX_PLAYER_POSITION/100); |
397 | |
398 | for (int j = 0; j < MAX_BUILDINGS; j++) |
399 | { |
400 | if (building[j].rectangle.x > player[i].position.x) |
401 | { |
402 | // Set the player in the center of the building |
403 | player[i].position.x = building[j-1].rectangle.x + building[j-1].rectangle.width/2; |
404 | // Set the player at the top of the building |
405 | player[i].position.y = building[j-1].rectangle.y - player[i].size.y/2; |
406 | break; |
407 | } |
408 | } |
409 | |
410 | // Set statistics to 0 |
411 | player[i].aimingPoint = player[i].position; |
412 | player[i].previousAngle = 0; |
413 | player[i].previousPower = 0; |
414 | player[i].previousPoint = player[i].position; |
415 | player[i].aimingAngle = 0; |
416 | player[i].aimingPower = 0; |
417 | |
418 | player[i].impactPoint = (Vector2){ -100, -100 }; |
419 | } |
420 | } |
421 | |
422 | static bool UpdatePlayer(int playerTurn) |
423 | { |
424 | // If we are aiming at the firing quadrant, we calculate the angle |
425 | if (GetMousePosition().y <= player[playerTurn].position.y) |
426 | { |
427 | // Left team |
428 | if (player[playerTurn].isLeftTeam && GetMousePosition().x >= player[playerTurn].position.x) |
429 | { |
430 | // Distance (calculating the fire power) |
431 | player[playerTurn].aimingPower = sqrt(pow(player[playerTurn].position.x - GetMousePosition().x, 2) + pow(player[playerTurn].position.y - GetMousePosition().y, 2)); |
432 | // Calculates the angle via arcsin |
433 | player[playerTurn].aimingAngle = asin((player[playerTurn].position.y - GetMousePosition().y)/player[playerTurn].aimingPower)*RAD2DEG; |
434 | // Point of the screen we are aiming at |
435 | player[playerTurn].aimingPoint = GetMousePosition(); |
436 | |
437 | // Ball fired |
438 | if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) |
439 | { |
440 | player[playerTurn].previousPoint = player[playerTurn].aimingPoint; |
441 | player[playerTurn].previousPower = player[playerTurn].aimingPower; |
442 | player[playerTurn].previousAngle = player[playerTurn].aimingAngle; |
443 | ball.position = player[playerTurn].position; |
444 | |
445 | return true; |
446 | } |
447 | } |
448 | // Right team |
449 | else if (!player[playerTurn].isLeftTeam && GetMousePosition().x <= player[playerTurn].position.x) |
450 | { |
451 | // Distance (calculating the fire power) |
452 | player[playerTurn].aimingPower = sqrt(pow(player[playerTurn].position.x - GetMousePosition().x, 2) + pow(player[playerTurn].position.y - GetMousePosition().y, 2)); |
453 | // Calculates the angle via arcsin |
454 | player[playerTurn].aimingAngle = asin((player[playerTurn].position.y - GetMousePosition().y)/player[playerTurn].aimingPower)*RAD2DEG; |
455 | // Point of the screen we are aiming at |
456 | player[playerTurn].aimingPoint = GetMousePosition(); |
457 | |
458 | // Ball fired |
459 | if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) |
460 | { |
461 | player[playerTurn].previousPoint = player[playerTurn].aimingPoint; |
462 | player[playerTurn].previousPower = player[playerTurn].aimingPower; |
463 | player[playerTurn].previousAngle = player[playerTurn].aimingAngle; |
464 | ball.position = player[playerTurn].position; |
465 | |
466 | return true; |
467 | } |
468 | } |
469 | else |
470 | { |
471 | player[playerTurn].aimingPoint = player[playerTurn].position; |
472 | player[playerTurn].aimingPower = 0; |
473 | player[playerTurn].aimingAngle = 0; |
474 | } |
475 | } |
476 | else |
477 | { |
478 | player[playerTurn].aimingPoint = player[playerTurn].position; |
479 | player[playerTurn].aimingPower = 0; |
480 | player[playerTurn].aimingAngle = 0; |
481 | } |
482 | |
483 | return false; |
484 | } |
485 | |
486 | static bool UpdateBall(int playerTurn) |
487 | { |
488 | static int explosionNumber = 0; |
489 | |
490 | // Activate ball |
491 | if (!ball.active) |
492 | { |
493 | if (player[playerTurn].isLeftTeam) |
494 | { |
495 | ball.speed.x = cos(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS; |
496 | ball.speed.y = -sin(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS; |
497 | ball.active = true; |
498 | } |
499 | else |
500 | { |
501 | ball.speed.x = -cos(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS; |
502 | ball.speed.y = -sin(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS; |
503 | ball.active = true; |
504 | } |
505 | } |
506 | |
507 | ball.position.x += ball.speed.x; |
508 | ball.position.y += ball.speed.y; |
509 | ball.speed.y += GRAVITY/DELTA_FPS; |
510 | |
511 | // Collision |
512 | if (ball.position.x + ball.radius < 0) return true; |
513 | else if (ball.position.x - ball.radius > screenWidth) return true; |
514 | else |
515 | { |
516 | // Player collision |
517 | for (int i = 0; i < MAX_PLAYERS; i++) |
518 | { |
519 | if (CheckCollisionCircleRec(ball.position, ball.radius, (Rectangle){ player[i].position.x - player[i].size.x/2, player[i].position.y - player[i].size.y/2, |
520 | player[i].size.x, player[i].size.y })) |
521 | { |
522 | // We can't hit ourselves |
523 | if (i == playerTurn) return false; |
524 | else |
525 | { |
526 | // We set the impact point |
527 | player[playerTurn].impactPoint.x = ball.position.x; |
528 | player[playerTurn].impactPoint.y = ball.position.y + ball.radius; |
529 | |
530 | // We destroy the player |
531 | player[i].isAlive = false; |
532 | return true; |
533 | } |
534 | } |
535 | } |
536 | |
537 | // Building collision |
538 | // NOTE: We only check building collision if we are not inside an explosion |
539 | for (int i = 0; i < MAX_BUILDINGS; i++) |
540 | { |
541 | if (CheckCollisionCircles(ball.position, ball.radius, explosion[i].position, explosion[i].radius - ball.radius)) |
542 | { |
543 | return false; |
544 | } |
545 | } |
546 | |
547 | for (int i = 0; i < MAX_BUILDINGS; i++) |
548 | { |
549 | if (CheckCollisionCircleRec(ball.position, ball.radius, building[i].rectangle)) |
550 | { |
551 | // We set the impact point |
552 | player[playerTurn].impactPoint.x = ball.position.x; |
553 | player[playerTurn].impactPoint.y = ball.position.y + ball.radius; |
554 | |
555 | // We create an explosion |
556 | explosion[explosionNumber].position = player[playerTurn].impactPoint; |
557 | explosion[explosionNumber].active = true; |
558 | explosionNumber++; |
559 | |
560 | return true; |
561 | } |
562 | } |
563 | } |
564 | |
565 | return false; |
566 | } |
567 | |