summaryrefslogtreecommitdiffhomepage
path: root/games/gorilas.c
diff options
context:
space:
mode:
authorraysan5 <[email protected]>2016-02-20 20:25:01 +0100
committerraysan5 <[email protected]>2016-02-20 20:25:01 +0100
commit7b360d8579c63658ee05377b44d2e0b478d12b74 (patch)
tree16c1553ba117869aeb370ae40f99bb4086701b55 /games/gorilas.c
parent83459159f4c8622cefe93a062138e7e2391b6761 (diff)
downloadraylib-7b360d8579c63658ee05377b44d2e0b478d12b74.tar.gz
raylib-7b360d8579c63658ee05377b44d2e0b478d12b74.zip
Reorganized games folder
Simplified to match raylib installer package folder structure
Diffstat (limited to 'games/gorilas.c')
-rw-r--r--games/gorilas.c571
1 files changed, 571 insertions, 0 deletions
diff --git a/games/gorilas.c b/games/gorilas.c
new file mode 100644
index 00000000..86fd3f5b
--- /dev/null
+++ b/games/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