|
|
- /*******************************************************************************************
- *
- * 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] = { 0 };
- static Interceptor interceptor[MAX_INTERCEPTORS] = { 0 };
- static Explosion explosion[MAX_EXPLOSIONS] = { 0 };
- static Launcher launcher[LAUNCHERS_AMOUNT] = { 0 };
- static Building building[BUILDINGS_AMOUNT] = { 0 };
- 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(void)
- {
- // Initialization (Note windowTitle is unused on Android)
- //---------------------------------------------------------
- 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 and Draw
- //----------------------------------------------------------------------------------
- UpdateDrawFrame();
- //----------------------------------------------------------------------------------
- }
- #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(TextFormat("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;
- }
- }
|