diff options
| author | raysan5 <[email protected]> | 2016-02-20 20:25:01 +0100 |
|---|---|---|
| committer | raysan5 <[email protected]> | 2016-02-20 20:25:01 +0100 |
| commit | 7b360d8579c63658ee05377b44d2e0b478d12b74 (patch) | |
| tree | 16c1553ba117869aeb370ae40f99bb4086701b55 /games/gorilas.c | |
| parent | 83459159f4c8622cefe93a062138e7e2391b6761 (diff) | |
| download | raylib-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.c | 571 |
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 |
