aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay <raysan5@gmail.com>2016-01-29 07:26:06 -0800
committerRay <raysan5@gmail.com>2016-01-29 07:26:06 -0800
commit708e8c558cb843b5e4b071bc2b99102533bafaea (patch)
tree83561a8bf0b640c565a684c7a2b1ec80f490c044
parent4ec0ac89cda482031c393425381a2627a9468f09 (diff)
downloadraylib-708e8c558cb843b5e4b071bc2b99102533bafaea.tar.gz
raylib-708e8c558cb843b5e4b071bc2b99102533bafaea.zip
Added a bunch of sample games
Those games have been developed by students and ported to a common base template. Some of them still require some review to be consistent with each other (formatting, variables naming, code structure...)
-rw-r--r--games/samples/arkanoid.c349
-rw-r--r--games/samples/asteroids.c596
-rw-r--r--games/samples/asteroids_survival.c395
-rw-r--r--games/samples/floppy.c246
-rw-r--r--games/samples/gold_fever.c293
-rw-r--r--games/samples/gorilas.c571
-rw-r--r--games/samples/missile_commander.c539
-rw-r--r--games/samples/pang.c692
-rw-r--r--games/samples/snake.c293
-rw-r--r--games/samples/space_invaders.c407
-rw-r--r--games/samples/tetris.c835
11 files changed, 5216 insertions, 0 deletions
diff --git a/games/samples/arkanoid.c b/games/samples/arkanoid.c
new file mode 100644
index 00000000..f10f9383
--- /dev/null
+++ b/games/samples/arkanoid.c
@@ -0,0 +1,349 @@
+/*******************************************************************************************
+*
+* 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 int screenWidth = 800;
+static int screenHeight = 450;
+
+static int framesCounter;
+static bool gameOver;
+static bool pause;
+
+static Player player;
+static Ball ball;
+static Brick brick[LINES_OF_BRICKS][BRICKS_PER_LINE];
+static Vector2 brickSize;
+
+//------------------------------------------------------------------------------------
+// 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)
+
+// Additional module functions
+static void UpdateBall(void);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#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
+ 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;
+
+ // Launch ball
+ if (!ball.active)
+ {
+ if (IsKeyPressed(KEY_SPACE))
+ {
+ ball.active = true;
+ ball.speed = (Vector2){ 0, -5 };
+ }
+ }
+
+ UpdateBall();
+
+ // 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();
+}
+
+//--------------------------------------------------------------------------------------
+// Additional module functions
+//--------------------------------------------------------------------------------------
+static void UpdateBall()
+{
+ // Update position
+ 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 };
+ }
+
+ // Bounce in x
+ if (((ball.position.x + ball.radius) >= screenWidth) || ((ball.position.x - ball.radius) <= 0)) ball.speed.x *= -1;
+
+ // Bounce in y
+ if ((ball.position.y - ball.radius) <= 0) ball.speed.y *= -1;
+
+ // Ball reaches bottom of the screen
+ 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;
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/games/samples/asteroids.c b/games/samples/asteroids.c
new file mode 100644
index 00000000..676b0154
--- /dev/null
+++ b/games/samples/asteroids.c
@@ -0,0 +1,596 @@
+/*******************************************************************************************
+*
+* raylib - sample game: asteroids
+*
+* Sample game developed by Ian Eito, Albert Martos 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 <math.h>
+
+#if defined(PLATFORM_WEB)
+ #include <emscripten/emscripten.h>
+#endif
+
+//----------------------------------------------------------------------------------
+// Some Defines
+//----------------------------------------------------------------------------------
+#define MAX_SPEED 6
+#define METEORS_SPEED 2
+#define NUM_SHOOTS 10
+#define NUM_BIG_METEORS 4
+#define NUM_MEDIUM_METEORS 8
+#define NUM_SMALL_METEORS 16
+#define SHIP_BASE_SIZE 20.0f
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+
+typedef struct Player {
+ Vector2 position;
+ Vector2 speed;
+ float acceleration;
+ float rotation;
+ Vector3 collider;
+ Color color;
+} Player;
+
+typedef struct Shoot {
+ Vector2 position;
+ Vector2 speed;
+ float radius;
+ float rotation;
+ int lifeSpawn;
+ bool active;
+ Color color;
+} Shoot;
+
+typedef struct BigMeteor {
+ Vector2 position;
+ Vector2 speed;
+ float radius;
+ bool active;
+ Color color;
+} BigMeteor;
+
+typedef struct MediumMeteor {
+ Vector2 position;
+ Vector2 speed;
+ float radius;
+ bool active;
+ Color color;
+} MediumMeteor;
+
+typedef struct SmallMeteor {
+ Vector2 position;
+ Vector2 speed;
+ float radius;
+ bool active;
+ Color color;
+} SmallMeteor;
+
+//------------------------------------------------------------------------------------
+// Global Variables Declaration
+//------------------------------------------------------------------------------------
+static int screenWidth = 800;
+static int screenHeight = 450;
+
+static int framesCounter;
+static bool gameOver;
+static bool pause;
+static bool victory;
+
+// NOTE: Defined triangle is isosceles with common angles of 70 degrees.
+static float shipHeight;
+
+static Player player;
+static Shoot shoot[NUM_SHOOTS];
+static BigMeteor bigMeteor[NUM_BIG_METEORS];
+static MediumMeteor mediumMeteor[NUM_MEDIUM_METEORS];
+static SmallMeteor smallMeteor[NUM_SMALL_METEORS];
+
+static int countMediumMeteors;
+static int countSmallMeteors;
+static int meteorsDestroyed;
+
+//------------------------------------------------------------------------------------
+// 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)
+
+static void InitShoot(Shoot shoot);
+static void DrawSpaceship(Vector2 position, float rotation, Color color);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "sample game: asteroids");
+
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#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)
+{
+ int posx, posy;
+ int velx, vely;
+ bool correctRange = false;
+ victory = false;
+ pause = false;
+
+ shipHeight = (SHIP_BASE_SIZE/2)/tanf(20*DEG2RAD);
+
+ // Initialization player
+ player.position = (Vector2){screenWidth/2, screenHeight/2 - shipHeight/2};
+ player.speed = (Vector2){0, 0};
+ player.acceleration = 0;
+ player.rotation = 0;
+ player.collider = (Vector3){player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight/2.5f), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight/2.5f), 12};
+ player.color = LIGHTGRAY;
+
+ meteorsDestroyed = 0;
+
+ //InitShoot(&shoot);
+
+ // Initialization shoot
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ shoot[i].position = (Vector2){0, 0};
+ shoot[i].speed = (Vector2){0, 0};
+ shoot[i].radius = 2;
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ shoot[i].color = WHITE;
+ }
+
+ for (int i = 0; i < NUM_BIG_METEORS; i++)
+ {
+ posx = GetRandomValue(0, screenWidth);
+
+ while(!correctRange)
+ {
+ if (posx > screenWidth/2 - 150 && posx < screenWidth/2 + 150) posx = GetRandomValue(0, screenWidth);
+ else correctRange = true;
+ }
+
+ correctRange = false;
+
+ posy = GetRandomValue(0, screenHeight);
+
+ while(!correctRange)
+ {
+ if (posy > screenHeight/2 - 150 && posy < screenHeight/2 + 150) posy = GetRandomValue(0, screenHeight);
+ else correctRange = true;
+ }
+
+ bigMeteor[i].position = (Vector2){posx, posy};
+
+ correctRange = false;
+ velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+
+ while(!correctRange)
+ {
+ if (velx == 0 && vely == 0)
+ {
+ velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ }
+ else correctRange = true;
+ }
+
+ bigMeteor[i].speed = (Vector2){velx, vely};
+ bigMeteor[i].radius = 40;
+ bigMeteor[i].active = true;
+ bigMeteor[i].color = BLUE;
+ }
+
+ for (int i = 0; i < NUM_MEDIUM_METEORS; i++)
+ {
+ mediumMeteor[i].position = (Vector2){-100, -100};
+ mediumMeteor[i].speed = (Vector2){0,0};
+ mediumMeteor[i].radius = 20;
+ mediumMeteor[i].active = false;
+ mediumMeteor[i].color = BLUE;
+ }
+
+ for (int i = 0; i < NUM_SMALL_METEORS; i++)
+ {
+ smallMeteor[i].position = (Vector2){-100, -100};
+ smallMeteor[i].speed = (Vector2){0,0};
+ smallMeteor[i].radius = 10;
+ smallMeteor[i].active = false;
+ smallMeteor[i].color = BLUE;
+ }
+
+ countMediumMeteors = 0;
+ countSmallMeteors = 0;
+}
+
+// Update game (one frame)
+void UpdateGame(void)
+{
+ if (!gameOver)
+ {
+ if (IsKeyPressed('P')) pause = !pause;
+
+ if (!pause)
+ {
+ // Player logic
+
+ // Rotation
+ if (IsKeyDown(KEY_LEFT)) player.rotation -= 5;
+ if (IsKeyDown(KEY_RIGHT)) player.rotation += 5;
+
+ // Speed
+ player.speed.x = sin(player.rotation*DEG2RAD)*MAX_SPEED;
+ player.speed.y = cos(player.rotation*DEG2RAD)*MAX_SPEED;
+
+ // Controller
+ if (IsKeyDown(KEY_UP))
+ {
+ if (player.acceleration < 1) player.acceleration += 0.04f;
+ }
+ else
+ {
+ if (player.acceleration > 0) player.acceleration -= 0.02f;
+ else if (player.acceleration < 0) player.acceleration = 0;
+ }
+ if (IsKeyDown(KEY_DOWN))
+ {
+ if (player.acceleration > 0) player.acceleration -= 0.04f;
+ else if (player.acceleration < 0) player.acceleration = 0;
+ }
+
+ // Movement
+ player.position.x += (player.speed.x*player.acceleration);
+ player.position.y -= (player.speed.y*player.acceleration);
+
+ // Wall behaviour for player
+ if (player.position.x > screenWidth + shipHeight) player.position.x = -(shipHeight);
+ else if (player.position.x < -(shipHeight)) player.position.x = screenWidth + shipHeight;
+ if (player.position.y > (screenHeight + shipHeight)) player.position.y = -(shipHeight);
+ else if (player.position.y < -(shipHeight)) player.position.y = screenHeight + shipHeight;
+
+ // Activation of shoot
+ if (IsKeyPressed(KEY_SPACE))
+ {
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (!shoot[i].active)
+ {
+ shoot[i].position = (Vector2){ player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight) };
+ shoot[i].active = true;
+ shoot[i].speed.x = 1.5*sin(player.rotation*DEG2RAD)*MAX_SPEED;
+ shoot[i].speed.y = 1.5*cos(player.rotation*DEG2RAD)*MAX_SPEED;
+ shoot[i].rotation = player.rotation;
+ break;
+ }
+ }
+ }
+
+ // Shoot life timer
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (shoot[i].active) shoot[i].lifeSpawn++;
+ }
+
+ // Shot logic
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (shoot[i].active)
+ {
+ // Movement
+ shoot[i].position.x += shoot[i].speed.x;
+ shoot[i].position.y -= shoot[i].speed.y;
+
+ // Wall behaviour for shoot
+ if (shoot[i].position.x > screenWidth + shoot[i].radius)
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ }
+ else if (shoot[i].position.x < 0 - shoot[i].radius)
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ }
+ if (shoot[i].position.y > screenHeight + shoot[i].radius)
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ }
+ else if (shoot[i].position.y < 0 - shoot[i].radius)
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ }
+
+ // Life of shoot
+ if (shoot[i].lifeSpawn >= 60)
+ {
+ shoot[i].position = (Vector2){0, 0};
+ shoot[i].speed = (Vector2){0, 0};
+ shoot[i].lifeSpawn = 0;
+ shoot[i].active = false;
+ }
+ }
+ }
+
+ // Collision Player to meteors
+ player.collider = (Vector3){player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight/2.5f), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight/2.5f), 12};
+
+ for (int a = 0; a < NUM_BIG_METEORS; a++)
+ {
+ if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, bigMeteor[a].position, bigMeteor[a].radius) && bigMeteor[a].active) gameOver = true;
+ }
+
+ for (int a = 0; a < NUM_MEDIUM_METEORS; a++)
+ {
+ if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, mediumMeteor[a].position, mediumMeteor[a].radius) && mediumMeteor[a].active) gameOver = true;
+ }
+
+ for (int a = 0; a < NUM_SMALL_METEORS; a++)
+ {
+ if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, smallMeteor[a].position, smallMeteor[a].radius) && smallMeteor[a].active) gameOver = true;
+ }
+
+ // Meteor logic
+ for (int i = 0; i < NUM_BIG_METEORS; i++)
+ {
+ if (bigMeteor[i].active)
+ {
+ // movement
+ bigMeteor[i].position.x += bigMeteor[i].speed.x;
+ bigMeteor[i].position.y += bigMeteor[i].speed.y;
+
+ // wall behaviour
+ if (bigMeteor[i].position.x > screenWidth + bigMeteor[i].radius) bigMeteor[i].position.x = -(bigMeteor[i].radius);
+ else if (bigMeteor[i].position.x < 0 - bigMeteor[i].radius) bigMeteor[i].position.x = screenWidth + bigMeteor[i].radius;
+ if (bigMeteor[i].position.y > screenHeight + bigMeteor[i].radius) bigMeteor[i].position.y = -(bigMeteor[i].radius);
+ else if (bigMeteor[i].position.y < 0 - bigMeteor[i].radius) bigMeteor[i].position.y = screenHeight + bigMeteor[i].radius;
+ }
+ }
+
+ for (int i = 0; i < NUM_MEDIUM_METEORS; i++)
+ {
+ if (mediumMeteor[i].active)
+ {
+ // movement
+ mediumMeteor[i].position.x += mediumMeteor[i].speed.x;
+ mediumMeteor[i].position.y += mediumMeteor[i].speed.y;
+
+ // wall behaviour
+ if (mediumMeteor[i].position.x > screenWidth + mediumMeteor[i].radius) mediumMeteor[i].position.x = -(mediumMeteor[i].radius);
+ else if (mediumMeteor[i].position.x < 0 - mediumMeteor[i].radius) mediumMeteor[i].position.x = screenWidth + mediumMeteor[i].radius;
+ if (mediumMeteor[i].position.y > screenHeight + mediumMeteor[i].radius) mediumMeteor[i].position.y = -(mediumMeteor[i].radius);
+ else if (mediumMeteor[i].position.y < 0 - mediumMeteor[i].radius) mediumMeteor[i].position.y = screenHeight + mediumMeteor[i].radius;
+ }
+ }
+
+ for (int i = 0; i < NUM_SMALL_METEORS; i++)
+ {
+ if (smallMeteor[i].active)
+ {
+ // movement
+ smallMeteor[i].position.x += smallMeteor[i].speed.x;
+ smallMeteor[i].position.y += smallMeteor[i].speed.y;
+
+ // wall behaviour
+ if (smallMeteor[i].position.x > screenWidth + smallMeteor[i].radius) smallMeteor[i].position.x = -(smallMeteor[i].radius);
+ else if (smallMeteor[i].position.x < 0 - smallMeteor[i].radius) smallMeteor[i].position.x = screenWidth + smallMeteor[i].radius;
+ if (smallMeteor[i].position.y > screenHeight + smallMeteor[i].radius) smallMeteor[i].position.y = -(smallMeteor[i].radius);
+ else if (smallMeteor[i].position.y < 0 - smallMeteor[i].radius) smallMeteor[i].position.y = screenHeight + smallMeteor[i].radius;
+ }
+ }
+
+ // Collision behaviour
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if ((shoot[i].active))
+ {
+ for (int a = 0; a < NUM_BIG_METEORS; a++)
+ {
+ if (bigMeteor[a].active && CheckCollisionCircles(shoot[i].position, shoot[i].radius, bigMeteor[a].position, bigMeteor[a].radius))
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ bigMeteor[a].active = false;
+ meteorsDestroyed++;
+ for (int j = 0; j < 2; j ++)
+ {
+ if (countMediumMeteors%2 == 0)
+ {
+ mediumMeteor[countMediumMeteors].position = (Vector2){bigMeteor[a].position.x, bigMeteor[a].position.y};
+ mediumMeteor[countMediumMeteors].speed = (Vector2){cos(shoot[i].rotation*DEG2RAD)*METEORS_SPEED*-1, sin(shoot[i].rotation*DEG2RAD)*METEORS_SPEED*-1};
+ }
+ else
+ {
+ mediumMeteor[countMediumMeteors].position = (Vector2){bigMeteor[a].position.x, bigMeteor[a].position.y};
+ mediumMeteor[countMediumMeteors].speed = (Vector2){cos(shoot[i].rotation*DEG2RAD)*METEORS_SPEED, sin(shoot[i].rotation*DEG2RAD)*METEORS_SPEED};
+ }
+
+ mediumMeteor[countMediumMeteors].active = true;
+ countMediumMeteors ++;
+ }
+ //bigMeteor[a].position = (Vector2){-100, -100};
+ bigMeteor[a].color = RED;
+ a = NUM_BIG_METEORS;
+ }
+ }
+ }
+ if ((shoot[i].active))
+ {
+ for (int b = 0; b < NUM_MEDIUM_METEORS; b++)
+ {
+ if (mediumMeteor[b].active && CheckCollisionCircles(shoot[i].position, shoot[i].radius, mediumMeteor[b].position, mediumMeteor[b].radius))
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ mediumMeteor[b].active = false;
+ meteorsDestroyed++;
+ for (int j = 0; j < 2; j ++)
+ {
+ if (countSmallMeteors%2 == 0)
+ {
+ smallMeteor[countSmallMeteors].position = (Vector2){mediumMeteor[b].position.x, mediumMeteor[b].position.y};
+ smallMeteor[countSmallMeteors].speed = (Vector2){cos(shoot[i].rotation*DEG2RAD)*METEORS_SPEED*-1, sin(shoot[i].rotation*DEG2RAD)*METEORS_SPEED*-1};
+ }
+ else
+ {
+ smallMeteor[countSmallMeteors].position = (Vector2){mediumMeteor[b].position.x, mediumMeteor[b].position.y};
+ smallMeteor[countSmallMeteors].speed = (Vector2){cos(shoot[i].rotation*DEG2RAD)*METEORS_SPEED, sin(shoot[i].rotation*DEG2RAD)*METEORS_SPEED};
+ }
+
+ smallMeteor[countSmallMeteors].active = true;
+ countSmallMeteors ++;
+ }
+ //mediumMeteor[b].position = (Vector2){-100, -100};
+ mediumMeteor[b].color = GREEN;
+ b = NUM_MEDIUM_METEORS;
+ }
+ }
+ }
+ if ((shoot[i].active))
+ {
+ for (int c = 0; c < NUM_SMALL_METEORS; c++)
+ {
+ if (smallMeteor[c].active && CheckCollisionCircles(shoot[i].position, shoot[i].radius, smallMeteor[c].position, smallMeteor[c].radius))
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ smallMeteor[c].active = false;
+ meteorsDestroyed++;
+ smallMeteor[c].color = YELLOW;
+ // smallMeteor[c].position = (Vector2){-100, -100};
+ c = NUM_SMALL_METEORS;
+ }
+ }
+ }
+ }
+ }
+
+ if (meteorsDestroyed == NUM_BIG_METEORS + NUM_MEDIUM_METEORS + NUM_SMALL_METEORS) victory = true;
+ }
+ else
+ {
+ if (IsKeyPressed(KEY_ENTER))
+ {
+ InitGame();
+ gameOver = false;
+ }
+ }
+}
+
+// Draw game (one frame)
+void DrawGame(void)
+{
+ BeginDrawing();
+
+ ClearBackground(DARKGRAY);
+
+ if (!gameOver)
+ {
+ // Draw spaceship
+ Vector2 v1 = { player.position.x + sinf(player.rotation*DEG2RAD)*(shipHeight), player.position.y - cosf(player.rotation*DEG2RAD)*(shipHeight) };
+ Vector2 v2 = { player.position.x - cosf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2), player.position.y - sinf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2) };
+ Vector2 v3 = { player.position.x + cosf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2), player.position.y + sinf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2) };
+ DrawTriangleLines(v1, v2, v3, player.color);
+
+ // Draw meteors
+ for (int i = 0; i < NUM_BIG_METEORS; i++)
+ {
+ if (bigMeteor[i].active) DrawCircleV(bigMeteor[i].position, bigMeteor[i].radius, bigMeteor[i].color);
+ else DrawCircleV(bigMeteor[i].position, bigMeteor[i].radius, Fade(bigMeteor[i].color, 0.25f));
+ }
+
+ for (int i = 0; i < NUM_MEDIUM_METEORS; i++)
+ {
+ if (mediumMeteor[i].active) DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, mediumMeteor[i].color);
+ else DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, Fade(mediumMeteor[i].color, 0.25f));
+ }
+
+ for (int i = 0; i < NUM_SMALL_METEORS; i++)
+ {
+ if (smallMeteor[i].active) DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, smallMeteor[i].color);
+ else DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, Fade(smallMeteor[i].color, 0.25f));
+ }
+
+ // Draw shoot
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (shoot[i].active) DrawCircleV(shoot[i].position, shoot[i].radius, shoot[i].color);
+ }
+
+ if (victory) DrawText("VICTORY", screenWidth/2 - MeasureText("VICTORY", 20)/2, screenHeight/2, 20, LIGHTGRAY);
+
+ 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();
+} \ No newline at end of file
diff --git a/games/samples/asteroids_survival.c b/games/samples/asteroids_survival.c
new file mode 100644
index 00000000..e2be9366
--- /dev/null
+++ b/games/samples/asteroids_survival.c
@@ -0,0 +1,395 @@
+/*******************************************************************************************
+*
+* raylib - sample game: asteroids survival
+*
+* Sample game developed by Ian Eito, Albert Martos 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 <math.h>
+
+#if defined(PLATFORM_WEB)
+ #include <emscripten/emscripten.h>
+#endif
+
+//----------------------------------------------------------------------------------
+// Some Defines
+//----------------------------------------------------------------------------------
+#define MAX_SPEED 6
+#define METEORS_SPEED 2
+#define NUM_SHOOTS 10
+#define NUM_BIG_METEORS 4
+#define NUM_MEDIUM_METEORS 8
+#define NUM_SMALL_METEORS 16
+#define SHIP_BASE_SIZE 20.0f
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+
+typedef struct Player {
+ Vector2 position;
+ Vector2 speed;
+ float acceleration;
+ float rotation;
+ Vector3 collider;
+ Color color;
+} Player;
+
+typedef struct MediumMeteor {
+ Vector2 position;
+ Vector2 speed;
+ float radius;
+ bool active;
+ Color color;
+} MediumMeteor;
+
+typedef struct SmallMeteor {
+ Vector2 position;
+ Vector2 speed;
+ float radius;
+ bool active;
+ Color color;
+} SmallMeteor;
+
+
+//------------------------------------------------------------------------------------
+// Global Variables Declaration
+//------------------------------------------------------------------------------------
+static int screenWidth = 800;
+static int screenHeight = 450;
+
+static int framesCounter;
+static bool gameOver;
+static bool pause;
+
+// NOTE: Defined triangle is isosceles with common angles of 70 degrees.
+static float shipHeight;
+
+static Player player;
+static MediumMeteor mediumMeteor[NUM_MEDIUM_METEORS];
+static SmallMeteor smallMeteor[NUM_SMALL_METEORS];
+
+//------------------------------------------------------------------------------------
+// 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)
+
+static void DrawSpaceship(Vector2 position, float rotation, Color color);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "sample game: asteroids survival");
+
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#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)
+{
+ int posx, posy;
+ int velx, vely;
+ bool correctRange = false;
+
+ pause = false;
+
+ framesCounter = 0;
+
+ shipHeight = (SHIP_BASE_SIZE/2)/tanf(20*DEG2RAD);
+
+ // Initialization player
+ player.position = (Vector2){screenWidth/2, screenHeight/2 - shipHeight/2};
+ player.speed = (Vector2){0, 0};
+ player.acceleration = 0;
+ player.rotation = 0;
+ player.collider = (Vector3){player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight/2.5f), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight/2.5f), 12};
+ player.color = LIGHTGRAY;
+
+ for (int i = 0; i < NUM_MEDIUM_METEORS; i++)
+ {
+ posx = GetRandomValue(0, screenWidth);
+
+ while(!correctRange)
+ {
+ if (posx > screenWidth/2 - 150 && posx < screenWidth/2 + 150) posx = GetRandomValue(0, screenWidth);
+ else correctRange = true;
+ }
+
+ correctRange = false;
+
+ posy = GetRandomValue(0, screenHeight);
+
+ while(!correctRange)
+ {
+ if (posy > screenHeight/2 - 150 && posy < screenHeight/2 + 150) posy = GetRandomValue(0, screenHeight);
+ else correctRange = true;
+ }
+
+ correctRange = false;
+ velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+
+ while(!correctRange)
+ {
+ if (velx == 0 && vely == 0)
+ {
+ velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ }
+ else correctRange = true;
+ }
+ mediumMeteor[i].position = (Vector2){posx, posy};
+ mediumMeteor[i].speed = (Vector2){velx, vely};
+ mediumMeteor[i].radius = 20;
+ mediumMeteor[i].active = true;
+ mediumMeteor[i].color = GREEN;
+ }
+
+ for (int i = 0; i < NUM_SMALL_METEORS; i++)
+ {
+ posx = GetRandomValue(0, screenWidth);
+
+ while(!correctRange)
+ {
+ if (posx > screenWidth/2 - 150 && posx < screenWidth/2 + 150) posx = GetRandomValue(0, screenWidth);
+ else correctRange = true;
+ }
+
+ correctRange = false;
+
+ posy = GetRandomValue(0, screenHeight);
+
+ while(!correctRange)
+ {
+ if (posy > screenHeight/2 - 150 && posy < screenHeight/2 + 150) posy = GetRandomValue(0, screenHeight);
+ else correctRange = true;
+ }
+
+ correctRange = false;
+ velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+
+ while(!correctRange)
+ {
+ if (velx == 0 && vely == 0)
+ {
+ velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ }
+ else correctRange = true;
+ }
+ smallMeteor[i].position = (Vector2){posx, posy};
+ smallMeteor[i].speed = (Vector2){velx, vely};
+ smallMeteor[i].radius = 10;
+ smallMeteor[i].active = true;
+ smallMeteor[i].color = YELLOW;
+ }
+}
+
+// Update game (one frame)
+void UpdateGame(void)
+{
+ if (!gameOver)
+ {
+ if (IsKeyPressed('P')) pause = !pause;
+
+ if (!pause)
+ {
+ framesCounter++;
+
+ // Player logic
+
+ // Rotation
+ if (IsKeyDown(KEY_LEFT)) player.rotation -= 5;
+ if (IsKeyDown(KEY_RIGHT)) player.rotation += 5;
+
+ // Speed
+ player.speed.x = sin(player.rotation*DEG2RAD)*MAX_SPEED;
+ player.speed.y = cos(player.rotation*DEG2RAD)*MAX_SPEED;
+
+ // Controller
+ if (IsKeyDown(KEY_UP))
+ {
+ if (player.acceleration < 1) player.acceleration += 0.04f;
+ }
+ else
+ {
+ if (player.acceleration > 0) player.acceleration -= 0.02f;
+ else if (player.acceleration < 0) player.acceleration = 0;
+ }
+ if (IsKeyDown(KEY_DOWN))
+ {
+ if (player.acceleration > 0) player.acceleration -= 0.04f;
+ else if (player.acceleration < 0) player.acceleration = 0;
+ }
+
+ // Movement
+ player.position.x += (player.speed.x*player.acceleration);
+ player.position.y -= (player.speed.y*player.acceleration);
+
+ // Wall behaviour for player
+ if (player.position.x > screenWidth + shipHeight) player.position.x = -(shipHeight);
+ else if (player.position.x < -(shipHeight)) player.position.x = screenWidth + shipHeight;
+ if (player.position.y > (screenHeight + shipHeight)) player.position.y = -(shipHeight);
+ else if (player.position.y < -(shipHeight)) player.position.y = screenHeight + shipHeight;
+
+ // Collision Player to meteors
+ player.collider = (Vector3){player.position.x + sin(player.rotation*DEG2RAD)*(shipHeight/2.5f), player.position.y - cos(player.rotation*DEG2RAD)*(shipHeight/2.5f), 12};
+
+ for (int a = 0; a < NUM_MEDIUM_METEORS; a++)
+ {
+ if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, mediumMeteor[a].position, mediumMeteor[a].radius) && mediumMeteor[a].active) gameOver = true;
+ }
+
+ for (int a = 0; a < NUM_SMALL_METEORS; a++)
+ {
+ if (CheckCollisionCircles((Vector2){player.collider.x, player.collider.y}, player.collider.z, smallMeteor[a].position, smallMeteor[a].radius) && smallMeteor[a].active) gameOver = true;
+ }
+
+ // Meteor logic
+
+ for (int i = 0; i < NUM_MEDIUM_METEORS; i++)
+ {
+ if (mediumMeteor[i].active)
+ {
+ // movement
+ mediumMeteor[i].position.x += mediumMeteor[i].speed.x;
+ mediumMeteor[i].position.y += mediumMeteor[i].speed.y;
+
+ // wall behaviour
+ if (mediumMeteor[i].position.x > screenWidth + mediumMeteor[i].radius) mediumMeteor[i].position.x = -(mediumMeteor[i].radius);
+ else if (mediumMeteor[i].position.x < 0 - mediumMeteor[i].radius) mediumMeteor[i].position.x = screenWidth + mediumMeteor[i].radius;
+ if (mediumMeteor[i].position.y > screenHeight + mediumMeteor[i].radius) mediumMeteor[i].position.y = -(mediumMeteor[i].radius);
+ else if (mediumMeteor[i].position.y < 0 - mediumMeteor[i].radius) mediumMeteor[i].position.y = screenHeight + mediumMeteor[i].radius;
+ }
+ }
+
+ for (int i = 0; i < NUM_SMALL_METEORS; i++)
+ {
+ if (smallMeteor[i].active)
+ {
+ // movement
+ smallMeteor[i].position.x += smallMeteor[i].speed.x;
+ smallMeteor[i].position.y += smallMeteor[i].speed.y;
+
+ // wall behaviour
+ if (smallMeteor[i].position.x > screenWidth + smallMeteor[i].radius) smallMeteor[i].position.x = -(smallMeteor[i].radius);
+ else if (smallMeteor[i].position.x < 0 - smallMeteor[i].radius) smallMeteor[i].position.x = screenWidth + smallMeteor[i].radius;
+ if (smallMeteor[i].position.y > screenHeight + smallMeteor[i].radius) smallMeteor[i].position.y = -(smallMeteor[i].radius);
+ else if (smallMeteor[i].position.y < 0 - smallMeteor[i].radius) smallMeteor[i].position.y = screenHeight + smallMeteor[i].radius;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (IsKeyPressed(KEY_ENTER))
+ {
+ InitGame();
+ gameOver = false;
+ }
+ }
+}
+
+// Draw game (one frame)
+void DrawGame(void)
+{
+ BeginDrawing();
+
+ ClearBackground(DARKGRAY);
+
+ if (!gameOver)
+ {
+ // Draw spaceship
+ Vector2 v1 = { player.position.x + sinf(player.rotation*DEG2RAD)*(shipHeight), player.position.y - cosf(player.rotation*DEG2RAD)*(shipHeight) };
+ Vector2 v2 = { player.position.x - cosf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2), player.position.y - sinf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2) };
+ Vector2 v3 = { player.position.x + cosf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2), player.position.y + sinf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2) };
+
+ DrawTriangleLines(v1, v2, v3, player.color);
+
+ // Draw meteor
+ for (int i = 0;i < NUM_MEDIUM_METEORS; i++)
+ {
+ if (mediumMeteor[i].active) DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, mediumMeteor[i].color);
+ else DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, Fade(mediumMeteor[i].color, 0.25f));
+ }
+
+ for (int i = 0;i < NUM_SMALL_METEORS; i++)
+ {
+ if (smallMeteor[i].active) DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, smallMeteor[i].color);
+ else DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, Fade(smallMeteor[i].color, 0.25f));
+ }
+
+ DrawText(FormatText("SURVIVAL TIME: %.02f", (float)framesCounter/60), 10, 10, 20, WHITE);
+
+ 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();
+} \ No newline at end of file
diff --git a/games/samples/floppy.c b/games/samples/floppy.c
new file mode 100644
index 00000000..d66f5bbe
--- /dev/null
+++ b/games/samples/floppy.c
@@ -0,0 +1,246 @@
+/*******************************************************************************************
+*
+* raylib - sample game: floppy
+*
+* Sample game developed by Ian Eito, Albert Martos 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"
+
+#if defined(PLATFORM_WEB)
+ #include <emscripten/emscripten.h>
+#endif
+
+//----------------------------------------------------------------------------------
+// Some Defines
+//----------------------------------------------------------------------------------
+#define MAX_TUBES 100
+#define FLOPPY_RADIUS 24
+#define TUBES_WIDTH 80
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct Floppy {
+ Vector2 position;
+ int radius;
+ Color color;
+} Floppy;
+
+typedef struct Tubes {
+ Rectangle rec;
+ Color color;
+ bool active;
+} Tubes;
+
+//------------------------------------------------------------------------------------
+// Global Variables Declaration
+//------------------------------------------------------------------------------------
+static int screenWidth = 800;
+static int screenHeight = 450;
+
+static int framesCounter;
+static bool gameOver;
+static bool pause;
+static int score;
+static int hiScore = 0;
+
+static Floppy floppy;
+static Tubes tubes[MAX_TUBES*2];
+static Vector2 tubesPos[MAX_TUBES];
+static int tubesSpeedX;
+static bool superfx;
+
+//------------------------------------------------------------------------------------
+// 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()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "sample game: floppy");
+
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#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)
+{
+ floppy.radius = FLOPPY_RADIUS;
+ floppy.position = (Vector2){80, screenHeight/2 - floppy.radius};
+ tubesSpeedX = 2;
+
+ for (int i = 0; i < MAX_TUBES; i++)
+ {
+ tubesPos[i].x = 400 + 280*i;
+ tubesPos[i].y = -GetRandomValue(0, 120);
+ }
+
+ for (int i = 0; i < MAX_TUBES*2; i += 2)
+ {
+ tubes[i].rec.x = tubesPos[i/2].x;
+ tubes[i].rec.y = tubesPos[i/2].y;
+ tubes[i].rec.width = TUBES_WIDTH;
+ tubes[i].rec.height = 255;
+
+ tubes[i+1].rec.x = tubesPos[i/2].x;
+ tubes[i+1].rec.y = 600 + tubesPos[i/2].y - 255;
+ tubes[i+1].rec.width = TUBES_WIDTH;
+ tubes[i+1].rec.height = 255;
+
+ tubes[i/2].active = true;
+ }
+
+ score = 0;
+
+ gameOver = false;
+ superfx = false;
+ pause = false;
+}
+
+// Update game (one frame)
+void UpdateGame(void)
+{
+ if (!gameOver)
+ {
+ if (IsKeyPressed('P')) pause = !pause;
+
+ if (!pause)
+ {
+ for (int i = 0; i < MAX_TUBES; i++) tubesPos[i].x -= tubesSpeedX;
+
+ for (int i = 0; i < MAX_TUBES*2; i += 2)
+ {
+ tubes[i].rec.x = tubesPos[i/2].x;
+ tubes[i+1].rec.x = tubesPos[i/2].x;
+ }
+
+ if (IsKeyDown(KEY_SPACE) && !gameOver) floppy.position.y -= 3;
+ else floppy.position.y += 1;
+
+ // Check Collisions
+ for (int i = 0; i < MAX_TUBES*2; i++)
+ {
+ if (CheckCollisionCircleRec(floppy.position, floppy.radius, tubes[i].rec))
+ {
+ gameOver = true;
+ pause = false;
+ }
+ else if ((tubesPos[i/2].x < floppy.position.x) && tubes[i/2].active && !gameOver)
+ {
+ score += 100;
+ tubes[i/2].active = false;
+
+ superfx = true;
+
+ if (score > hiScore) hiScore = score;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (IsKeyPressed(KEY_ENTER))
+ {
+ InitGame();
+ gameOver = false;
+ }
+ }
+}
+
+// Draw game (one frame)
+void DrawGame(void)
+{
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ if (!gameOver)
+ {
+ DrawCircle(floppy.position.x, floppy.position.y, floppy.radius, BLUE);
+
+ // Draw tubes
+ for (int i = 0; i < MAX_TUBES; i++)
+ {
+ DrawRectangle(tubes[i*2].rec.x, tubes[i*2].rec.y, tubes[i*2].rec.width, tubes[i*2].rec.height, RED);
+ DrawRectangle(tubes[i*2 + 1].rec.x, tubes[i*2 + 1].rec.y, tubes[i*2 + 1].rec.width, tubes[i*2 + 1].rec.height, RED);
+ }
+
+ // Draw flashing fx (one frame only)
+ if (superfx)
+ {
+ DrawRectangle(0, 0, screenWidth, screenHeight, GOLD);
+ superfx = false;
+ }
+
+ DrawText(FormatText("%04i", score), 20, 20, 40, PINK);
+ DrawText(FormatText("HI-SCORE: %04i", hiScore), 20, 70, 20, VIOLET);
+
+ 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();
+} \ No newline at end of file
diff --git a/games/samples/gold_fever.c b/games/samples/gold_fever.c
new file mode 100644
index 00000000..d4c0d99f
--- /dev/null
+++ b/games/samples/gold_fever.c
@@ -0,0 +1,293 @@
+/*******************************************************************************************
+*
+* raylib - sample game: gold fever
+*
+* Sample game developed by Ian Eito, Albert Martos 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"
+
+#if defined(PLATFORM_WEB)
+ #include <emscripten/emscripten.h>
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct Player {
+ Vector2 position;
+ int radius;
+ Vector2 speed;
+ Color color;
+} Player;
+
+typedef struct Enemy {
+ Vector2 position;
+ int radius;
+ int radiusBounds;
+ Vector2 speed;
+ bool moveRight;
+ Color colorBounds;
+ Color color;
+} Enemy;
+
+typedef struct Points {
+ Vector2 position;
+ int radius;
+ int value;
+ bool active;
+ Color color;
+} Points;
+
+typedef struct Exit {
+ Rectangle rec;
+ bool active;
+ bool save;
+ Color color;
+} Exit;
+
+//------------------------------------------------------------------------------------
+// Global Variables Declaration
+//------------------------------------------------------------------------------------
+static int screenWidth = 800;
+static int screenHeight = 450;
+
+static int framesCounter;
+static bool gameOver;
+static bool pause;
+static int score;
+static int hiScore = 0;
+
+static Player player;
+static Enemy enemy;
+static Points points;
+static Exit exit;
+static bool follow;
+
+//------------------------------------------------------------------------------------
+// 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()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+
+ InitWindow(screenWidth, screenHeight, "sample game: gold fever");
+
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#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)
+{
+ pause = false;
+ score = 0;
+
+ player.position = (Vector2){50, 50};
+ player.radius = 20;
+ player.speed = (Vector2){5, 5};
+ player.color = DARKGRAY;
+
+ enemy.position = (Vector2){screenWidth - 50, screenHeight/2};
+ enemy.radius = 20;
+ enemy.radiusBounds = 150;
+ enemy.speed = (Vector2){3, 3};
+ enemy.moveRight = true;
+ enemy.color = MAROON;
+ enemy.colorBounds = RED;
+ follow = false;
+
+ points.radius = 10;
+ points.position = (Vector2){GetRandomValue(points.radius, screenWidth - points.radius), GetRandomValue(points.radius, screenHeight - points.radius)};
+ points.value = 100;
+ points.active = true;
+ points.color = GOLD;
+
+ exit.rec.width = 50;
+ exit.rec.height = 50;
+ exit.rec.x = GetRandomValue(0, screenWidth - exit.rec.width);
+ exit.rec.y = GetRandomValue(0, screenHeight - exit.rec.height);
+ exit.active = false;
+ exit.save = false;
+ exit.color = PINK;
+}
+
+// Update game (one frame)
+void UpdateGame(void)
+{
+ if (!gameOver)
+ {
+ if (IsKeyPressed('P')) pause = !pause;
+
+ if (!pause)
+ {
+ //Control player
+ if (IsKeyDown(KEY_RIGHT)) player.position.x += player.speed.x;
+ if (IsKeyDown(KEY_LEFT)) player.position.x -= player.speed.x;
+ if (IsKeyDown(KEY_UP)) player.position.y -= player.speed.y;
+ if (IsKeyDown(KEY_DOWN)) player.position.y += player.speed.y;
+
+ //wall behaviour player
+ if (player.position.x - player.radius <= 0) player.position.x = player.radius;
+ if (player.position.x + player.radius >= screenWidth) player.position.x = screenWidth - player.radius;
+ if (player.position.y - player.radius <= 0) player.position.y = player.radius;
+ if (player.position.y + player.radius >= screenHeight) player.position.y = screenHeight - player.radius;
+
+ //IA Enemy
+ if ( (follow || CheckCollisionCircles(player.position, player.radius, enemy.position, enemy.radiusBounds)) && !exit.save)
+ {
+ if (player.position.x > enemy.position.x) enemy.position.x += enemy.speed.x;
+ if (player.position.x < enemy.position.x) enemy.position.x -= enemy.speed.x;
+
+ if (player.position.y > enemy.position.y) enemy.position.y += enemy.speed.y;
+ if (player.position.y < enemy.position.y) enemy.position.y -= enemy.speed.y;
+ }
+ else
+ {
+ if (enemy.moveRight) enemy.position.x += enemy.speed.x;
+ else enemy.position.x -= enemy.speed.x;
+ }
+
+ //wall behaviour enemy
+ if (enemy.position.x - enemy.radius <= 0) enemy.moveRight = true;
+ if (enemy.position.x + enemy.radius >= screenWidth) enemy.moveRight = false;
+
+ if (enemy.position.x - enemy.radius <= 0) enemy.position.x = enemy.radius;
+ if (enemy.position.x + enemy.radius >= screenWidth) enemy.position.x = screenWidth - enemy.radius;
+ if (enemy.position.y - enemy.radius <= 0) enemy.position.y = enemy.radius;
+ if (enemy.position.y + enemy.radius >= screenHeight) enemy.position.y = screenHeight - enemy.radius;
+
+ //Collisions
+ if (CheckCollisionCircles(player.position, player.radius, points.position, points.radius) && points.active)
+ {
+ follow = true;
+ points.active = false;
+ exit.active = true;
+ }
+
+ if (CheckCollisionCircles(player.position, player.radius, enemy.position, enemy.radius) && !exit.save)
+ {
+ gameOver = true;
+
+ if (hiScore < score) hiScore = score;
+ }
+
+ if (CheckCollisionCircleRec(player.position, player.radius, exit.rec))
+ {
+ follow = false;
+
+ if (!points.active)
+ {
+ score += points.value;
+ points.active = true;
+ enemy.speed.x += 0.5;
+ enemy.speed.y += 0.5;
+ points.position = (Vector2){GetRandomValue(points.radius, screenWidth - points.radius), GetRandomValue(points.radius, screenHeight - points.radius)};
+ }
+
+ exit.save = true;
+ }
+ else exit.save = false;
+ }
+ }
+ else
+ {
+ if (IsKeyPressed(KEY_ENTER))
+ {
+ InitGame();
+ gameOver = false;
+ }
+ }
+}
+
+// Draw game (one frame)
+void DrawGame(void)
+{
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ if (!gameOver)
+ {
+ if (follow) ClearBackground(RED);
+
+ DrawCircleLines(enemy.position.x, enemy.position.y, enemy.radiusBounds, enemy.colorBounds);
+ DrawCircleV(enemy.position, enemy.radius, enemy.color);
+
+ DrawCircleV(player.position, player.radius, player.color);
+ DrawCircleV(points.position, points.radius, points.color);
+
+ if (exit.active) DrawRectangleRec(exit.rec, exit.color);
+
+ DrawText(FormatText("SCORE: %04i", score), 10, 10, 20, GRAY);
+ DrawText(FormatText("HI-SCORE: %04i", hiScore), 300, 10, 20, GRAY);
+
+ 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();
+} \ No newline at end of file
diff --git a/games/samples/gorilas.c b/games/samples/gorilas.c
new file mode 100644
index 00000000..86fd3f5b
--- /dev/null
+++ b/games/samples/gorilas.c
@@ -0,0 +1,571 @@
+/*******************************************************************************************
+*
+* raylib - sample game: gorilas
+*
+* 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 MAX_BUILDINGS 15
+#define MAX_EXPLOSIONS 200
+#define MAX_PLAYERS 2
+
+#define BUILDING_RELATIVE_ERROR 30 // Building size random range %
+#define BUILDING_MIN_RELATIVE_HEIGHT 20 // Minimum height in % of the screenHeight
+#define BUILDING_MAX_RELATIVE_HEIGHT 60 // Maximum height in % of the screenHeight
+#define BUILDING_MIN_GRAYSCALE_COLOR 120 // Minimum gray color for the buildings
+#define BUILDING_MAX_GRAYSCALE_COLOR 200 // Maximum gray color for the buildings
+
+#define MIN_PLAYER_POSITION 5 // Minimum x position %
+#define MAX_PLAYER_POSITION 20 // Maximum x position %
+
+#define GRAVITY 9.81f
+#define DELTA_FPS 60
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct Player {
+ Vector2 position;
+ Vector2 size;
+
+ Vector2 aimingPoint;
+ int aimingAngle;
+ int aimingPower;
+
+ Vector2 previousPoint;
+ int previousAngle;
+ int previousPower;
+
+ Vector2 impactPoint;
+
+ bool isLeftTeam; // This player belongs to the left or to the right team
+ bool isPlayer; // If is a player or an AI
+ bool isAlive;
+} Player;
+
+typedef struct Building {
+ Rectangle rectangle;
+ Color color;
+} Building;
+
+typedef struct Explosion {
+ Vector2 position;
+ int radius;
+ bool active;
+} Explosion;
+
+typedef struct Ball {
+ Vector2 position;
+ Vector2 speed;
+ int radius;
+ bool active;
+} Ball;
+
+//------------------------------------------------------------------------------------
+// Global Variables Declaration
+//------------------------------------------------------------------------------------
+static int screenWidth = 800;
+static int screenHeight = 450;
+
+static bool gameOver = false;
+static bool pause = false;
+
+static Player player[MAX_PLAYERS];
+static Building building[MAX_BUILDINGS];
+static Explosion explosion[MAX_EXPLOSIONS];
+static Ball ball;
+
+static int playerTurn = 0;
+static bool ballOnAir = false;
+
+//------------------------------------------------------------------------------------
+// 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)
+
+// Additional module functions
+static void InitBuildings(void);
+static void InitPlayers(void);
+static bool UpdatePlayer(int playerTurn);
+static bool UpdateBall(int playerTurn);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "sample game: gorilas");
+
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#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)
+{
+ // Init shoot
+ ball.radius = 10;
+ ballOnAir = false;
+ ball.active = false;
+
+ InitBuildings();
+ InitPlayers();
+
+ // Init explosions
+ for (int i = 0; i < MAX_EXPLOSIONS; i++)
+ {
+ explosion[i].position = (Vector2){ 0.0f, 0.0f };
+ explosion[i].radius = 30;
+ explosion[i].active = false;
+ }
+}
+
+// Update game (one frame)
+void UpdateGame(void)
+{
+ if (!gameOver)
+ {
+ if (IsKeyPressed('P')) pause = !pause;
+
+ if (!pause)
+ {
+ if (!ballOnAir) ballOnAir = UpdatePlayer(playerTurn); // If we are aiming
+ else
+ {
+ if (UpdateBall(playerTurn)) // If collision
+ {
+ // Game over logic
+ bool leftTeamAlive = false;
+ bool rightTeamAlive = false;
+
+ for (int i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (player[i].isAlive)
+ {
+ if (player[i].isLeftTeam) leftTeamAlive = true;
+ if (!player[i].isLeftTeam) rightTeamAlive = true;
+ }
+ }
+
+ if (leftTeamAlive && rightTeamAlive)
+ {
+ ballOnAir = false;
+ ball.active = false;
+
+ playerTurn++;
+
+ if (playerTurn == MAX_PLAYERS) playerTurn = 0;
+ }
+ else
+ {
+ gameOver = true;
+
+ // if (leftTeamAlive) left team wins
+ // if (rightTeamAlive) right team wins
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (IsKeyPressed(KEY_ENTER))
+ {
+ InitGame();
+ gameOver = false;
+ }
+ }
+}
+
+// Draw game (one frame)
+void DrawGame(void)
+{
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ if (!gameOver)
+ {
+ // Draw buildings
+ for (int i = 0; i < MAX_BUILDINGS; i++) DrawRectangleRec(building[i].rectangle, building[i].color);
+
+ // Draw explosions
+ for (int i = 0; i < MAX_EXPLOSIONS; i++)
+ {
+ if (explosion[i].active) DrawCircle(explosion[i].position.x, explosion[i].position.y, explosion[i].radius, RAYWHITE);
+ }
+
+ // Draw players
+ for (int i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (player[i].isAlive)
+ {
+ if (player[i].isLeftTeam) DrawRectangle(player[i].position.x - player[i].size.x/2, player[i].position.y - player[i].size.y/2,
+ player[i].size.x, player[i].size.y, BLUE);
+ else DrawRectangle(player[i].position.x - player[i].size.x/2, player[i].position.y - player[i].size.y/2,
+ player[i].size.x, player[i].size.y, RED);
+ }
+ }
+
+ // Draw ball
+ if (ball.active) DrawCircle(ball.position.x, ball.position.y, ball.radius, MAROON);
+
+ // Draw the angle and the power of the aim, and the previous ones
+ if (!ballOnAir)
+ {
+ // Draw shot information
+ /*
+ if (player[playerTurn].isLeftTeam)
+ {
+ DrawText(FormatText("Previous Point %i, %i", (int)player[playerTurn].previousPoint.x, (int)player[playerTurn].previousPoint.y), 20, 20, 20, DARKBLUE);
+ DrawText(FormatText("Previous Angle %i", player[playerTurn].previousAngle), 20, 50, 20, DARKBLUE);
+ DrawText(FormatText("Previous Power %i", player[playerTurn].previousPower), 20, 80, 20, DARKBLUE);
+ DrawText(FormatText("Aiming Point %i, %i", (int)player[playerTurn].aimingPoint.x, (int)player[playerTurn].aimingPoint.y), 20, 110, 20, DARKBLUE);
+ DrawText(FormatText("Aiming Angle %i", player[playerTurn].aimingAngle), 20, 140, 20, DARKBLUE);
+ DrawText(FormatText("Aiming Power %i", player[playerTurn].aimingPower), 20, 170, 20, DARKBLUE);
+ }
+ else
+ {
+ DrawText(FormatText("Previous Point %i, %i", (int)player[playerTurn].previousPoint.x, (int)player[playerTurn].previousPoint.y), screenWidth*3/4, 20, 20, DARKBLUE);
+ DrawText(FormatText("Previous Angle %i", player[playerTurn].previousAngle), screenWidth*3/4, 50, 20, DARKBLUE);
+ DrawText(FormatText("Previous Power %i", player[playerTurn].previousPower), screenWidth*3/4, 80, 20, DARKBLUE);
+ DrawText(FormatText("Aiming Point %i, %i", (int)player[playerTurn].aimingPoint.x, (int)player[playerTurn].aimingPoint.y), screenWidth*3/4, 110, 20, DARKBLUE);
+ DrawText(FormatText("Aiming Angle %i", player[playerTurn].aimingAngle), screenWidth*3/4, 140, 20, DARKBLUE);
+ DrawText(FormatText("Aiming Power %i", player[playerTurn].aimingPower), screenWidth*3/4, 170, 20, DARKBLUE);
+ }
+ */
+
+ // Draw aim
+ if (player[playerTurn].isLeftTeam)
+ {
+ // Previous aiming
+ DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 },
+ (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 },
+ player[playerTurn].previousPoint, GRAY);
+
+ // Actual aiming
+ DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 },
+ (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 },
+ player[playerTurn].aimingPoint, DARKBLUE);
+ }
+ else
+ {
+ // Previous aiming
+ DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 },
+ (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 },
+ player[playerTurn].previousPoint, GRAY);
+
+ // Actual aiming
+ DrawTriangle((Vector2){ player[playerTurn].position.x - player[playerTurn].size.x/4, player[playerTurn].position.y + player[playerTurn].size.y/4 },
+ (Vector2){ player[playerTurn].position.x + player[playerTurn].size.x/4, player[playerTurn].position.y - player[playerTurn].size.y/4 },
+ player[playerTurn].aimingPoint, MAROON);
+ }
+ }
+
+ 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();
+}
+
+//--------------------------------------------------------------------------------------
+// Additional module functions
+//--------------------------------------------------------------------------------------
+static void InitBuildings(void)
+{
+ // Horizontal generation
+ int currentWidth = 0;
+
+ // We make sure the absolute error randomly generated for each building, has as a minimum value the screenWidth.
+ // This way all the screen will be filled with buildings. Each building will have a different, random width.
+
+ float relativeWidth = 100/(100 - BUILDING_RELATIVE_ERROR);
+ float buildingWidthMean = (screenWidth*relativeWidth/MAX_BUILDINGS) + 1; // We add one to make sure we will cover the whole screen.
+
+ // Vertical generation
+ int currentHeighth = 0;
+ int grayLevel;
+
+ // Creation
+ for (int i = 0; i < MAX_BUILDINGS; i++)
+ {
+ // Horizontal
+ building[i].rectangle.x = currentWidth;
+ building[i].rectangle.width = GetRandomValue(buildingWidthMean*(100 - BUILDING_RELATIVE_ERROR/2)/100 + 1, buildingWidthMean*(100 + BUILDING_RELATIVE_ERROR)/100);
+
+ currentWidth += building[i].rectangle.width;
+
+ // Vertical
+ currentHeighth = GetRandomValue(BUILDING_MIN_RELATIVE_HEIGHT, BUILDING_MAX_RELATIVE_HEIGHT);
+ building[i].rectangle.y = screenHeight - (screenHeight*currentHeighth/100);
+ building[i].rectangle.height = screenHeight*currentHeighth/100 + 1;
+
+ // Color
+ grayLevel = GetRandomValue(BUILDING_MIN_GRAYSCALE_COLOR, BUILDING_MAX_GRAYSCALE_COLOR);
+ building[i].color = (Color){ grayLevel, grayLevel, grayLevel, 255 };
+ }
+}
+
+static void InitPlayers(void)
+{
+ for (int i = 0; i < MAX_PLAYERS; i++)
+ {
+ player[i].isAlive = true;
+
+ // Decide the team of this player
+ if (i % 2 == 0) player[i].isLeftTeam = true;
+ else player[i].isLeftTeam = false;
+
+ // Now there is no AI
+ player[i].isPlayer = true;
+
+ // Set size, by default by now
+ player[i].size = (Vector2){ 40, 40 };
+
+ // Set position
+ if (player[i].isLeftTeam) player[i].position.x = GetRandomValue(screenWidth*MIN_PLAYER_POSITION/100, screenWidth*MAX_PLAYER_POSITION/100);
+ else player[i].position.x = screenWidth - GetRandomValue(screenWidth*MIN_PLAYER_POSITION/100, screenWidth*MAX_PLAYER_POSITION/100);
+
+ for (int j = 0; j < MAX_BUILDINGS; j++)
+ {
+ if (building[j].rectangle.x > player[i].position.x)
+ {
+ // Set the player in the center of the building
+ player[i].position.x = building[j-1].rectangle.x + building[j-1].rectangle.width/2;
+ // Set the player at the top of the building
+ player[i].position.y = building[j-1].rectangle.y - player[i].size.y/2;
+ break;
+ }
+ }
+
+ // Set statistics to 0
+ player[i].aimingPoint = player[i].position;
+ player[i].previousAngle = 0;
+ player[i].previousPower = 0;
+ player[i].previousPoint = player[i].position;
+ player[i].aimingAngle = 0;
+ player[i].aimingPower = 0;
+
+ player[i].impactPoint = (Vector2){ -100, -100 };
+ }
+}
+
+static bool UpdatePlayer(int playerTurn)
+{
+ // If we are aiming at the firing quadrant, we calculate the angle
+ if (GetMousePosition().y <= player[playerTurn].position.y)
+ {
+ // Left team
+ if (player[playerTurn].isLeftTeam && GetMousePosition().x >= player[playerTurn].position.x)
+ {
+ // Distance (calculating the fire power)
+ player[playerTurn].aimingPower = sqrt(pow(player[playerTurn].position.x - GetMousePosition().x, 2) + pow(player[playerTurn].position.y - GetMousePosition().y, 2));
+ // Calculates the angle via arcsin
+ player[playerTurn].aimingAngle = asin((player[playerTurn].position.y - GetMousePosition().y)/player[playerTurn].aimingPower)*RAD2DEG;
+ // Point of the screen we are aiming at
+ player[playerTurn].aimingPoint = GetMousePosition();
+
+ // Ball fired
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ player[playerTurn].previousPoint = player[playerTurn].aimingPoint;
+ player[playerTurn].previousPower = player[playerTurn].aimingPower;
+ player[playerTurn].previousAngle = player[playerTurn].aimingAngle;
+ ball.position = player[playerTurn].position;
+
+ return true;
+ }
+ }
+ // Right team
+ else if (!player[playerTurn].isLeftTeam && GetMousePosition().x <= player[playerTurn].position.x)
+ {
+ // Distance (calculating the fire power)
+ player[playerTurn].aimingPower = sqrt(pow(player[playerTurn].position.x - GetMousePosition().x, 2) + pow(player[playerTurn].position.y - GetMousePosition().y, 2));
+ // Calculates the angle via arcsin
+ player[playerTurn].aimingAngle = asin((player[playerTurn].position.y - GetMousePosition().y)/player[playerTurn].aimingPower)*RAD2DEG;
+ // Point of the screen we are aiming at
+ player[playerTurn].aimingPoint = GetMousePosition();
+
+ // Ball fired
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ player[playerTurn].previousPoint = player[playerTurn].aimingPoint;
+ player[playerTurn].previousPower = player[playerTurn].aimingPower;
+ player[playerTurn].previousAngle = player[playerTurn].aimingAngle;
+ ball.position = player[playerTurn].position;
+
+ return true;
+ }
+ }
+ else
+ {
+ player[playerTurn].aimingPoint = player[playerTurn].position;
+ player[playerTurn].aimingPower = 0;
+ player[playerTurn].aimingAngle = 0;
+ }
+ }
+ else
+ {
+ player[playerTurn].aimingPoint = player[playerTurn].position;
+ player[playerTurn].aimingPower = 0;
+ player[playerTurn].aimingAngle = 0;
+ }
+
+ return false;
+}
+
+static bool UpdateBall(int playerTurn)
+{
+ static int explosionNumber = 0;
+
+ // Activate ball
+ if (!ball.active)
+ {
+ if (player[playerTurn].isLeftTeam)
+ {
+ ball.speed.x = cos(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS;
+ ball.speed.y = -sin(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS;
+ ball.active = true;
+ }
+ else
+ {
+ ball.speed.x = -cos(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS;
+ ball.speed.y = -sin(player[playerTurn].previousAngle*DEG2RAD)*player[playerTurn].previousPower*3/DELTA_FPS;
+ ball.active = true;
+ }
+ }
+
+ ball.position.x += ball.speed.x;
+ ball.position.y += ball.speed.y;
+ ball.speed.y += GRAVITY/DELTA_FPS;
+
+ // Collision
+ if (ball.position.x + ball.radius < 0) return true;
+ else if (ball.position.x - ball.radius > screenWidth) return true;
+ else
+ {
+ // Player collision
+ for (int i = 0; i < MAX_PLAYERS; i++)
+ {
+ 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,
+ player[i].size.x, player[i].size.y }))
+ {
+ // We can't hit ourselves
+ if (i == playerTurn) return false;
+ else
+ {
+ // We set the impact point
+ player[playerTurn].impactPoint.x = ball.position.x;
+ player[playerTurn].impactPoint.y = ball.position.y + ball.radius;
+
+ // We destroy the player
+ player[i].isAlive = false;
+ return true;
+ }
+ }
+ }
+
+ // Building collision
+ // NOTE: We only check building collision if we are not inside an explosion
+ for (int i = 0; i < MAX_BUILDINGS; i++)
+ {
+ if (CheckCollisionCircles(ball.position, ball.radius, explosion[i].position, explosion[i].radius - ball.radius))
+ {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < MAX_BUILDINGS; i++)
+ {
+ if (CheckCollisionCircleRec(ball.position, ball.radius, building[i].rectangle))
+ {
+ // We set the impact point
+ player[playerTurn].impactPoint.x = ball.position.x;
+ player[playerTurn].impactPoint.y = ball.position.y + ball.radius;
+
+ // We create an explosion
+ explosion[explosionNumber].position = player[playerTurn].impactPoint;
+ explosion[explosionNumber].active = true;
+ explosionNumber++;
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+} \ No newline at end of file
diff --git a/games/samples/missile_commander.c b/games/samples/missile_commander.c
new file mode 100644
index 00000000..6317c41a
--- /dev/null
+++ b/games/samples/missile_commander.c
@@ -0,0 +1,539 @@
+/*******************************************************************************************
+*
+* raylib - sample game: missile commander
+*
+* 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 MAX_MISSILES 100
+#define MAX_INTERCEPTORS 30
+#define MAX_EXPLOSIONS 100
+#define LAUNCHERS_AMOUNT 3 // Not a variable, should not be changed
+#define BUILDINGS_AMOUNT 6 // Not a variable, should not be changed
+
+#define LAUNCHER_SIZE 80
+#define BUILDING_SIZE 60
+#define EXPLOSION_RADIUS 40
+
+#define MISSILE_SPEED 1
+#define MISSILE_LAUNCH_FRAMES 80
+#define INTERCEPTOR_SPEED 10
+#define EXPLOSION_INCREASE_TIME 90 // In frames
+#define EXPLOSION_TOTAL_TIME 210 // In frames
+
+#define EXPLOSION_COLOR (Color){ 125, 125, 125, 125 }
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct Missile {
+ Vector2 origin;
+ Vector2 position;
+ Vector2 objective;
+ Vector2 speed;
+
+ bool active;
+} Missile;
+
+typedef struct Interceptor {
+ Vector2 origin;
+ Vector2 position;
+ Vector2 objective;
+ Vector2 speed;
+
+ bool active;
+} Interceptor;
+
+typedef struct Explosion {
+ Vector2 position;
+ float radiusMultiplier;
+ int frame;
+ bool active;
+} Explosion;
+
+typedef struct Launcher {
+ Vector2 position;
+ bool active;
+} Launcher;
+
+typedef struct Building {
+ Vector2 position;
+ bool active;
+} Building;
+
+//------------------------------------------------------------------------------------
+// Global Variables Declaration
+//------------------------------------------------------------------------------------
+static int screenWidth = 800;
+static int screenHeight = 450;
+
+static int framesCounter = 0;
+static bool gameOver = false;
+static bool pause = false;
+static int score = 0;
+
+static Missile missile[MAX_MISSILES];
+static Interceptor interceptor[MAX_INTERCEPTORS];
+static Explosion explosion[MAX_EXPLOSIONS];
+static Launcher launcher[LAUNCHERS_AMOUNT];
+static Building building[BUILDINGS_AMOUNT];
+static int explosionIndex = 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)
+
+// Additional module functions
+static void UpdateOutgoingFire();
+static void UpdateIncomingFire();
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "sample game: missile commander");
+
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#endif
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadGame(); // Unload loaded data (textures, sounds, models...)
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------------------
+// Game Module Functions Definition
+//--------------------------------------------------------------------------------------
+
+// Initialize game variables
+void InitGame(void)
+{
+ // Initialize missiles
+ for (int i = 0; i < MAX_MISSILES; i++)
+ {
+ missile[i].origin = (Vector2){ 0, 0 };
+ missile[i].speed = (Vector2){ 0, 0 };
+ missile[i].position = (Vector2){ 0, 0 };
+
+ missile[i].active = false;
+ }
+
+ // Initialize interceptors
+ for (int i = 0; i < MAX_INTERCEPTORS; i++)
+ {
+ interceptor[i].origin = (Vector2){ 0, 0 };
+ interceptor[i].speed = (Vector2){ 0, 0 };
+ interceptor[i].position = (Vector2){ 0, 0 };
+
+ interceptor[i].active = false;
+ }
+
+ // Initialize explosions
+ for (int i = 0; i < MAX_EXPLOSIONS; i++)
+ {
+ explosion[i].position = (Vector2){ 0, 0 };
+ explosion[i].frame = 0;
+ explosion[i].active = false;
+ }
+
+ // Initialize buildings and launchers
+ int sparcing = screenWidth/(LAUNCHERS_AMOUNT + BUILDINGS_AMOUNT + 1);
+
+ // Buildings and launchers placing
+ launcher[0].position = (Vector2){ 1*sparcing, screenHeight - LAUNCHER_SIZE/2 };
+ building[0].position = (Vector2){ 2*sparcing, screenHeight - BUILDING_SIZE/2 };
+ building[1].position = (Vector2){ 3*sparcing, screenHeight - BUILDING_SIZE/2 };
+ building[2].position = (Vector2){ 4*sparcing, screenHeight - BUILDING_SIZE/2 };
+ launcher[1].position = (Vector2){ 5*sparcing, screenHeight - LAUNCHER_SIZE/2 };
+ building[3].position = (Vector2){ 6*sparcing, screenHeight - BUILDING_SIZE/2 };
+ building[4].position = (Vector2){ 7*sparcing, screenHeight - BUILDING_SIZE/2 };
+ building[5].position = (Vector2){ 8*sparcing, screenHeight - BUILDING_SIZE/2 };
+ launcher[2].position = (Vector2){ 9*sparcing, screenHeight - LAUNCHER_SIZE/2 };
+
+ // Buildings and launchers activation
+ for (int i = 0; i < LAUNCHERS_AMOUNT; i++) launcher[i].active = true;
+ for (int i = 0; i < BUILDINGS_AMOUNT; i++) building[i].active = true;
+
+ // Initialize game variables
+ score = 0;
+}
+
+// Update game (one frame)
+void UpdateGame(void)
+{
+ if (!gameOver)
+ {
+ if (IsKeyPressed('P')) pause = !pause;
+
+ if (!pause)
+ {
+ framesCounter++;
+
+ static
+ float distance;
+
+ // Interceptors update
+ for (int i = 0; i < MAX_INTERCEPTORS; i++)
+ {
+ if (interceptor[i].active)
+ {
+ // Update position
+ interceptor[i].position.x += interceptor[i].speed.x;
+ interceptor[i].position.y += interceptor[i].speed.y;
+
+ // Distance to objective
+ distance = sqrt( pow(interceptor[i].position.x - interceptor[i].objective.x, 2) +
+ pow(interceptor[i].position.y - interceptor[i].objective.y, 2));
+
+ if (distance < INTERCEPTOR_SPEED)
+ {
+ // Interceptor dissapears
+ interceptor[i].active = false;
+
+ // Explosion
+ explosion[explosionIndex].position = interceptor[i].position;
+ explosion[explosionIndex].active = true;
+ explosion[explosionIndex].frame = 0;
+ explosionIndex++;
+ if (explosionIndex == MAX_EXPLOSIONS) explosionIndex = 0;
+
+ break;
+ }
+ }
+ }
+
+ // Missiles update
+ for (int i = 0; i < MAX_MISSILES; i++)
+ {
+ if (missile[i].active)
+ {
+ // Update position
+ missile[i].position.x += missile[i].speed.x;
+ missile[i].position.y += missile[i].speed.y;
+
+ // Collision and missile out of bounds
+ if (missile[i].position.y > screenHeight) missile[i].active = false;
+ else
+ {
+ // CHeck collision with launchers
+ for (int j = 0; j < LAUNCHERS_AMOUNT; j++)
+ {
+ if (launcher[j].active)
+ {
+ if (CheckCollisionPointRec(missile[i].position, (Rectangle){ launcher[j].position.x - LAUNCHER_SIZE/2, launcher[j].position.y - LAUNCHER_SIZE/2,
+ LAUNCHER_SIZE, LAUNCHER_SIZE }))
+ {
+ // Missile dissapears
+ missile[i].active = false;
+
+ // Explosion and destroy building
+ launcher[j].active = false;
+
+ explosion[explosionIndex].position = missile[i].position;
+ explosion[explosionIndex].active = true;
+ explosion[explosionIndex].frame = 0;
+ explosionIndex++;
+ if (explosionIndex == MAX_EXPLOSIONS) explosionIndex = 0;
+
+ break;
+ }
+ }
+ }
+
+ // CHeck collision with buildings
+ for (int j = 0; j < BUILDINGS_AMOUNT; j++)
+ {
+ if (building[j].active)
+ {
+ if (CheckCollisionPointRec(missile[i].position, (Rectangle){ building[j].position.x - BUILDING_SIZE/2, building[j].position.y - BUILDING_SIZE/2,
+ BUILDING_SIZE, BUILDING_SIZE }))
+ {
+ // Missile dissapears
+ missile[i].active = false;
+
+ // Explosion and destroy building
+ building[j].active = false;
+
+ explosion[explosionIndex].position = missile[i].position;
+ explosion[explosionIndex].active = true;
+ explosion[explosionIndex].frame = 0;
+ explosionIndex++;
+ if (explosionIndex == MAX_EXPLOSIONS) explosionIndex = 0;
+
+ break;
+ }
+ }
+ }
+
+ // CHeck collision with explosions
+ for (int j = 0; j < MAX_EXPLOSIONS; j++)
+ {
+ if (explosion[j].active)
+ {
+ if (CheckCollisionPointCircle(missile[i].position, explosion[j].position, EXPLOSION_RADIUS*explosion[j].radiusMultiplier))
+ {
+ // Missile dissapears and we earn 100 points
+ missile[i].active = false;
+ score += 100;
+
+ explosion[explosionIndex].position = missile[i].position;
+ explosion[explosionIndex].active = true;
+ explosion[explosionIndex].frame = 0;
+ explosionIndex++;
+ if (explosionIndex == MAX_EXPLOSIONS) explosionIndex = 0;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Explosions update
+ for (int i = 0; i < MAX_EXPLOSIONS; i++)
+ {
+ if (explosion[i].active)
+ {
+ explosion[i].frame++;
+
+ if (explosion[i].frame <= EXPLOSION_INCREASE_TIME) explosion[i].radiusMultiplier = explosion[i].frame/(float)EXPLOSION_INCREASE_TIME;
+ else if (explosion[i].frame <= EXPLOSION_TOTAL_TIME) explosion[i].radiusMultiplier = 1 - (explosion[i].frame - (float)EXPLOSION_INCREASE_TIME)/(float)EXPLOSION_TOTAL_TIME;
+ else
+ {
+ explosion[i].frame = 0;
+ explosion[i].active = false;
+ }
+ }
+ }
+
+ // Fire logic
+ UpdateOutgoingFire();
+ UpdateIncomingFire();
+
+ // Game over logic
+ int checker = 0;
+
+ for (int i = 0; i < LAUNCHERS_AMOUNT; i++)
+ {
+ if (!launcher[i].active) checker++;
+ if (checker == LAUNCHERS_AMOUNT) gameOver = true;
+ }
+
+ checker = 0;
+ for (int i = 0; i < BUILDINGS_AMOUNT; i++)
+ {
+ if (!building[i].active) checker++;
+ if (checker == BUILDINGS_AMOUNT) gameOver = true;
+ }
+ }
+ }
+ else
+ {
+ if (IsKeyPressed(KEY_ENTER))
+ {
+ InitGame();
+ gameOver = false;
+ }
+ }
+}
+
+// Draw game (one frame)
+void DrawGame(void)
+{
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ if (!gameOver)
+ {
+ // Draw missiles
+ for (int i = 0; i < MAX_MISSILES; i++)
+ {
+ if (missile[i].active)
+ {
+ DrawLine(missile[i].origin.x, missile[i].origin.y, missile[i].position.x, missile[i].position.y, RED);
+
+ if (framesCounter % 16 < 8) DrawCircle(missile[i].position.x, missile[i].position.y, 3, YELLOW);
+ }
+ }
+
+ // Draw interceptors
+ for (int i = 0; i < MAX_INTERCEPTORS; i++)
+ {
+ if (interceptor[i].active)
+ {
+ DrawLine(interceptor[i].origin.x, interceptor[i].origin.y, interceptor[i].position.x, interceptor[i].position.y, GREEN);
+
+ if (framesCounter % 16 < 8) DrawCircle(interceptor[i].position.x, interceptor[i].position.y, 3, BLUE);
+ }
+ }
+
+ // Draw explosions
+ for (int i = 0; i < MAX_EXPLOSIONS; i++)
+ {
+ if (explosion[i].active) DrawCircle(explosion[i].position.x, explosion[i].position.y, EXPLOSION_RADIUS*explosion[i].radiusMultiplier, EXPLOSION_COLOR);
+ }
+
+ // Draw buildings and launchers
+ for (int i = 0; i < LAUNCHERS_AMOUNT; i++)
+ {
+ if (launcher[i].active) DrawRectangle(launcher[i].position.x - LAUNCHER_SIZE/2, launcher[i].position.y - LAUNCHER_SIZE/2, LAUNCHER_SIZE, LAUNCHER_SIZE, GRAY);
+ }
+
+ for (int i = 0; i < BUILDINGS_AMOUNT; i++)
+ {
+ if (building[i].active) DrawRectangle(building[i].position.x - BUILDING_SIZE/2, building[i].position.y - BUILDING_SIZE/2, BUILDING_SIZE, BUILDING_SIZE, LIGHTGRAY);
+ }
+
+ // Draw score
+ DrawText(FormatText("SCORE %4i", score), 20, 20, 40, LIGHTGRAY);
+
+ 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();
+}
+
+//--------------------------------------------------------------------------------------
+// Additional module functions
+//--------------------------------------------------------------------------------------
+static void UpdateOutgoingFire()
+{
+ static int interceptorNumber = 0;
+ int launcherShooting = 0;
+
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) launcherShooting = 1;
+ if (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) launcherShooting = 2;
+ if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) launcherShooting = 3;
+
+ if (launcherShooting > 0 && launcher[launcherShooting - 1].active)
+ {
+ float module;
+ float sideX;
+ float sideY;
+
+ // Activate the interceptor
+ interceptor[interceptorNumber].active = true;
+
+ // Assign start position
+ interceptor[interceptorNumber].origin = launcher[launcherShooting - 1].position;
+ interceptor[interceptorNumber].position = interceptor[interceptorNumber].origin;
+ interceptor[interceptorNumber].objective = GetMousePosition();
+
+ // Calculate speed
+ module = sqrt( pow(interceptor[interceptorNumber].objective.x - interceptor[interceptorNumber].origin.x, 2) +
+ pow(interceptor[interceptorNumber].objective.y - interceptor[interceptorNumber].origin.y, 2));
+
+ sideX = (interceptor[interceptorNumber].objective.x - interceptor[interceptorNumber].origin.x)*INTERCEPTOR_SPEED/module;
+ sideY = (interceptor[interceptorNumber].objective.y - interceptor[interceptorNumber].origin.y)*INTERCEPTOR_SPEED/module;
+
+ interceptor[interceptorNumber].speed = (Vector2){ sideX, sideY };
+
+ // Update
+ interceptorNumber++;
+ if (interceptorNumber == MAX_INTERCEPTORS) interceptorNumber = 0;
+ }
+}
+
+static void UpdateIncomingFire()
+{
+ static int missileIndex = 0;
+
+ // Launch missile
+ if (framesCounter % MISSILE_LAUNCH_FRAMES == 0)
+ {
+ float module;
+ float sideX;
+ float sideY;
+
+ // Activate the missile
+ missile[missileIndex].active = true;
+
+ // Assign start position
+ missile[missileIndex].origin = (Vector2){ GetRandomValue(20, screenWidth - 20), -10 };
+ missile[missileIndex].position = missile[missileIndex].origin;
+ missile[missileIndex].objective = (Vector2){ GetRandomValue(20, screenWidth - 20), screenHeight + 10 };
+
+ // Calculate speed
+ module = sqrt( pow(missile[missileIndex].objective.x - missile[missileIndex].origin.x, 2) +
+ pow(missile[missileIndex].objective.y - missile[missileIndex].origin.y, 2));
+
+ sideX = (missile[missileIndex].objective.x - missile[missileIndex].origin.x)*MISSILE_SPEED/module;
+ sideY = (missile[missileIndex].objective.y - missile[missileIndex].origin.y)*MISSILE_SPEED/module;
+
+ missile[missileIndex].speed = (Vector2){ sideX, sideY };
+
+ // Update
+ missileIndex++;
+ if (missileIndex == MAX_MISSILES) missileIndex = 0;
+ }
+} \ No newline at end of file
diff --git a/games/samples/pang.c b/games/samples/pang.c
new file mode 100644
index 00000000..e7b2bb86
--- /dev/null
+++ b/games/samples/pang.c
@@ -0,0 +1,692 @@
+/*******************************************************************************************
+*
+* raylib - sample game: pang
+*
+* Sample game developed by Ian Eito, Albert Martos 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 <math.h>
+
+#if defined(PLATFORM_WEB)
+ #include <emscripten/emscripten.h>
+#endif
+
+//----------------------------------------------------------------------------------
+// Some Defines
+//----------------------------------------------------------------------------------
+#define MAX_SPEED 5
+#define METEORS_SPEED 2
+#define NUM_SHOOTS 1
+#define NUM_BIG_METEORS 2
+#define NUM_MEDIUM_METEORS 4
+#define NUM_SMALL_METEORS 8
+#define SHIP_BASE_SIZE 20.0f
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+
+typedef struct Player {
+ Vector2 position;
+ Vector2 speed;
+ float rotation;
+ Vector3 collider;
+ Color color;
+} Player;
+
+typedef struct Shoot {
+ Vector2 position;
+ Vector2 speed;
+ float radius;
+ float rotation;
+ int lifeSpawn;
+ bool active;
+ Color color;
+} Shoot;
+
+typedef struct BigMeteor {
+ Vector2 position;
+ Vector2 speed;
+ float radius;
+ int points;
+ bool active;
+ Color color;
+} BigMeteor;
+
+typedef struct MediumMeteor {
+ Vector2 position;
+ Vector2 speed;
+ float radius;
+ int points;
+ bool active;
+ Color color;
+} MediumMeteor;
+
+typedef struct SmallMeteor {
+ Vector2 position;
+ Vector2 speed;
+ float radius;
+ int points;
+ bool active;
+ Color color;
+} SmallMeteor;
+
+typedef struct Points {
+ char letter;
+ Vector2 position;
+ int value;
+ Color color;
+ float alpha;
+} Points;
+
+//------------------------------------------------------------------------------------
+// Global Variables Declaration
+//------------------------------------------------------------------------------------
+static int screenWidth = 800;
+static int screenHeight = 450;
+
+static int framesCounter;
+static bool gameOver;
+static bool pause;
+static int score;
+
+static Player player;
+static Shoot shoot[NUM_SHOOTS];
+static BigMeteor bigMeteor[NUM_BIG_METEORS];
+static MediumMeteor mediumMeteor[NUM_MEDIUM_METEORS];
+static SmallMeteor smallMeteor[NUM_SMALL_METEORS];
+static Points points[5];
+
+// NOTE: Defined triangle is isosceles with common angles of 70 degrees.
+static float shipHeight;
+static float gravity;
+
+static int countMediumMeteors;
+static int countSmallMeteors;
+static int meteorsDestroyed;
+static Vector2 linePosition;
+
+static bool victory;
+static bool lose;
+static bool awake;
+
+//------------------------------------------------------------------------------------
+// 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)
+
+static void InitShoot(Shoot shoot);
+static void DrawSpaceship(Vector2 position, float rotation, Color color);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+ InitWindow(screenWidth, screenHeight, "sample game: pang");
+
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#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
+static void InitGame(void)
+{
+ int posx, posy;
+ int velx = 0;
+ int vely = 0;
+
+ framesCounter = 0;
+ gameOver = false;
+ pause = false;
+ score = 0;
+
+ victory = false;
+ lose = false;
+ awake = true;
+ gravity = 0.25f;
+
+ linePosition = (Vector2){ 0.0f , 0.0f };
+ shipHeight = (SHIP_BASE_SIZE/2)/tanf(20*DEG2RAD);
+
+ // Initialization player
+ player.position = (Vector2){ screenWidth/2, screenHeight };
+ player.speed = (Vector2){ MAX_SPEED, MAX_SPEED };
+ player.rotation = 0;
+ player.collider = (Vector3){ player.position.x, player.position.y - shipHeight/2.0f, 12.0f };
+ player.color = LIGHTGRAY;
+
+ meteorsDestroyed = 0;
+
+ // Initialize shoots
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ shoot[i].position = (Vector2){ 0, 0 };
+ shoot[i].speed = (Vector2){ 0, 0 };
+ shoot[i].radius = 2;
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ shoot[i].color = WHITE;
+ }
+
+ // Initialize big meteors
+ for (int i = 0; i < NUM_BIG_METEORS; i++)
+ {
+ bigMeteor[i].radius = 40.0f;
+ posx = GetRandomValue(0 + bigMeteor[i].radius, screenWidth - bigMeteor[i].radius);
+ posy = GetRandomValue(0 + bigMeteor[i].radius, screenHeight/2);
+
+ bigMeteor[i].position = (Vector2){ posx, posy };
+
+ while ((velx == 0) || (vely == 0))
+ {
+ velx = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ vely = GetRandomValue(-METEORS_SPEED, METEORS_SPEED);
+ }
+
+ bigMeteor[i].speed = (Vector2){ velx, vely };
+ bigMeteor[i].points = 200;
+ bigMeteor[i].active = true;
+ bigMeteor[i].color = BLUE;
+ }
+
+ // Initialize medium meteors
+ for (int i = 0; i < NUM_MEDIUM_METEORS; i++)
+ {
+ mediumMeteor[i].position = (Vector2){-100, -100};
+ mediumMeteor[i].speed = (Vector2){0,0};
+ mediumMeteor[i].radius = 20.0f;
+ mediumMeteor[i].points = 100;
+ mediumMeteor[i].active = false;
+ mediumMeteor[i].color = BLUE;
+ }
+
+ // Initialize small meteors
+ for (int i = 0; i < NUM_SMALL_METEORS; i++)
+ {
+ smallMeteor[i].position = (Vector2){ -100, -100 };
+ smallMeteor[i].speed = (Vector2){ 0, 0 };
+ smallMeteor[i].radius = 10.0f;
+ smallMeteor[i].points = 50;
+ smallMeteor[i].active = false;
+ smallMeteor[i].color = BLUE;
+ }
+
+ // Initialize animated points
+ for (int i = 0; i < 5; i++)
+ {
+ points[i].position = (Vector2){ 0, 0 };
+ points[i].value = 0;
+ points[i].alpha = 0.0f;
+ }
+
+ countMediumMeteors = 0;
+ countSmallMeteors = 0;
+}
+
+// Update game (one frame)
+void UpdateGame(void)
+{
+ if (!gameOver)
+ {
+ if (IsKeyPressed('P')) pause = !pause;
+
+ if (!pause)
+ {
+ if (awake)
+ {
+ // Player logic
+ if (IsKeyDown(KEY_LEFT)) player.position.x -= player.speed.x;
+ if (IsKeyDown(KEY_RIGHT)) player.position.x += player.speed.x;
+
+ // Wall behaviour for player
+ if (player.position.x + SHIP_BASE_SIZE/2 > screenWidth) player.position.x = screenWidth - SHIP_BASE_SIZE/2;
+ else if (player.position.x - SHIP_BASE_SIZE/2 < 0) player.position.x = 0 + SHIP_BASE_SIZE/2;
+
+ // Activation of shoot
+ if (IsKeyPressed(KEY_SPACE))
+ {
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (!shoot[i].active)
+ {
+ shoot[i].position = (Vector2){ player.position.x, player.position.y - shipHeight };
+ linePosition = (Vector2){ player.position.x, player.position.y};
+ shoot[i].active = true;
+ shoot[i].speed.y = MAX_SPEED;
+ break;
+ }
+ }
+ }
+
+ // Shoot life timer
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (shoot[i].active) shoot[i].lifeSpawn++;
+ }
+
+ // Shot logic
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (shoot[i].active)
+ {
+ // Movement
+ shoot[i].position.y -= shoot[i].speed.y;
+
+ // Wall behaviour for shoot
+ if (shoot[i].position.x > screenWidth + shoot[i].radius)
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ }
+ else if (shoot[i].position.x < 0 - shoot[i].radius)
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ }
+
+ if (shoot[i].position.y > screenHeight + shoot[i].radius)
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ }
+ else if (shoot[i].position.y < 0 - shoot[i].radius)
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ }
+
+ // Life of shoot
+ if (shoot[i].lifeSpawn >= 120)
+ {
+ shoot[i].position = (Vector2){0, 0};
+ shoot[i].speed = (Vector2){0, 0};
+ shoot[i].lifeSpawn = 0;
+ shoot[i].active = false;
+ }
+ }
+ }
+
+ // Player collision with meteors
+ player.collider = (Vector3){player.position.x, player.position.y - shipHeight/2, 12};
+
+ for (int i = 0; i < NUM_BIG_METEORS; i++)
+ {
+ if (CheckCollisionCircles((Vector2){ player.collider.x, player.collider.y }, player.collider.z, bigMeteor[i].position, bigMeteor[i].radius) && bigMeteor[i].active)
+ {
+ gameOver = true;
+ }
+ }
+
+ for (int i = 0; i < NUM_MEDIUM_METEORS; i++)
+ {
+ if (CheckCollisionCircles((Vector2){ player.collider.x, player.collider.y }, player.collider.z, mediumMeteor[i].position, mediumMeteor[i].radius) && mediumMeteor[i].active)
+ {
+ gameOver = true;
+ }
+ }
+
+ for (int i = 0; i < NUM_SMALL_METEORS; i++)
+ {
+ if (CheckCollisionCircles((Vector2){ player.collider.x, player.collider.y }, player.collider.z, smallMeteor[i].position, smallMeteor[i].radius) && smallMeteor[i].active)
+ {
+ gameOver = true;
+ }
+ }
+
+ // Meteor logic
+ for (int i = 0; i < NUM_BIG_METEORS; i++)
+ {
+ if (bigMeteor[i].active)
+ {
+ // movement
+ bigMeteor[i].position.x += bigMeteor[i].speed.x;
+ bigMeteor[i].position.y += bigMeteor[i].speed.y;
+
+ // wall behaviour
+ if (((bigMeteor[i].position.x + bigMeteor[i].radius) >= screenWidth) || ((bigMeteor[i].position.x - bigMeteor[i].radius) <= 0)) bigMeteor[i].speed.x *= -1;
+ if ((bigMeteor[i].position.y - bigMeteor[i].radius) <= 0) bigMeteor[i].speed.y *= -1.5;
+
+ if ((bigMeteor[i].position.y + bigMeteor[i].radius) >= screenHeight)
+ {
+ bigMeteor[i].speed.y *= -1;
+ bigMeteor[i].position.y = screenHeight - bigMeteor[i].radius;
+ }
+
+ bigMeteor[i].speed.y += gravity;
+ }
+ }
+
+ for (int i = 0; i < NUM_MEDIUM_METEORS; i++)
+ {
+ if (mediumMeteor[i].active)
+ {
+ // Movement logic
+ mediumMeteor[i].position.x += mediumMeteor[i].speed.x;
+ mediumMeteor[i].position.y += mediumMeteor[i].speed.y;
+
+ // Wall behaviour
+ if (mediumMeteor[i].position.x + mediumMeteor[i].radius >= screenWidth || mediumMeteor[i].position.x - mediumMeteor[i].radius <= 0) mediumMeteor[i].speed.x *= -1;
+ if (mediumMeteor[i].position.y - mediumMeteor[i].radius <= 0) mediumMeteor[i].speed.y *= -1;
+ if (mediumMeteor[i].position.y + mediumMeteor[i].radius >= screenHeight)
+ {
+ mediumMeteor[i].speed.y *= -1;
+ mediumMeteor[i].position.y = screenHeight - mediumMeteor[i].radius;
+ }
+
+ mediumMeteor[i].speed.y += gravity + 0.12f;
+ }
+ }
+
+ for (int i = 0; i < NUM_SMALL_METEORS; i++)
+ {
+ if (smallMeteor[i].active)
+ {
+ // movement
+ smallMeteor[i].position.x += smallMeteor[i].speed.x;
+ smallMeteor[i].position.y += smallMeteor[i].speed.y;
+
+ // wall behaviour
+ if (smallMeteor[i].position.x + smallMeteor[i].radius >= screenWidth || smallMeteor[i].position.x - smallMeteor[i].radius <= 0) smallMeteor[i].speed.x *= -1;
+ if (smallMeteor[i].position.y - smallMeteor[i].radius <= 0) smallMeteor[i].speed.y *= -1;
+ if (smallMeteor[i].position.y + smallMeteor[i].radius >= screenHeight)
+ {
+ smallMeteor[i].speed.y *= -1;
+ smallMeteor[i].position.y = screenHeight - smallMeteor[i].radius;
+ }
+
+ smallMeteor[i].speed.y += gravity + 0.25f;
+ }
+ }
+
+ // Collision behaviour
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if ((shoot[i].active))
+ {
+ for (int a = 0; a < NUM_BIG_METEORS; a++)
+ {
+ if (bigMeteor[a].active && (bigMeteor[a].position.x - bigMeteor[a].radius <= linePosition.x && bigMeteor[a].position.x + bigMeteor[a].radius >= linePosition.x)
+ && (bigMeteor[a].position.y + bigMeteor[a].radius >= shoot[i].position.y))
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ bigMeteor[a].active = false;
+ meteorsDestroyed++;
+ score += bigMeteor[a].points;
+
+ for (int z = 0; z < 5; z++)
+ {
+ if (points[z].alpha == 0.0f)
+ {
+ points[z].position = bigMeteor[a].position;
+ points[z].value = bigMeteor[a].points;
+ points[z].color = RED;
+ points[z].alpha = 1.0f;
+ z = 5;
+ }
+ }
+
+ for (int j = 0; j < 2; j ++)
+ {
+ if ((countMediumMeteors%2) == 0)
+ {
+ mediumMeteor[countMediumMeteors].position = (Vector2){bigMeteor[a].position.x, bigMeteor[a].position.y};
+ mediumMeteor[countMediumMeteors].speed = (Vector2){METEORS_SPEED*-1, METEORS_SPEED};
+ }
+ else
+ {
+ mediumMeteor[countMediumMeteors].position = (Vector2){bigMeteor[a].position.x, bigMeteor[a].position.y};
+ mediumMeteor[countMediumMeteors].speed = (Vector2){METEORS_SPEED, METEORS_SPEED};
+ }
+
+ mediumMeteor[countMediumMeteors].active = true;
+ countMediumMeteors ++;
+ }
+
+ bigMeteor[a].color = RED;
+ a = NUM_BIG_METEORS;
+ }
+ }
+ }
+
+ if ((shoot[i].active))
+ {
+ for (int b = 0; b < NUM_MEDIUM_METEORS; b++)
+ {
+ if (mediumMeteor[b].active && (mediumMeteor[b].position.x - mediumMeteor[b].radius <= linePosition.x && mediumMeteor[b].position.x + mediumMeteor[b].radius >= linePosition.x)
+ && (mediumMeteor[b].position.y + mediumMeteor[b].radius >= shoot[i].position.y))
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ mediumMeteor[b].active = false;
+ meteorsDestroyed++;
+ score += mediumMeteor[b].points;
+
+ for (int z = 0; z < 5; z++)
+ {
+ if (points[z].alpha == 0.0f)
+ {
+ points[z].position = mediumMeteor[b].position;
+ points[z].value = mediumMeteor[b].points;
+ points[z].color = GREEN;
+ points[z].alpha = 1.0f;
+ z = 5;
+ }
+ }
+
+ for (int j = 0; j < 2; j ++)
+ {
+ if (countSmallMeteors%2 == 0)
+ {
+ smallMeteor[countSmallMeteors].position = (Vector2){mediumMeteor[b].position.x, mediumMeteor[b].position.y};
+ smallMeteor[countSmallMeteors].speed = (Vector2){METEORS_SPEED*-1, METEORS_SPEED*-1};
+ }
+ else
+ {
+ smallMeteor[countSmallMeteors].position = (Vector2){mediumMeteor[b].position.x, mediumMeteor[b].position.y};
+ smallMeteor[countSmallMeteors].speed = (Vector2){METEORS_SPEED, METEORS_SPEED*-1};
+ }
+
+ smallMeteor[countSmallMeteors].active = true;
+ countSmallMeteors ++;
+ }
+ mediumMeteor[b].color = GREEN;
+ b = NUM_MEDIUM_METEORS;
+ }
+ }
+ }
+
+ if ((shoot[i].active))
+ {
+ for (int c = 0; c < NUM_SMALL_METEORS; c++)
+ {
+ if (smallMeteor[c].active && (smallMeteor[c].position.x - smallMeteor[c].radius <= linePosition.x && smallMeteor[c].position.x + smallMeteor[c].radius >= linePosition.x)
+ && (smallMeteor[c].position.y + smallMeteor[c].radius >= shoot[i].position.y))
+ {
+ shoot[i].active = false;
+ shoot[i].lifeSpawn = 0;
+ smallMeteor[c].active = false;
+ meteorsDestroyed++;
+ smallMeteor[c].color = YELLOW;
+ score += smallMeteor[c].points;
+
+ for (int z = 0; z < 5; z++)
+ {
+ if (points[z].alpha == 0.0f)
+ {
+ points[z].position = smallMeteor[c].position;
+ points[z].value = smallMeteor[c].points;
+ points[z].color = YELLOW;
+ points[z].alpha = 1.0f;
+ z = 5;
+ }
+ }
+
+ c = NUM_SMALL_METEORS;
+ }
+ }
+ }
+ }
+
+ for (int z = 0; z < 5; z++)
+ {
+ if (points[z].alpha > 0.0f)
+ {
+ points[z].position.y -= 2;
+ points[z].alpha -= 0.02f;
+ }
+
+ if (points[z].alpha < 0.0f) points[z].alpha = 0.0f;
+ }
+
+ if (meteorsDestroyed == (NUM_BIG_METEORS + NUM_MEDIUM_METEORS + NUM_SMALL_METEORS)) victory = true;
+ }
+ else
+ {
+ framesCounter++;
+ if (framesCounter%180 == 0) awake = false;
+ }
+ }
+ }
+ else
+ {
+ if (IsKeyPressed(KEY_ENTER))
+ {
+ InitGame();
+ gameOver = false;
+ }
+ }
+}
+
+// Draw game (one frame)
+void DrawGame(void)
+{
+ BeginDrawing();
+
+ ClearBackground(DARKGRAY);
+
+ if (!gameOver)
+ {
+ // Draw player
+ Vector2 v1 = { player.position.x + sinf(player.rotation*DEG2RAD)*(shipHeight), player.position.y - cosf(player.rotation*DEG2RAD)*(shipHeight) };
+ Vector2 v2 = { player.position.x - cosf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2), player.position.y - sinf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2) };
+ Vector2 v3 = { player.position.x + cosf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2), player.position.y + sinf(player.rotation*DEG2RAD)*(SHIP_BASE_SIZE/2) };
+ DrawTriangleLines(v1, v2, v3, player.color);
+
+ // Draw meteor
+ for (int i = 0;i < NUM_BIG_METEORS; i++)
+ {
+ if (bigMeteor[i].active) DrawCircleV(bigMeteor[i].position, bigMeteor[i].radius, bigMeteor[i].color);
+ else
+ {
+ DrawCircleV(bigMeteor[i].position, bigMeteor[i].radius, Fade(bigMeteor[i].color, 0.25f));
+ //DrawText(FormatText("%i", bigMeteor[i].points), bigMeteor[i].position.x - MeasureText("200", 20)/2, bigMeteor[i].position.y - 10, 20, Fade(WHITE, 0.25f));
+ }
+ }
+
+ for (int i = 0;i < NUM_MEDIUM_METEORS; i++)
+ {
+ if (mediumMeteor[i].active) DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, mediumMeteor[i].color);
+ else
+ {
+ DrawCircleV(mediumMeteor[i].position, mediumMeteor[i].radius, Fade(mediumMeteor[i].color, 0.25f));
+ //DrawText(FormatText("%i", mediumMeteor[i].points), mediumMeteor[i].position.x - MeasureText("100", 20)/2, mediumMeteor[i].position.y - 10, 20, Fade(WHITE, 0.25f));
+ }
+ }
+
+ for (int i = 0;i < NUM_SMALL_METEORS; i++)
+ {
+ if (smallMeteor[i].active) DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, smallMeteor[i].color);
+ else
+ {
+ DrawCircleV(smallMeteor[i].position, smallMeteor[i].radius, Fade(smallMeteor[i].color, 0.25f));
+ //DrawText(FormatText("%i", smallMeteor[i].points), smallMeteor[i].position.x - MeasureText("50", 10)/2, smallMeteor[i].position.y - 5, 10, Fade(WHITE, 0.25f));
+ }
+ }
+
+ // Draw shoot
+
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (shoot[i].active) DrawLine(linePosition.x, linePosition.y, shoot[i].position.x, shoot[i].position.y, RED);
+ }
+
+ for (int z = 0; z < 5; z++)
+ {
+ if (points[z].alpha > 0.0f)
+ {
+ DrawText(FormatText("+%i", points[z].value), points[z].position.x, points[z].position.y, 20, Fade(points[z].color, points[z].alpha));
+ }
+ }
+
+ // Draw Text
+ DrawText(FormatText("SCORE: %i", score), 10, 10, 20, LIGHTGRAY);
+
+ if (victory) DrawText("VICTORY", screenWidth/2 - MeasureText("VICTORY", 40)/2, screenHeight/2 - 40, 40, LIGHTGRAY);
+
+ if (pause) DrawText("GAME PAUSED", screenWidth/2 - MeasureText("GAME PAUSED", 40)/2, screenHeight/2 - 40, 40, LIGHTGRAY);
+ }
+ else DrawText("PRESS [ENTER] TO PLAY AGAIN", GetScreenWidth()/2 - MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20)/2, GetScreenHeight()/2 - 50, 20, LIGHTGRAY);
+
+ 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();
+} \ No newline at end of file
diff --git a/games/samples/snake.c b/games/samples/snake.c
new file mode 100644
index 00000000..ac2f6132
--- /dev/null
+++ b/games/samples/snake.c
@@ -0,0 +1,293 @@
+/*******************************************************************************************
+*
+* raylib - sample game: snake
+*
+* Sample game developed by Ian Eito, Albert Martos 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"
+
+#if defined(PLATFORM_WEB)
+ #include <emscripten/emscripten.h>
+#endif
+
+//----------------------------------------------------------------------------------
+// Some Defines
+//----------------------------------------------------------------------------------
+#define SNAKE_LENGTH 256
+#define SQUARE_SIZE 31
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct Snake {
+ Vector2 position;
+ Vector2 size;
+ Vector2 speed;
+ Color color;
+} Snake;
+
+typedef struct Food {
+ Vector2 position;
+ Vector2 size;
+ bool active;
+ Color color;
+} Food;
+
+//------------------------------------------------------------------------------------
+// Global Variables Declaration
+//------------------------------------------------------------------------------------
+static int screenWidth = 800;
+static int screenHeight = 450;
+
+static int framesCounter;
+static bool gameOver;
+static bool pause;
+
+static Food fruit;
+static Snake snake[SNAKE_LENGTH];
+static Vector2 snakePosition[SNAKE_LENGTH];
+static bool allowMove;
+static Vector2 offset;
+static int counterTail;
+
+//------------------------------------------------------------------------------------
+// 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()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "sample game: snake");
+
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#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)
+{
+ framesCounter = 0;
+ gameOver = false;
+ pause = false;
+
+ counterTail = 1;
+ allowMove = false;
+
+ offset.x = screenWidth%SQUARE_SIZE;
+ offset.y = screenHeight%SQUARE_SIZE;
+
+ for (int i = 0; i < SNAKE_LENGTH; i++)
+ {
+ snake[i].position = (Vector2){ offset.x/2, offset.y/2 };
+ snake[i].size = (Vector2){ SQUARE_SIZE, SQUARE_SIZE };
+ snake[i].speed = (Vector2){ SQUARE_SIZE, 0 };
+
+ if (i == 0) snake[i].color = DARKBLUE;
+ else snake[i].color = BLUE;
+ }
+
+ for (int i = 0; i < SNAKE_LENGTH; i++)
+ {
+ snakePosition[i] = (Vector2){ 0.0f, 0.0f };
+ }
+
+ fruit.size = (Vector2){ SQUARE_SIZE, SQUARE_SIZE };
+ fruit.color = SKYBLUE;
+ fruit.active = false;
+}
+
+// Update game (one frame)
+void UpdateGame(void)
+{
+ if (!gameOver)
+ {
+ if (IsKeyPressed('P')) pause = !pause;
+
+ if (!pause)
+ {
+ // control
+ if (IsKeyPressed(KEY_RIGHT) && (snake[0].speed.x == 0) && allowMove)
+ {
+ snake[0].speed = (Vector2){ SQUARE_SIZE, 0 };
+ allowMove = false;
+ }
+ if (IsKeyPressed(KEY_LEFT) && (snake[0].speed.x == 0) && allowMove)
+ {
+ snake[0].speed = (Vector2){ -SQUARE_SIZE, 0 };
+ allowMove = false;
+ }
+ if (IsKeyPressed(KEY_UP) && (snake[0].speed.y == 0) && allowMove)
+ {
+ snake[0].speed = (Vector2){ 0, -SQUARE_SIZE };
+ allowMove = false;
+ }
+ if (IsKeyPressed(KEY_DOWN) && (snake[0].speed.y == 0) && allowMove)
+ {
+ snake[0].speed = (Vector2){ 0, SQUARE_SIZE };
+ allowMove = false;
+ }
+
+ // movement
+ for (int i = 0; i < counterTail; i++) snakePosition[i] = snake[i].position;
+
+ if ((framesCounter%5) == 0)
+ {
+ for (int i = 0; i < counterTail; i++)
+ {
+ if (i == 0)
+ {
+ snake[0].position.x += snake[0].speed.x;
+ snake[0].position.y += snake[0].speed.y;
+ allowMove = true;
+ }
+ else snake[i].position = snakePosition[i-1];
+ }
+ }
+
+ // wall behaviour
+ if (((snake[0].position.x) > (screenWidth - offset.x)) ||
+ ((snake[0].position.y) > (screenHeight - offset.y)) ||
+ (snake[0].position.x < 0) || (snake[0].position.y < 0))
+ {
+ gameOver = true;
+ }
+
+ // collision with yourself
+ for (int i = 1; i < counterTail; i++)
+ {
+ if ((snake[0].position.x == snake[i].position.x) && (snake[0].position.y == snake[i].position.y)) gameOver = true;
+ }
+
+ // TODO: review logic: fruit.position calculation
+ if (!fruit.active)
+ {
+ fruit.active = true;
+ fruit.position = (Vector2){ GetRandomValue(0, (screenWidth/SQUARE_SIZE) - 1)*SQUARE_SIZE + offset.x/2, GetRandomValue(0, (screenHeight/SQUARE_SIZE) - 1)*SQUARE_SIZE + offset.y/2 };
+
+ for (int i = 0; i < counterTail; i++)
+ {
+ while ((fruit.position.x == snake[i].position.x) && (fruit.position.y == snake[i].position.y))
+ {
+ fruit.position = (Vector2){ GetRandomValue(0, (screenWidth/SQUARE_SIZE) - 1)*SQUARE_SIZE, GetRandomValue(0, (screenHeight/SQUARE_SIZE) - 1)*SQUARE_SIZE };
+ i = 0;
+ }
+ }
+ }
+
+ // collision
+ if (CheckCollisionRecs((Rectangle){(int)snake[0].position.x, (int)snake[0].position.y, (int)snake[0].size.x, (int)snake[0].size.y},
+ (Rectangle){(int)fruit.position.x, (int)fruit.position.y, (int)fruit.size.x, (int)fruit.size.y}))
+ {
+ snake[counterTail].position = snakePosition[counterTail - 1];
+ counterTail += 1;
+ fruit.active = false;
+ }
+
+ framesCounter++;
+ }
+ }
+ else
+ {
+ if (IsKeyPressed(KEY_ENTER))
+ {
+ InitGame();
+ gameOver = false;
+ }
+ }
+}
+
+// Draw game (one frame)
+void DrawGame(void)
+{
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ if (!gameOver)
+ {
+ // Draw grid lines
+ for (int i = 0; i < screenWidth/SQUARE_SIZE + 1; i++)
+ {
+ DrawLineV((Vector2){SQUARE_SIZE*i + offset.x/2, offset.y/2}, (Vector2){SQUARE_SIZE*i + offset.x/2, screenHeight - offset.y/2}, LIGHTGRAY);
+ }
+
+ for (int i = 0; i < screenHeight/SQUARE_SIZE + 1; i++)
+ {
+ DrawLineV((Vector2){offset.x/2, SQUARE_SIZE*i + offset.y/2}, (Vector2){screenWidth - offset.x/2, SQUARE_SIZE*i + offset.y/2}, LIGHTGRAY);
+ }
+
+ // Draw snake
+ for (int i = 0; i < counterTail; i++) DrawRectangleV(snake[i].position, snake[i].size, snake[i].color);
+
+ // Draw fruit to pick
+ DrawRectangleV(fruit.position, fruit.size, fruit.color);
+
+ 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();
+} \ No newline at end of file
diff --git a/games/samples/space_invaders.c b/games/samples/space_invaders.c
new file mode 100644
index 00000000..9f380628
--- /dev/null
+++ b/games/samples/space_invaders.c
@@ -0,0 +1,407 @@
+/*******************************************************************************************
+*
+* raylib - sample game: space invaders
+*
+* Sample game developed by Ian Eito, Albert Martos 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"
+
+#if defined(PLATFORM_WEB)
+ #include <emscripten/emscripten.h>
+#endif
+
+//----------------------------------------------------------------------------------
+// Some Defines
+//----------------------------------------------------------------------------------
+#define NUM_SHOOTS 50
+#define NUM_MAX_ENEMIES 50
+#define FIRST_WAVE 10
+#define SECOND_WAVE 20
+#define THIRD_WAVE 50
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef enum { FIRST = 0, SECOND, THIRD } enemyWave;
+
+typedef struct Player{
+ Rectangle rec;
+ Vector2 speed;
+ Color color;
+} Player;
+
+typedef struct Enemy{
+ Rectangle rec;
+ Vector2 speed;
+ bool active;
+ Color color;
+} Enemy;
+
+typedef struct Shoot{
+ Rectangle rec;
+ Vector2 speed;
+ bool active;
+ Color color;
+} Shoot;
+
+//------------------------------------------------------------------------------------
+// Global Variables Declaration
+//------------------------------------------------------------------------------------
+static int screenWidth = 800;
+static int screenHeight = 450;
+
+static int framesCounter;
+static bool gameOver;
+static bool pause;
+static int score;
+static bool victory;
+
+static Player player;
+static Enemy enemy[NUM_MAX_ENEMIES];
+static Shoot shoot[NUM_SHOOTS];
+static enemyWave wave;
+
+static int shootRate;
+static float alpha;
+
+static int activeEnemies;
+static int enemiesKill;
+static bool smooth;
+
+//------------------------------------------------------------------------------------
+// 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()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "sample game: space invaders");
+
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#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)
+{
+ // Initialize game variables
+ shootRate = 0;
+ pause = false;
+ gameOver = false;
+ victory = false;
+ smooth = false;
+ wave = FIRST;
+ activeEnemies = FIRST_WAVE;
+ enemiesKill = 0;
+ score = 0;
+ alpha = 0;
+
+ // Initialize player
+ player.rec.x = 20;
+ player.rec.y = 50;
+ player.rec.width = 10;
+ player.rec.height = 10;
+ player.speed.x = 5;
+ player.speed.y = 5;
+ player.color = BLACK;
+
+ // Initialize enemies
+ for (int i = 0; i < NUM_MAX_ENEMIES; i++)
+ {
+ enemy[i].rec.width = 10;
+ enemy[i].rec.height = 10;
+ enemy[i].rec.x = GetRandomValue(screenWidth, screenWidth + 1000);
+ enemy[i].rec.y = GetRandomValue(0, screenHeight - enemy[i].rec.height);
+ enemy[i].speed.x = 5;
+ enemy[i].speed.y = 5;
+ enemy[i].active = true;
+ enemy[i].color = DARKGRAY;
+ }
+
+ // Initialize shoots
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ shoot[i].rec.x = player.rec.x;
+ shoot[i].rec.y = player.rec.y + player.rec.height/4;
+ shoot[i].rec.width = 10;
+ shoot[i].rec.height = 5;
+ shoot[i].speed.x = 7;
+ shoot[i].speed.y = 0;
+ shoot[i].active = false;
+ shoot[i].color = WHITE;
+ }
+}
+
+// Update game (one frame)
+void UpdateGame(void)
+{
+ if (!gameOver)
+ {
+ if (IsKeyPressed('P')) pause = !pause;
+
+ if (!pause)
+ {
+ switch (wave)
+ {
+ case FIRST:
+ {
+ if (!smooth)
+ {
+ alpha += 0.02f;
+
+ if (alpha >= 1.0f) smooth = true;
+ }
+
+ if (smooth) alpha -= 0.02f;
+
+ if (enemiesKill == activeEnemies)
+ {
+ enemiesKill = 0;
+
+ for (int i = 0; i < activeEnemies; i++)
+ {
+ if (!enemy[i].active) enemy[i].active = true;
+ }
+
+ activeEnemies = SECOND_WAVE;
+ wave = SECOND;
+ smooth = false;
+ alpha = 0.0f;
+ }
+ } break;
+ case SECOND:
+ {
+ if (!smooth)
+ {
+ alpha += 0.02f;
+
+ if (alpha >= 1.0f) smooth = true;
+ }
+
+ if (smooth) alpha -= 0.02f;
+
+ if (enemiesKill == activeEnemies)
+ {
+ enemiesKill = 0;
+
+ for (int i = 0; i < activeEnemies; i++)
+ {
+ if (!enemy[i].active) enemy[i].active = true;
+ }
+
+ activeEnemies = THIRD_WAVE;
+ wave = THIRD;
+ smooth = false;
+ alpha = 0.0f;
+ }
+ } break;
+ case THIRD:
+ {
+ if (!smooth)
+ {
+ alpha += 0.02f;
+
+ if (alpha >= 1.0f) smooth = true;
+ }
+
+ if (smooth) alpha -= 0.02f;
+
+ if (enemiesKill == activeEnemies) victory = true;
+
+ } break;
+ default: break;
+ }
+
+ // Player movement
+ if (IsKeyDown(KEY_RIGHT)) player.rec.x += player.speed.x;
+ if (IsKeyDown(KEY_LEFT)) player.rec.x -= player.speed.x;
+ if (IsKeyDown(KEY_UP)) player.rec.y -= player.speed.y;
+ if (IsKeyDown(KEY_DOWN)) player.rec.y += player.speed.y;
+
+ // Player collision with enemy
+ for (int i = 0; i < activeEnemies; i++)
+ {
+ if (CheckCollisionRecs(player.rec, enemy[i].rec)) gameOver = true;
+ }
+
+ // Enemy behaviour
+ for (int i = 0; i < activeEnemies; i++)
+ {
+ if (enemy[i].active)
+ {
+ enemy[i].rec.x -= enemy[i].speed.x;
+
+ if (enemy[i].rec.x < 0)
+ {
+ enemy[i].rec.x = GetRandomValue(screenWidth, screenWidth + 1000);
+ enemy[i].rec.y = GetRandomValue(0, screenHeight - enemy[i].rec.height);
+ }
+ }
+ }
+
+ // Wall behaviour
+ if (player.rec.x <= 0) player.rec.x = 0;
+ if (player.rec.x + player.rec.width >= screenWidth) player.rec.x = screenWidth - player.rec.width;
+ if (player.rec.y <= 0) player.rec.y = 0;
+ if (player.rec.y + player.rec.height >= screenHeight) player.rec.y = screenHeight - player.rec.height;
+
+ //Shoot initialization
+ if (IsKeyDown(KEY_SPACE))
+ {
+ shootRate += 5;
+
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (!shoot[i].active && shootRate%20 == 0)
+ {
+ shoot[i].rec.x = player.rec.x;
+ shoot[i].rec.y = player.rec.y + player.rec.height/4;
+ shoot[i].active = true;
+ break;
+ }
+ }
+ }
+
+ // Shoot logic
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (shoot[i].active)
+ {
+ // Movement
+ shoot[i].rec.x += shoot[i].speed.x;
+
+ // Collision with enemy
+ for (int j = 0; j < activeEnemies; j++)
+ {
+ if (enemy[j].active)
+ {
+ if (CheckCollisionRecs(shoot[i].rec, enemy[j].rec))
+ {
+ shoot[i].active = false;
+ enemy[j].active = false;
+ enemy[j].rec.x = GetRandomValue(screenWidth, screenWidth + 1000);
+ enemy[j].rec.y = GetRandomValue(0, screenHeight - enemy[j].rec.height);
+ shootRate = 0;
+ enemiesKill++;
+ score += 100;
+ }
+
+ if (shoot[i].rec.x + shoot[i].rec.width >= screenWidth)
+ {
+ shoot[i].active = false;
+ shootRate = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (IsKeyPressed(KEY_ENTER))
+ {
+ InitGame();
+ gameOver = false;
+ }
+ }
+}
+
+// Draw game (one frame)
+void DrawGame(void)
+{
+ BeginDrawing();
+
+ ClearBackground(LIGHTGRAY);
+
+ if (!gameOver)
+ {
+ DrawRectangleRec(player.rec, player.color);
+
+ if (wave == FIRST) DrawText("FIRST WAVE", screenWidth/2 - MeasureText("FIRST WAVE", 40)/2, screenHeight/2 - 40, 40, Fade(BLACK, alpha));
+ else if (wave == SECOND) DrawText("SECOND WAVE", screenWidth/2 - MeasureText("SECOND WAVE", 40)/2, screenHeight/2 - 40, 40, Fade(BLACK, alpha));
+ else if (wave == THIRD) DrawText("THIRD WAVE", screenWidth/2 - MeasureText("THIRD WAVE", 40)/2, screenHeight/2 - 40, 40, Fade(BLACK, alpha));
+
+ for (int i = 0; i < activeEnemies; i++)
+ {
+ if (enemy[i].active) DrawRectangleRec(enemy[i].rec, enemy[i].color);
+ }
+
+ for (int i = 0; i < NUM_SHOOTS; i++)
+ {
+ if (shoot[i].active) DrawRectangleRec(shoot[i].rec, shoot[i].color);
+ }
+
+ DrawText(FormatText("%04i", score), 20, 20, 40, DARKGRAY);
+
+ if (victory) DrawText("YOU WIN", screenWidth/2 - MeasureText("YOU WIN", 40)/2, screenHeight/2 - 40, 40, BLACK);
+
+ 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();
+} \ No newline at end of file
diff --git a/games/samples/tetris.c b/games/samples/tetris.c
new file mode 100644
index 00000000..8d550f3d
--- /dev/null
+++ b/games/samples/tetris.c
@@ -0,0 +1,835 @@
+/*******************************************************************************************
+*
+* raylib - sample game: tetris
+*
+* 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 SQUARE_SIZE 30
+
+#define GRID_HORIZONTAL_SIZE 12
+#define GRID_VERTICAL_SIZE 20
+
+#define LATERAL_SPEED 10
+#define TURNING_SPEED 12
+#define FAST_FALL_AWAIT_COUNTER 30
+
+#define FADING_TIME 33
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef enum GridSquare { EMPTY, MOVING, FULL, BLOCK, FADING } GridSquare;
+
+//------------------------------------------------------------------------------------
+// Global Variables Declaration
+//------------------------------------------------------------------------------------
+static int screenWidth = 800;
+static int screenHeight = 620;
+
+static bool gameOver = false;
+static bool pause = false;
+
+// Matrices
+static GridSquare grid [GRID_HORIZONTAL_SIZE][GRID_VERTICAL_SIZE];
+static GridSquare piece [4][4];
+static GridSquare incomingPiece [4][4];
+
+// Theese variables keep track of the active piece position
+static int piecePositionX = 0;
+static int piecePositionY = 0;
+
+// Game parameters
+static Color fadingColor;
+//static int fallingSpeed; // In frames
+
+static bool beginPlay = true; // This var is only true at the begining of the game, used for the first matrix creations
+static bool pieceActive = false;
+static bool detection = false;
+static bool lineToDelete = false;
+
+// Statistics
+static int level = 1;
+static int lines = 0;
+
+// Counters
+static int gravityMovementCounter = 0;
+static int lateralMovementCounter = 0;
+static int turnMovementCounter = 0;
+static int fastFallMovementCounter = 0;
+
+static int fadeLineCounter = 0;
+
+// Based on level
+static int gravitySpeed = 30;
+
+//------------------------------------------------------------------------------------
+// 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)
+
+// Additional module functions
+static bool Createpiece();
+static void GetRandompiece();
+static void ResolveFallingMovement();
+static bool ResolveLateralMovement();
+static bool ResolveTurnMovement();
+static void CheckDetection();
+static void CheckCompletition();
+static void DeleteCompleteLines();
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "sample game: tetris");
+
+ 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
+ //----------------------------------------------------------------------------------
+ UpdateGame();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ DrawGame();
+ //----------------------------------------------------------------------------------
+ }
+#endif
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadGame(); // Unload loaded data (textures, sounds, models...)
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------------------
+// Game Module Functions Definition
+//--------------------------------------------------------------------------------------
+
+// Initialize game variables
+void InitGame(void)
+{
+ // Initialize game statistics
+ level = 1;
+ lines = 0;
+
+ fadingColor = GRAY;
+
+ piecePositionX = 0;
+ piecePositionY = 0;
+
+ pause = false;
+
+ beginPlay = true;
+ pieceActive = false;
+ detection = false;
+ lineToDelete = false;
+
+ // Counters
+ gravityMovementCounter = 0;
+ lateralMovementCounter = 0;
+ turnMovementCounter = 0;
+ fastFallMovementCounter = 0;
+
+ fadeLineCounter = 0;
+ gravitySpeed = 30;
+
+ // Initialize grid matrices
+ for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++)
+ {
+ for (int j = 0; j < GRID_VERTICAL_SIZE; j++)
+ {
+ if ((j == GRID_VERTICAL_SIZE - 1) || (i == 0) || (i == GRID_HORIZONTAL_SIZE - 1)) grid[i][j] = BLOCK;
+ else grid[i][j] = EMPTY;
+ }
+ }
+
+ // Initialize incoming piece matrices
+ for (int i = 0; i < 4; i++)
+ {
+ for (int j = 0; j< 4; j++)
+ {
+ incomingPiece[i][j] = EMPTY;
+ }
+ }
+}
+
+// Update game (one frame)
+void UpdateGame(void)
+{
+ if (!gameOver)
+ {
+ if (IsKeyPressed('P')) pause = !pause;
+
+ if (!pause)
+ {
+ if (!lineToDelete)
+ {
+ if (!pieceActive)
+ {
+ // Get another piece
+ pieceActive = Createpiece();
+
+ // We leave a little time before starting the fast falling down
+ fastFallMovementCounter = 0;
+ }
+ else // Piece falling
+ {
+ // Counters update
+ fastFallMovementCounter++;
+ gravityMovementCounter++;
+ lateralMovementCounter++;
+ turnMovementCounter++;
+
+ // We make sure to move if we've pressed the key this frame
+ if (IsKeyPressed(KEY_LEFT) || IsKeyPressed(KEY_RIGHT)) lateralMovementCounter = LATERAL_SPEED;
+ if (IsKeyPressed(KEY_UP)) turnMovementCounter = TURNING_SPEED;
+
+ // Fall down
+ if (IsKeyDown(KEY_DOWN) && (fastFallMovementCounter >= FAST_FALL_AWAIT_COUNTER))
+ {
+ // We make sure the piece is going to fall this frame
+ gravityMovementCounter += gravitySpeed;
+ }
+
+ if (gravityMovementCounter >= gravitySpeed)
+ {
+ // Basic falling movement
+ CheckDetection(&detection);
+
+ // Check if the piece has collided with another piece or with the boundings
+ ResolveFallingMovement(&detection, &pieceActive);
+
+ // Check if we fullfilled a line and if so, erase the line and pull down the the lines above
+ CheckCompletition(&lineToDelete);
+
+ gravityMovementCounter = 0;
+ }
+
+ // Move laterally at player's will
+ if (lateralMovementCounter >= LATERAL_SPEED)
+ {
+ // Update the lateral movement and if success, reset the lateral counter
+ if (!ResolveLateralMovement()) lateralMovementCounter = 0;
+ }
+
+ // Turn the piece at player's will
+ if (turnMovementCounter >= TURNING_SPEED)
+ {
+ // Update the turning movement and reset the turning counter
+ if (ResolveTurnMovement()) turnMovementCounter = 0;
+ }
+ }
+
+ // Game over logic
+ for (int j = 0; j < 2; j++)
+ {
+ for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
+ {
+ if (grid[i][j] == FULL)
+ {
+ gameOver = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Animation when deleting lines
+ fadeLineCounter++;
+
+ if (fadeLineCounter%8 < 4) fadingColor = MAROON;
+ else fadingColor = GRAY;
+
+ if (fadeLineCounter >= FADING_TIME)
+ {
+ DeleteCompleteLines();
+ fadeLineCounter = 0;
+ lineToDelete = false;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (IsKeyPressed(KEY_ENTER))
+ {
+ InitGame();
+ gameOver = false;
+ }
+ }
+}
+
+// Draw game (one frame)
+void DrawGame(void)
+{
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ if (!gameOver)
+ {
+ // Draw gameplay area
+ Vector2 offset;
+ offset.x = screenWidth/2 - (GRID_HORIZONTAL_SIZE*SQUARE_SIZE/2);
+ offset.y = screenHeight/2 - ((GRID_VERTICAL_SIZE - 1)*SQUARE_SIZE/2) + SQUARE_SIZE*2;
+
+ offset.y -= 60; // NOTE: Harcoded position!
+
+ int controller = offset.x;
+
+ for (int j = 0; j < GRID_VERTICAL_SIZE; j++)
+ {
+ for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++)
+ {
+ // Draw each square of the grid
+ if (grid[i][j] == EMPTY)
+ {
+ DrawLine(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, LIGHTGRAY );
+ DrawLine(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, LIGHTGRAY );
+ DrawLine(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, LIGHTGRAY );
+ DrawLine(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, LIGHTGRAY );
+ offset.x += SQUARE_SIZE;
+ }
+ else if (grid[i][j] == FULL)
+ {
+ DrawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, GRAY);
+ offset.x += SQUARE_SIZE;
+ }
+ else if (grid[i][j] == MOVING)
+ {
+ DrawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, DARKGRAY);
+ offset.x += SQUARE_SIZE;
+ }
+ else if (grid[i][j] == BLOCK)
+ {
+ DrawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, LIGHTGRAY);
+ offset.x += SQUARE_SIZE;
+ }
+ else if (grid[i][j] == FADING)
+ {
+ DrawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, fadingColor);
+ offset.x += SQUARE_SIZE;
+ }
+ }
+
+ offset.x = controller;
+ offset.y += SQUARE_SIZE;
+ }
+
+ // Draw incoming piece
+ //offset.x = screenWidth/2 - (4*SQUARE_SIZE/2);
+ //offset.y = (screenHeight/2 - ((GRID_VERTICAL_SIZE - 1)*SQUARE_SIZE/2)) - (3*SQUARE_SIZE);
+
+ // NOTE: Harcoded positions for the demo!
+ offset.x = 850;
+ offset.y = 75;
+
+ int controler = offset.x;
+
+ for (int j = 0; j < 4; j++)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ if (incomingPiece[i][j] == EMPTY)
+ {
+ DrawLine(offset.x, offset.y, offset.x + SQUARE_SIZE, offset.y, LIGHTGRAY );
+ DrawLine(offset.x, offset.y, offset.x, offset.y + SQUARE_SIZE, LIGHTGRAY );
+ DrawLine(offset.x + SQUARE_SIZE, offset.y, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, LIGHTGRAY );
+ DrawLine(offset.x, offset.y + SQUARE_SIZE, offset.x + SQUARE_SIZE, offset.y + SQUARE_SIZE, LIGHTGRAY );
+ offset.x += SQUARE_SIZE;
+ }
+ else if (incomingPiece[i][j] == MOVING)
+ {
+ DrawRectangle(offset.x, offset.y, SQUARE_SIZE, SQUARE_SIZE, GRAY);
+ offset.x += SQUARE_SIZE;
+ }
+ }
+
+ offset.x = controler;
+ offset.y += SQUARE_SIZE;
+ }
+
+ 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();
+}
+
+//--------------------------------------------------------------------------------------
+// Additional module functions
+//--------------------------------------------------------------------------------------
+static bool Createpiece()
+{
+ piecePositionX = (int)((GRID_HORIZONTAL_SIZE - 4)/2);
+ piecePositionY = 0;
+
+ // If the game is starting and you are going to create the first piece, we create an extra one
+ if (beginPlay)
+ {
+ GetRandompiece();
+ beginPlay = false;
+ }
+
+ // We assign the incoming piece to the actual piece
+ for (int i = 0; i < 4; i++)
+ {
+ for (int j = 0; j< 4; j++)
+ {
+ piece[i][j] = incomingPiece[i][j];
+ }
+ }
+
+ // We assign a random piece to the incoming one
+ GetRandompiece();
+
+ // Assign the piece to the grid
+ for (int i = piecePositionX; i < piecePositionX + 4; i++)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ if (piece[i - (int)piecePositionX][j] == MOVING) grid[i][j] = MOVING;
+ }
+ }
+
+ return true;
+}
+
+static void GetRandompiece()
+{
+ srand(time(NULL));
+ int random = rand() % 7;
+
+ for (int i = 0; i < 4; i++)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ incomingPiece[i][j] = EMPTY;
+ }
+ }
+
+ switch(random)
+ {
+ case 0: { incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; } break; //Cube
+ case 1: { incomingPiece[1][0] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; } break; //L
+ case 2: { incomingPiece[1][2] = MOVING; incomingPiece[2][0] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[2][2] = MOVING; } break; //L inversa
+ case 3: { incomingPiece[0][1] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[3][1] = MOVING; } break; //Recta
+ case 4: { incomingPiece[1][0] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][1] = MOVING; } break; //Creu tallada
+ case 5: { incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[2][2] = MOVING; incomingPiece[3][2] = MOVING; } break; //S
+ case 6: { incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[3][1] = MOVING; } break; //S inversa
+ }
+}
+
+static void ResolveFallingMovement(bool *detection, bool *pieceActive)
+{
+ // If we finished moving this piece, we stop it
+ if (*detection)
+ {
+ for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
+ {
+ for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
+ {
+ if (grid[i][j] == MOVING)
+ {
+ grid[i][j] = FULL;
+ *detection = false;
+ *pieceActive = false;
+ }
+ }
+ }
+ }
+ // We move down the piece
+ else
+ {
+ for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
+ {
+ for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
+ {
+ if (grid[i][j] == MOVING)
+ {
+ grid[i][j+1] = MOVING;
+ grid[i][j] = EMPTY;
+ }
+ }
+ }
+ piecePositionY++;
+ }
+}
+
+static bool ResolveLateralMovement()
+{
+ bool collision = false;
+
+ // Move left
+ if (IsKeyDown(KEY_LEFT))
+ {
+ // Check if is possible to move to left
+ for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
+ {
+ for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
+ {
+ if (grid[i][j] == MOVING)
+ {
+ // Check if we are touching the left wall or we have a full square at the left
+ if ((i-1 == 0) || (grid[i-1][j] == FULL)) collision = true;
+ }
+ }
+ }
+ // If able, move left
+ if (!collision)
+ {
+ for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
+ {
+ for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) // We check the matrix from left to right
+ {
+ // Move everything to the left
+ if (grid[i][j] == MOVING)
+ {
+ grid[i-1][j] = MOVING;
+ grid[i][j] = EMPTY;
+ }
+ }
+ }
+
+ piecePositionX--;
+ }
+ }
+
+ // Move right
+ else if (IsKeyDown(KEY_RIGHT))
+ {
+ // Check if is possible to move to right
+ for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
+ {
+ for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
+ {
+ if (grid[i][j] == MOVING)
+ {
+ // Check if we are touching the right wall or we have a full square at the right
+ if ((i+1 == GRID_HORIZONTAL_SIZE - 1) || (grid[i+1][j] == FULL))
+ {
+ collision = true;
+
+ }
+ }
+ }
+ }
+ // If able move right
+ if (!collision)
+ {
+ for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
+ {
+ for (int i = GRID_HORIZONTAL_SIZE - 1; i >= 1; i--) // We check the matrix from right to left
+ {
+ // Move everything to the right
+ if (grid[i][j] == MOVING)
+ {
+ grid[i+1][j] = MOVING;
+ grid[i][j] = EMPTY;
+ }
+ }
+ }
+
+ piecePositionX++;
+ }
+ }
+
+ return collision;
+}
+
+static bool ResolveTurnMovement()
+{
+ // Input for turning the piece
+ if (IsKeyDown(KEY_UP))
+ {
+ int aux;
+ bool checker = false;
+
+ // Check all turning possibilities
+ if ((grid[piecePositionX + 3][piecePositionY] == MOVING) &&
+ (grid[piecePositionX][piecePositionY] != EMPTY) &&
+ (grid[piecePositionX][piecePositionY] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX + 3][piecePositionY + 3] == MOVING) &&
+ (grid[piecePositionX + 3][piecePositionY] != EMPTY) &&
+ (grid[piecePositionX + 3][piecePositionY] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX][piecePositionY + 3] == MOVING) &&
+ (grid[piecePositionX + 3][piecePositionY + 3] != EMPTY) &&
+ (grid[piecePositionX + 3][piecePositionY + 3] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX][piecePositionY] == MOVING) &&
+ (grid[piecePositionX][piecePositionY + 3] != EMPTY) &&
+ (grid[piecePositionX][piecePositionY + 3] != MOVING))
+ {
+ checker = true;
+ }
+
+
+ if ((grid[piecePositionX + 1][piecePositionY] == MOVING) &&
+ (grid[piecePositionX][piecePositionY + 2] != EMPTY) &&
+ (grid[piecePositionX][piecePositionY + 2] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX + 3][piecePositionY + 1] == MOVING) &&
+ (grid[piecePositionX + 1][piecePositionY] != EMPTY) &&
+ (grid[piecePositionX + 1][piecePositionY] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX + 2][piecePositionY + 3] == MOVING) &&
+ (grid[piecePositionX + 3][piecePositionY + 1] != EMPTY) &&
+ (grid[piecePositionX + 3][piecePositionY + 1] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX][piecePositionY + 2] == MOVING) &&
+ (grid[piecePositionX + 2][piecePositionY + 3] != EMPTY) &&
+ (grid[piecePositionX + 2][piecePositionY + 3] != MOVING))
+ {
+ checker = true;
+ }
+
+
+ if ((grid[piecePositionX + 2][piecePositionY] == MOVING) &&
+ (grid[piecePositionX][piecePositionY + 1] != EMPTY) &&
+ (grid[piecePositionX][piecePositionY + 1] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX + 3][piecePositionY + 2] == MOVING) &&
+ (grid[piecePositionX + 2][piecePositionY] != EMPTY) &&
+ (grid[piecePositionX + 2][piecePositionY] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX + 1][piecePositionY + 3] == MOVING) &&
+ (grid[piecePositionX + 3][piecePositionY + 2] != EMPTY) &&
+ (grid[piecePositionX + 3][piecePositionY + 2] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX][piecePositionY + 1] == MOVING) &&
+ (grid[piecePositionX + 1][piecePositionY + 3] != EMPTY) &&
+ (grid[piecePositionX + 1][piecePositionY + 3] != MOVING))
+ {
+ checker = true;
+ }
+
+ if ((grid[piecePositionX + 1][piecePositionY + 1] == MOVING) &&
+ (grid[piecePositionX + 1][piecePositionY + 2] != EMPTY) &&
+ (grid[piecePositionX + 1][piecePositionY + 2] != MOVING))
+ {
+ checker = true;
+ }
+
+ if ((grid[piecePositionX + 2][piecePositionY + 1] == MOVING) &&
+ (grid[piecePositionX + 1][piecePositionY + 1] != EMPTY) &&
+ (grid[piecePositionX + 1][piecePositionY + 1] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX + 2][piecePositionY + 2] == MOVING) &&
+ (grid[piecePositionX + 2][piecePositionY + 1] != EMPTY) &&
+ (grid[piecePositionX + 2][piecePositionY + 1] != MOVING))
+ {
+ checker = true;
+ }
+ if ((grid[piecePositionX + 1][piecePositionY + 2] == MOVING) &&
+ (grid[piecePositionX + 2][piecePositionY + 2] != EMPTY) &&
+ (grid[piecePositionX + 2][piecePositionY + 2] != MOVING))
+ {
+ checker = true;
+ }
+
+ if (!checker)
+ {
+ aux = piece[0][0];
+ piece[0][0] = piece[3][0];
+ piece[3][0] = piece[3][3];
+ piece[3][3] = piece[0][3];
+ piece[0][3] = aux;
+
+ aux = piece[1][0];
+ piece[1][0] = piece[3][1];
+ piece[3][1] = piece[2][3];
+ piece[2][3] = piece[0][2];
+ piece[0][2] = aux;
+
+ aux = piece[2][0];
+ piece[2][0] = piece[3][2];
+ piece[3][2] = piece[1][3];
+ piece[1][3] = piece[0][1];
+ piece[0][1] = aux;
+
+ aux = piece[1][1];
+ piece[1][1] = piece[2][1];
+ piece[2][1] = piece[2][2];
+ piece[2][2] = piece[1][2];
+ piece[1][2] = aux;
+ }
+
+ for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
+ {
+ for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
+ {
+ if (grid[i][j] == MOVING)
+ {
+ grid[i][j] = EMPTY;
+ }
+ }
+ }
+
+ for (int i = piecePositionX; i < piecePositionX + 4; i++)
+ {
+ for (int j = piecePositionY; j < piecePositionY + 4; j++)
+ {
+ if (piece[i - piecePositionX][j - piecePositionY] == MOVING)
+ {
+ grid[i][j] = MOVING;
+ }
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+static void CheckDetection(bool *detection)
+{
+ for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
+ {
+ for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
+ {
+ if ((grid[i][j] == MOVING) && ((grid[i][j+1] == FULL) || (grid[i][j+1] == BLOCK))) *detection = true;
+ }
+ }
+}
+
+static void CheckCompletition(bool *lineToDelete)
+{
+ int calculator;
+
+ for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
+ {
+ calculator = 0;
+ for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
+ {
+ // Count each square of the line
+ if (grid[i][j] == FULL)
+ {
+ calculator++;
+ }
+
+ // Check if we completed the whole line
+ if (calculator == GRID_HORIZONTAL_SIZE - 2)
+ {
+ *lineToDelete = true;
+ calculator = 0;
+ // points++;
+
+ // Mark the completed line
+ for (int z = 1; z < GRID_HORIZONTAL_SIZE - 1; z++)
+ {
+ grid[z][j] = FADING;
+ }
+ }
+ }
+ }
+}
+
+static void DeleteCompleteLines()
+{
+ // erase the completed line
+ for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--)
+ {
+ while (grid[1][j] == FADING)
+ {
+ for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++)
+ {
+ grid[i][j] = EMPTY;
+ }
+ for (int j2 = j-1; j2 >= 0; j2--)
+ {
+ for (int i2 = 1; i2 < GRID_HORIZONTAL_SIZE - 1; i2++)
+ {
+ if (grid[i2][j2] == FULL)
+ {
+ grid[i2][j2+1] = FULL;
+ grid[i2][j2] = EMPTY;
+ }
+ else if (grid[i2][j2] == FADING)
+ {
+ grid[i2][j2+1] = FADING;
+ grid[i2][j2] = EMPTY;
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file