1/*******************************************************************************************
2*
3* raylib - sample game: arkanoid
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 PLAYER_MAX_LIFE 5
29#define LINES_OF_BRICKS 5
30#define BRICKS_PER_LINE 20
31
32//----------------------------------------------------------------------------------
33// Types and Structures Definition
34//----------------------------------------------------------------------------------
35typedef enum GameScreen { , TITLE, GAMEPLAY, ENDING } GameScreen;
36
37typedef struct Player {
38 Vector2 position;
39 Vector2 size;
40 int life;
41} Player;
42
43typedef struct Ball {
44 Vector2 position;
45 Vector2 speed;
46 int radius;
47 bool active;
48} Ball;
49
50typedef struct Brick {
51 Vector2 position;
52 bool active;
53} Brick;
54
55//------------------------------------------------------------------------------------
56// Global Variables Declaration
57//------------------------------------------------------------------------------------
58static const int screenWidth = 800;
59static const int screenHeight = 450;
60
61static bool gameOver = false;
62static bool pause = false;
63
64static Player player = { 0 };
65static Ball ball = { 0 };
66static Brick brick[LINES_OF_BRICKS][BRICKS_PER_LINE] = { 0 };
67static Vector2 brickSize = { 0 };
68
69//------------------------------------------------------------------------------------
70// Module Functions Declaration (local)
71//------------------------------------------------------------------------------------
72static void InitGame(void); // Initialize game
73static void UpdateGame(void); // Update game (one frame)
74static void DrawGame(void); // Draw game (one frame)
75static void UnloadGame(void); // Unload game
76static void UpdateDrawFrame(void); // Update and Draw (one frame)
77
78//------------------------------------------------------------------------------------
79// Program main entry point
80//------------------------------------------------------------------------------------
81int main(void)
82{
83 // Initialization (Note windowTitle is unused on Android)
84 //---------------------------------------------------------
85 InitWindow(screenWidth, screenHeight, "sample game: arkanoid");
86
87 InitGame();
88
89#if defined(PLATFORM_WEB)
90 emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
91#else
92 SetTargetFPS(60);
93 //--------------------------------------------------------------------------------------
94
95 // Main game loop
96 while (!WindowShouldClose()) // Detect window close button or ESC key
97 {
98 // Update and Draw
99 //----------------------------------------------------------------------------------
100 UpdateDrawFrame();
101 //----------------------------------------------------------------------------------
102 }
103#endif
104 // De-Initialization
105 //--------------------------------------------------------------------------------------
106 UnloadGame(); // Unload loaded data (textures, sounds, models...)
107
108 CloseWindow(); // Close window and OpenGL context
109 //--------------------------------------------------------------------------------------
110
111 return 0;
112}
113
114//------------------------------------------------------------------------------------
115// Module Functions Definitions (local)
116//------------------------------------------------------------------------------------
117
118// Initialize game variables
119void InitGame(void)
120{
121 brickSize = (Vector2){ GetScreenWidth()/BRICKS_PER_LINE, 40 };
122
123 // Initialize player
124 player.position = (Vector2){ screenWidth/2, screenHeight*7/8 };
125 player.size = (Vector2){ screenWidth/10, 20 };
126 player.life = PLAYER_MAX_LIFE;
127
128 // Initialize ball
129 ball.position = (Vector2){ screenWidth/2, screenHeight*7/8 - 30 };
130 ball.speed = (Vector2){ 0, 0 };
131 ball.radius = 7;
132 ball.active = false;
133
134 // Initialize bricks
135 int initialDownPosition = 50;
136
137 for (int i = 0; i < LINES_OF_BRICKS; i++)
138 {
139 for (int j = 0; j < BRICKS_PER_LINE; j++)
140 {
141 brick[i][j].position = (Vector2){ j*brickSize.x + brickSize.x/2, i*brickSize.y + initialDownPosition };
142 brick[i][j].active = true;
143 }
144 }
145}
146
147// Update game (one frame)
148void UpdateGame(void)
149{
150 if (!gameOver)
151 {
152 if (IsKeyPressed('P')) pause = !pause;
153
154 if (!pause)
155 {
156 // Player movement logic
157 if (IsKeyDown(KEY_LEFT)) player.position.x -= 5;
158 if ((player.position.x - player.size.x/2) <= 0) player.position.x = player.size.x/2;
159 if (IsKeyDown(KEY_RIGHT)) player.position.x += 5;
160 if ((player.position.x + player.size.x/2) >= screenWidth) player.position.x = screenWidth - player.size.x/2;
161
162 // Ball launching logic
163 if (!ball.active)
164 {
165 if (IsKeyPressed(KEY_SPACE))
166 {
167 ball.active = true;
168 ball.speed = (Vector2){ 0, -5 };
169 }
170 }
171
172 // Ball movement logic
173 if (ball.active)
174 {
175 ball.position.x += ball.speed.x;
176 ball.position.y += ball.speed.y;
177 }
178 else
179 {
180 ball.position = (Vector2){ player.position.x, screenHeight*7/8 - 30 };
181 }
182
183 // Collision logic: ball vs walls
184 if (((ball.position.x + ball.radius) >= screenWidth) || ((ball.position.x - ball.radius) <= 0)) ball.speed.x *= -1;
185 if ((ball.position.y - ball.radius) <= 0) ball.speed.y *= -1;
186 if ((ball.position.y + ball.radius) >= screenHeight)
187 {
188 ball.speed = (Vector2){ 0, 0 };
189 ball.active = false;
190
191 player.life--;
192 }
193
194 // Collision logic: ball vs player
195 if (CheckCollisionCircleRec(ball.position, ball.radius,
196 (Rectangle){ player.position.x - player.size.x/2, player.position.y - player.size.y/2, player.size.x, player.size.y}))
197 {
198 if (ball.speed.y > 0)
199 {
200 ball.speed.y *= -1;
201 ball.speed.x = (ball.position.x - player.position.x)/(player.size.x/2)*5;
202 }
203 }
204
205 // Collision logic: ball vs bricks
206 for (int i = 0; i < LINES_OF_BRICKS; i++)
207 {
208 for (int j = 0; j < BRICKS_PER_LINE; j++)
209 {
210 if (brick[i][j].active)
211 {
212 // Hit below
213 if (((ball.position.y - ball.radius) <= (brick[i][j].position.y + brickSize.y/2)) &&
214 ((ball.position.y - ball.radius) > (brick[i][j].position.y + brickSize.y/2 + ball.speed.y)) &&
215 ((fabs(ball.position.x - brick[i][j].position.x)) < (brickSize.x/2 + ball.radius*2/3)) && (ball.speed.y < 0))
216 {
217 brick[i][j].active = false;
218 ball.speed.y *= -1;
219 }
220 // Hit above
221 else if (((ball.position.y + ball.radius) >= (brick[i][j].position.y - brickSize.y/2)) &&
222 ((ball.position.y + ball.radius) < (brick[i][j].position.y - brickSize.y/2 + ball.speed.y)) &&
223 ((fabs(ball.position.x - brick[i][j].position.x)) < (brickSize.x/2 + ball.radius*2/3)) && (ball.speed.y > 0))
224 {
225 brick[i][j].active = false;
226 ball.speed.y *= -1;
227 }
228 // Hit left
229 else if (((ball.position.x + ball.radius) >= (brick[i][j].position.x - brickSize.x/2)) &&
230 ((ball.position.x + ball.radius) < (brick[i][j].position.x - brickSize.x/2 + ball.speed.x)) &&
231 ((fabs(ball.position.y - brick[i][j].position.y)) < (brickSize.y/2 + ball.radius*2/3)) && (ball.speed.x > 0))
232 {
233 brick[i][j].active = false;
234 ball.speed.x *= -1;
235 }
236 // Hit right
237 else if (((ball.position.x - ball.radius) <= (brick[i][j].position.x + brickSize.x/2)) &&
238 ((ball.position.x - ball.radius) > (brick[i][j].position.x + brickSize.x/2 + ball.speed.x)) &&
239 ((fabs(ball.position.y - brick[i][j].position.y)) < (brickSize.y/2 + ball.radius*2/3)) && (ball.speed.x < 0))
240 {
241 brick[i][j].active = false;
242 ball.speed.x *= -1;
243 }
244 }
245 }
246 }
247
248 // Game over logic
249 if (player.life <= 0) gameOver = true;
250 else
251 {
252 gameOver = true;
253
254 for (int i = 0; i < LINES_OF_BRICKS; i++)
255 {
256 for (int j = 0; j < BRICKS_PER_LINE; j++)
257 {
258 if (brick[i][j].active) gameOver = false;
259 }
260 }
261 }
262 }
263 }
264 else
265 {
266 if (IsKeyPressed(KEY_ENTER))
267 {
268 InitGame();
269 gameOver = false;
270 }
271 }
272}
273
274// Draw game (one frame)
275void DrawGame(void)
276{
277 BeginDrawing();
278
279 ClearBackground(RAYWHITE);
280
281 if (!gameOver)
282 {
283 // Draw player bar
284 DrawRectangle(player.position.x - player.size.x/2, player.position.y - player.size.y/2, player.size.x, player.size.y, BLACK);
285
286 // Draw player lives
287 for (int i = 0; i < player.life; i++) DrawRectangle(20 + 40*i, screenHeight - 30, 35, 10, LIGHTGRAY);
288
289 // Draw ball
290 DrawCircleV(ball.position, ball.radius, MAROON);
291
292 // Draw bricks
293 for (int i = 0; i < LINES_OF_BRICKS; i++)
294 {
295 for (int j = 0; j < BRICKS_PER_LINE; j++)
296 {
297 if (brick[i][j].active)
298 {
299 if ((i + j) % 2 == 0) DrawRectangle(brick[i][j].position.x - brickSize.x/2, brick[i][j].position.y - brickSize.y/2, brickSize.x, brickSize.y, GRAY);
300 else DrawRectangle(brick[i][j].position.x - brickSize.x/2, brick[i][j].position.y - brickSize.y/2, brickSize.x, brickSize.y, DARKGRAY);
301 }
302 }
303 }
304
305 if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY);
306 }
307 else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY);
308
309 EndDrawing();
310}
311
312// Unload game variables
313void UnloadGame(void)
314{
315 // TODO: Unload all dynamic loaded data (textures, sounds, models...)
316}
317
318// Update and Draw (one frame)
319void UpdateDrawFrame(void)
320{
321 UpdateGame();
322 DrawGame();
323}
324