/******************************************************************************************* * * 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 #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 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(void) { // Initialization (Note windowTitle is unused on Android) //--------------------------------------------------------- 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 and Draw //---------------------------------------------------------------------------------- UpdateDrawFrame(); //---------------------------------------------------------------------------------- } #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 = 20; player.rec.height = 20; 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 = GRAY; } // 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 = MAROON; } } // 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].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(RAYWHITE); 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, GRAY); 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(); }