mirror of
https://github.com/raysan5/raylib.git
synced 2026-01-22 07:09:18 -05:00
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...)
This commit is contained in:
539
games/samples/missile_commander.c
Normal file
539
games/samples/missile_commander.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user