/*******************************************************************************************
							 | 
						|
								*
							 | 
						|
								*   raylib - sample game: arkanoid
							 | 
						|
								*
							 | 
						|
								*   Sample game Marc Palau and Ramon Santamaria
							 | 
						|
								*
							 | 
						|
								*   This game has been created using raylib v1.3 (www.raylib.com)
							 | 
						|
								*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
							 | 
						|
								*
							 | 
						|
								*   Copyright (c) 2015 Ramon Santamaria (@raysan5)
							 | 
						|
								*
							 | 
						|
								********************************************************************************************/
							 | 
						|
								
							 | 
						|
								#include "raylib.h"
							 | 
						|
								
							 | 
						|
								#include <stdio.h>
							 | 
						|
								#include <stdlib.h>
							 | 
						|
								#include <time.h>
							 | 
						|
								#include <math.h>
							 | 
						|
								
							 | 
						|
								#if defined(PLATFORM_WEB)
							 | 
						|
								    #include <emscripten/emscripten.h>
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								// Some Defines
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								#define PLAYER_MAX_LIFE         5
							 | 
						|
								#define LINES_OF_BRICKS         5
							 | 
						|
								#define BRICKS_PER_LINE        20
							 | 
						|
								
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								// Types and Structures Definition
							 | 
						|
								//----------------------------------------------------------------------------------
							 | 
						|
								typedef enum GameScreen { LOGO, TITLE, GAMEPLAY, ENDING } GameScreen;
							 | 
						|
								
							 | 
						|
								typedef struct Player {
							 | 
						|
								    Vector2 position;
							 | 
						|
								    Vector2 size;
							 | 
						|
								    int life;
							 | 
						|
								} Player;
							 | 
						|
								
							 | 
						|
								typedef struct Ball {
							 | 
						|
								    Vector2 position;
							 | 
						|
								    Vector2 speed;
							 | 
						|
								    int radius;
							 | 
						|
								    bool active;
							 | 
						|
								} Ball;
							 | 
						|
								
							 | 
						|
								typedef struct Brick {
							 | 
						|
								    Vector2 position;
							 | 
						|
								    bool active;
							 | 
						|
								} Brick;
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------------
							 | 
						|
								// Global Variables Declaration
							 | 
						|
								//------------------------------------------------------------------------------------
							 | 
						|
								static const int screenWidth = 800;
							 | 
						|
								static const int screenHeight = 450;
							 | 
						|
								
							 | 
						|
								static bool gameOver = false;
							 | 
						|
								static bool pause = false;
							 | 
						|
								
							 | 
						|
								static Player player = { 0 };
							 | 
						|
								static Ball ball = { 0 };
							 | 
						|
								static Brick brick[LINES_OF_BRICKS][BRICKS_PER_LINE] = { 0 };
							 | 
						|
								static Vector2 brickSize = { 0 };
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------------
							 | 
						|
								// Module Functions Declaration (local)
							 | 
						|
								//------------------------------------------------------------------------------------
							 | 
						|
								static void InitGame(void);         // Initialize game
							 | 
						|
								static void UpdateGame(void);       // Update game (one frame)
							 | 
						|
								static void DrawGame(void);         // Draw game (one frame)
							 | 
						|
								static void UnloadGame(void);       // Unload game
							 | 
						|
								static void UpdateDrawFrame(void);  // Update and Draw (one frame)
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------------
							 | 
						|
								// Program main entry point
							 | 
						|
								//------------------------------------------------------------------------------------
							 | 
						|
								int main(void)
							 | 
						|
								{
							 | 
						|
								    // Initialization (Note windowTitle is unused on Android)
							 | 
						|
								    //---------------------------------------------------------
							 | 
						|
								    InitWindow(screenWidth, screenHeight, "sample game: arkanoid");
							 | 
						|
								
							 | 
						|
								    InitGame();
							 | 
						|
								
							 | 
						|
								#if defined(PLATFORM_WEB)
							 | 
						|
								    emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
							 | 
						|
								#else
							 | 
						|
								    SetTargetFPS(60);
							 | 
						|
								    //--------------------------------------------------------------------------------------
							 | 
						|
								    
							 | 
						|
								    // Main game loop
							 | 
						|
								    while (!WindowShouldClose())    // Detect window close button or ESC key
							 | 
						|
								    {
							 | 
						|
								        // Update and Draw
							 | 
						|
								        //----------------------------------------------------------------------------------
							 | 
						|
								        UpdateDrawFrame();
							 | 
						|
								        //----------------------------------------------------------------------------------
							 | 
						|
								    }
							 | 
						|
								#endif
							 | 
						|
								    // De-Initialization
							 | 
						|
								    //--------------------------------------------------------------------------------------
							 | 
						|
								    UnloadGame();         // Unload loaded data (textures, sounds, models...)
							 | 
						|
								    
							 | 
						|
								    CloseWindow();        // Close window and OpenGL context
							 | 
						|
								    //--------------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								    return 0;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------------
							 | 
						|
								// Module Functions Definitions (local)
							 | 
						|
								//------------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								// Initialize game variables
							 | 
						|
								void InitGame(void)
							 | 
						|
								{
							 | 
						|
								    brickSize = (Vector2){ GetScreenWidth()/BRICKS_PER_LINE, 40 };
							 | 
						|
								
							 | 
						|
								    // Initialize player
							 | 
						|
								    player.position = (Vector2){ screenWidth/2, screenHeight*7/8 };
							 | 
						|
								    player.size = (Vector2){ screenWidth/10, 20 };
							 | 
						|
								    player.life = PLAYER_MAX_LIFE;
							 | 
						|
								    
							 | 
						|
								    // Initialize ball
							 | 
						|
								    ball.position = (Vector2){ screenWidth/2, screenHeight*7/8 - 30 };
							 | 
						|
								    ball.speed = (Vector2){ 0, 0 };
							 | 
						|
								    ball.radius = 7;
							 | 
						|
								    ball.active = false;
							 | 
						|
								    
							 | 
						|
								    // Initialize bricks
							 | 
						|
								    int initialDownPosition = 50;
							 | 
						|
								
							 | 
						|
								    for (int i = 0; i < LINES_OF_BRICKS; i++)
							 | 
						|
								    {
							 | 
						|
								        for (int j = 0; j < BRICKS_PER_LINE; j++)
							 | 
						|
								        {
							 | 
						|
								            brick[i][j].position = (Vector2){ j*brickSize.x + brickSize.x/2, i*brickSize.y + initialDownPosition };
							 | 
						|
								            brick[i][j].active = true;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Update game (one frame)
							 | 
						|
								void UpdateGame(void)
							 | 
						|
								{
							 | 
						|
								    if (!gameOver)
							 | 
						|
								    {
							 | 
						|
								        if (IsKeyPressed('P')) pause = !pause;
							 | 
						|
								
							 | 
						|
								        if (!pause)
							 | 
						|
								        {
							 | 
						|
								            // Player movement logic
							 | 
						|
								            if (IsKeyDown(KEY_LEFT)) player.position.x -= 5;
							 | 
						|
								            if ((player.position.x - player.size.x/2) <= 0) player.position.x = player.size.x/2;
							 | 
						|
								            if (IsKeyDown(KEY_RIGHT)) player.position.x += 5;
							 | 
						|
								            if ((player.position.x + player.size.x/2) >= screenWidth) player.position.x = screenWidth - player.size.x/2;
							 | 
						|
								
							 | 
						|
								            // Ball launching logic
							 | 
						|
								            if (!ball.active)
							 | 
						|
								            {
							 | 
						|
								                if (IsKeyPressed(KEY_SPACE))
							 | 
						|
								                {
							 | 
						|
								                    ball.active = true;
							 | 
						|
								                    ball.speed = (Vector2){ 0, -5 };
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            
							 | 
						|
								            // Ball movement logic
							 | 
						|
								            if (ball.active)
							 | 
						|
								            {
							 | 
						|
								                ball.position.x += ball.speed.x;
							 | 
						|
								                ball.position.y += ball.speed.y;
							 | 
						|
								            }
							 | 
						|
								            else
							 | 
						|
								            {
							 | 
						|
								                ball.position = (Vector2){ player.position.x, screenHeight*7/8 - 30 };
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Collision logic: ball vs walls 
							 | 
						|
								            if (((ball.position.x + ball.radius) >= screenWidth) || ((ball.position.x - ball.radius) <= 0)) ball.speed.x *= -1;
							 | 
						|
								            if ((ball.position.y - ball.radius) <= 0) ball.speed.y *= -1;
							 | 
						|
								            if ((ball.position.y + ball.radius) >= screenHeight)
							 | 
						|
								            {
							 | 
						|
								                ball.speed = (Vector2){ 0, 0 };
							 | 
						|
								                ball.active = false;
							 | 
						|
								
							 | 
						|
								                player.life--;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Collision logic: ball vs player
							 | 
						|
								            if (CheckCollisionCircleRec(ball.position, ball.radius,
							 | 
						|
								                (Rectangle){ player.position.x - player.size.x/2, player.position.y - player.size.y/2, player.size.x, player.size.y}))
							 | 
						|
								            {
							 | 
						|
								                if (ball.speed.y > 0)
							 | 
						|
								                {
							 | 
						|
								                    ball.speed.y *= -1;
							 | 
						|
								                    ball.speed.x = (ball.position.x - player.position.x)/(player.size.x/2)*5;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Collision logic: ball vs bricks
							 | 
						|
								            for (int i = 0; i < LINES_OF_BRICKS; i++)
							 | 
						|
								            {
							 | 
						|
								                for (int j = 0; j < BRICKS_PER_LINE; j++)
							 | 
						|
								                {
							 | 
						|
								                    if (brick[i][j].active)
							 | 
						|
								                    {
							 | 
						|
								                        // Hit below
							 | 
						|
								                        if (((ball.position.y - ball.radius) <= (brick[i][j].position.y + brickSize.y/2)) &&
							 | 
						|
								                            ((ball.position.y - ball.radius) > (brick[i][j].position.y + brickSize.y/2 + ball.speed.y)) &&
							 | 
						|
								                            ((fabs(ball.position.x - brick[i][j].position.x)) < (brickSize.x/2 + ball.radius*2/3)) && (ball.speed.y < 0))
							 | 
						|
								                        {
							 | 
						|
								                            brick[i][j].active = false;
							 | 
						|
								                            ball.speed.y *= -1;
							 | 
						|
								                        }
							 | 
						|
								                        // Hit above
							 | 
						|
								                        else if (((ball.position.y + ball.radius) >= (brick[i][j].position.y - brickSize.y/2)) &&
							 | 
						|
								                                ((ball.position.y + ball.radius) < (brick[i][j].position.y - brickSize.y/2 + ball.speed.y)) &&
							 | 
						|
								                                ((fabs(ball.position.x - brick[i][j].position.x)) < (brickSize.x/2 + ball.radius*2/3)) && (ball.speed.y > 0))
							 | 
						|
								                        {
							 | 
						|
								                            brick[i][j].active = false;
							 | 
						|
								                            ball.speed.y *= -1;
							 | 
						|
								                        }
							 | 
						|
								                        // Hit left
							 | 
						|
								                        else if (((ball.position.x + ball.radius) >= (brick[i][j].position.x - brickSize.x/2)) &&
							 | 
						|
								                                ((ball.position.x + ball.radius) < (brick[i][j].position.x - brickSize.x/2 + ball.speed.x)) &&
							 | 
						|
								                                ((fabs(ball.position.y - brick[i][j].position.y)) < (brickSize.y/2 + ball.radius*2/3)) && (ball.speed.x > 0))
							 | 
						|
								                        {
							 | 
						|
								                            brick[i][j].active = false;
							 | 
						|
								                            ball.speed.x *= -1;
							 | 
						|
								                        }
							 | 
						|
								                        // Hit right
							 | 
						|
								                        else if (((ball.position.x - ball.radius) <= (brick[i][j].position.x + brickSize.x/2)) &&
							 | 
						|
								                                ((ball.position.x - ball.radius) > (brick[i][j].position.x + brickSize.x/2 + ball.speed.x)) &&
							 | 
						|
								                                ((fabs(ball.position.y - brick[i][j].position.y)) < (brickSize.y/2 + ball.radius*2/3)) && (ball.speed.x < 0))
							 | 
						|
								                        {
							 | 
						|
								                            brick[i][j].active = false;
							 | 
						|
								                            ball.speed.x *= -1;
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Game over logic
							 | 
						|
								            if (player.life <= 0) gameOver = true;
							 | 
						|
								            else
							 | 
						|
								            {
							 | 
						|
								                gameOver = true;
							 | 
						|
								                
							 | 
						|
								                for (int i = 0; i < LINES_OF_BRICKS; i++)
							 | 
						|
								                {
							 | 
						|
								                    for (int j = 0; j < BRICKS_PER_LINE; j++)
							 | 
						|
								                    {
							 | 
						|
								                        if (brick[i][j].active) gameOver = false;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    else
							 | 
						|
								    {
							 | 
						|
								        if (IsKeyPressed(KEY_ENTER))
							 | 
						|
								        {
							 | 
						|
								            InitGame();
							 | 
						|
								            gameOver = false;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Draw game (one frame)
							 | 
						|
								void DrawGame(void)
							 | 
						|
								{
							 | 
						|
								    BeginDrawing();
							 | 
						|
								
							 | 
						|
								        ClearBackground(RAYWHITE);
							 | 
						|
								
							 | 
						|
								        if (!gameOver)
							 | 
						|
								        {
							 | 
						|
								            // Draw player bar
							 | 
						|
								            DrawRectangle(player.position.x - player.size.x/2, player.position.y - player.size.y/2, player.size.x, player.size.y, BLACK);
							 | 
						|
								
							 | 
						|
								            // Draw player lives
							 | 
						|
								            for (int i = 0; i < player.life; i++) DrawRectangle(20 + 40*i, screenHeight - 30, 35, 10, LIGHTGRAY);
							 | 
						|
								            
							 | 
						|
								            // Draw ball
							 | 
						|
								            DrawCircleV(ball.position, ball.radius, MAROON);
							 | 
						|
								            
							 | 
						|
								            // Draw bricks
							 | 
						|
								            for (int i = 0; i < LINES_OF_BRICKS; i++)
							 | 
						|
								            {
							 | 
						|
								                for (int j = 0; j < BRICKS_PER_LINE; j++)
							 | 
						|
								                {
							 | 
						|
								                    if (brick[i][j].active)
							 | 
						|
								                    {
							 | 
						|
								                        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);
							 | 
						|
								                        else DrawRectangle(brick[i][j].position.x - brickSize.x/2, brick[i][j].position.y - brickSize.y/2, brickSize.x, brickSize.y, DARKGRAY);
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            
							 | 
						|
								            if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, GRAY);
							 | 
						|
								        }
							 | 
						|
								        else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, GRAY);
							 | 
						|
								
							 | 
						|
								    EndDrawing();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Unload game variables
							 | 
						|
								void UnloadGame(void)
							 | 
						|
								{
							 | 
						|
								    // TODO: Unload all dynamic loaded data (textures, sounds, models...)
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Update and Draw (one frame)
							 | 
						|
								void UpdateDrawFrame(void)
							 | 
						|
								{
							 | 
						|
								    UpdateGame();
							 | 
						|
								    DrawGame();
							 | 
						|
								}
							 |