| /******************************************************************************************* | |
| * | |
| *   raylib game - Dr. Turtle & Mr. Gamera | |
| * | |
| *   Welcome to raylib! | |
| * | |
| *   To test examples, just press F6 and execute raylib_compile_execute script | |
| *   Note that compiled executable is placed in the same folder as .c file | |
| * | |
| *   You can find all basic examples on C:\raylib\raylib\examples folder or | |
| *   raylib official webpage: www.raylib.com | |
| * | |
| *   Enjoy using raylib. :) | |
| * | |
| *   This game has been created using raylib 1.1 (www.raylib.com) | |
| *   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) | |
| * | |
| *   Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) | |
| * | |
| ********************************************************************************************/ | |
| 
 | |
| #include "raylib.h" | |
| #include <math.h>        // Used for sinf() | |
|  | |
| #if defined(PLATFORM_WEB) | |
|     #include <emscripten/emscripten.h> | |
| #endif | |
|  | |
| #define MAX_ENEMIES 10 | |
|  | |
| typedef enum { TITLE = 0, GAMEPLAY, ENDING } GameScreen; | |
| 
 | |
| //---------------------------------------------------------------------------------- | |
| // Global Variables Definition | |
| //---------------------------------------------------------------------------------- | |
| const int screenWidth = 1280; | |
| const int screenHeight = 720; | |
|      | |
| Texture2D sky; | |
| Texture2D mountains; | |
| Texture2D sea; | |
| Texture2D title; | |
| Texture2D turtle; | |
| Texture2D gamera; | |
| Texture2D shark; | |
| Texture2D orca; | |
| Texture2D swhale; | |
| Texture2D fish; | |
| Texture2D gframe; | |
| 
 | |
| SpriteFont font; | |
| 
 | |
| Sound eat; | |
| Sound die; | |
| Sound growl; | |
| 
 | |
| // Define scrolling variables | |
| int backScrolling = 0; | |
| int seaScrolling = 0; | |
| 
 | |
| // Define current screen | |
| GameScreen currentScreen = 0; | |
| 
 | |
| // Define player variables | |
| int playerRail = 1; | |
| Rectangle playerBounds; | |
| bool gameraMode = false; | |
| 
 | |
| // Define enemies variables | |
| Rectangle enemyBounds[MAX_ENEMIES]; | |
| int enemyRail[MAX_ENEMIES]; | |
| int enemyType[MAX_ENEMIES]; | |
| bool enemyActive[MAX_ENEMIES]; | |
| float enemySpeed = 10; | |
|      | |
| // Define additional game variables | |
| int score = 0; | |
| float distance = 0.0f; | |
| int hiscore = 0; | |
| float hidistance = 0.0f; | |
| int foodBar = 0; | |
| int framesCounter = 0; | |
| 
 | |
| unsigned char blue = 200; | |
| float timeCounter = 0; | |
|      | |
| //---------------------------------------------------------------------------------- | |
| // Module Functions Declaration | |
| //---------------------------------------------------------------------------------- | |
| void UpdateDrawFrame(void);     // Update and Draw one frame | |
|  | |
| //---------------------------------------------------------------------------------- | |
| // Main Enry Point | |
| //---------------------------------------------------------------------------------- | |
| int main() | |
| { | |
|     // Initialization | |
|     //-------------------------------------------------------------------------------------- | |
|      | |
|     // Init window | |
|     InitWindow(screenWidth, screenHeight, "Dr. Turtle & Mr. GAMERA"); | |
|      | |
|     // Initialize audio device | |
|     InitAudioDevice();       | |
|      | |
|     // Load game resources: textures | |
|     sky = LoadTexture("resources/sky.png"); | |
|     mountains = LoadTexture("resources/mountains.png"); | |
|     sea = LoadTexture("resources/sea.png"); | |
|     title = LoadTexture("resources/title.png"); | |
|     turtle = LoadTexture("resources/turtle.png"); | |
|     gamera = LoadTexture("resources/gamera.png"); | |
|     shark = LoadTexture("resources/shark.png"); | |
|     orca = LoadTexture("resources/orca.png"); | |
|     swhale = LoadTexture("resources/swhale.png"); | |
|     fish = LoadTexture("resources/fish.png"); | |
|     gframe = LoadTexture("resources/gframe.png"); | |
|      | |
|     // Load game resources: fonts | |
|     font = LoadSpriteFont("resources/komika.png"); | |
|      | |
|     // Load game resources: sounds | |
|     eat = LoadSound("resources/eat.wav"); | |
|     die = LoadSound("resources/die.wav"); | |
|     growl = LoadSound("resources/gamera.wav"); | |
|      | |
|     // Start playing streaming music | |
|     PlayMusicStream("resources/speeding.ogg"); | |
|      | |
|     playerBounds = (Rectangle){ 30 + 14, playerRail*120 + 90 + 14, 100, 100 }; | |
|      | |
|     // Init enemies variables | |
|     for (int i = 0; i < MAX_ENEMIES; i++) | |
|     { | |
|         // Define enemy type (all same probability) | |
|         //enemyType[i] = GetRandomValue(0, 3); | |
|      | |
|         // Probability system for enemies type | |
|         int enemyProb = GetRandomValue(0, 100); | |
|          | |
|         if (enemyProb < 30) enemyType[i] = 0; | |
|         else if (enemyProb < 60) enemyType[i] = 1; | |
|         else if (enemyProb < 90) enemyType[i] = 2; | |
|         else enemyType[i] = 3; | |
| 
 | |
|         // define enemy rail | |
|         enemyRail[i] = GetRandomValue(0, 4); | |
| 
 | |
|         // Make sure not two consecutive enemies in the same row | |
|         if (i > 0) while (enemyRail[i] == enemyRail[i - 1]) enemyRail[i] = GetRandomValue(0, 4); | |
|          | |
|         enemyBounds[i] = (Rectangle){ screenWidth + 14, 120*enemyRail[i] + 90 + 14, 100, 100 }; | |
|         enemyActive[i] = false; | |
|     } | |
|      | |
| #if defined(PLATFORM_WEB) | |
|     emscripten_set_main_loop(UpdateDrawFrame, 0, 1); | |
| #else | |
|     SetTargetFPS(60);   // Set our game to run at 60 frames-per-second | |
|     //-------------------------------------------------------------------------------------- | |
|      | |
|     // Main game loop | |
|     while (!WindowShouldClose())    // Detect window close button or ESC key | |
|     { | |
|         UpdateDrawFrame(); | |
|     } | |
| #endif | |
|  | |
|     // De-Initialization | |
|     //-------------------------------------------------------------------------------------- | |
|      | |
|     // Unload textures | |
|     UnloadTexture(sky); | |
|     UnloadTexture(mountains); | |
|     UnloadTexture(sea); | |
|     UnloadTexture(gframe); | |
|     UnloadTexture(title); | |
|     UnloadTexture(turtle); | |
|     UnloadTexture(shark); | |
|     UnloadTexture(orca); | |
|     UnloadTexture(swhale); | |
|     UnloadTexture(fish); | |
|     UnloadTexture(gamera); | |
|      | |
|     // Unload font texture | |
|     UnloadSpriteFont(font); | |
|      | |
|     // Unload sounds | |
|     UnloadSound(eat); | |
|     UnloadSound(die); | |
|     UnloadSound(growl); | |
|      | |
|     StopMusicStream();      // Stop music | |
|     CloseAudioDevice();     // Close audio device | |
|      | |
|     CloseWindow();          // Close window and OpenGL context | |
|     //-------------------------------------------------------------------------------------- | |
|      | |
|     return 0; | |
| } | |
| 
 | |
| //---------------------------------------------------------------------------------- | |
| // Module Functions Definition | |
| //---------------------------------------------------------------------------------- | |
| void UpdateDrawFrame(void) | |
| { | |
|     // Update | |
|     //---------------------------------------------------------------------------------- | |
|     UpdateMusicStream(); | |
|      | |
|     framesCounter++; | |
|      | |
|     // Sea color tint effect | |
|     blue = 210 + 25 * sinf(timeCounter); | |
|     timeCounter += 0.01; | |
| 
 | |
|     // Game screens management | |
|     switch (currentScreen) | |
|     { | |
|         case TITLE: | |
|         { | |
|             // Sea scrolling | |
|             seaScrolling -= 2; | |
|             if (seaScrolling <= -screenWidth) seaScrolling = 0;  | |
|          | |
|             // Press enter to change to gameplay screen | |
|             if (IsKeyPressed(KEY_ENTER)) | |
|             { | |
|                 currentScreen = GAMEPLAY; | |
|                 framesCounter = 0; | |
|             } | |
|              | |
|         } break; | |
|         case GAMEPLAY: | |
|         { | |
|             // Background scrolling logic | |
|             backScrolling--; | |
|             if (backScrolling <= -screenWidth) backScrolling = 0;  | |
|              | |
|             // Sea scrolling logic | |
|             seaScrolling -= (enemySpeed - 2); | |
|             if (seaScrolling <= -screenWidth) seaScrolling = 0;  | |
|          | |
|             // Player movement logic | |
|             if (IsKeyPressed(KEY_DOWN)) playerRail++; | |
|             else if (IsKeyPressed(KEY_UP)) playerRail--; | |
|              | |
|             // Check player not out of rails | |
|             if (playerRail > 4) playerRail = 4; | |
|             else if (playerRail < 0) playerRail = 0; | |
|          | |
|             // Update player bounds | |
|             playerBounds = (Rectangle){ 30 + 14, playerRail*120 + 90 + 14, 100, 100 }; | |
|              | |
|             // Enemies activation logic (every 40 frames)         | |
|             if (framesCounter > 40) | |
|             { | |
|                 for (int i = 0; i < MAX_ENEMIES; i++) | |
|                 { | |
|                     if (enemyActive[i] == false) | |
|                     { | |
|                         enemyActive[i] = true; | |
|                         i = MAX_ENEMIES; | |
|                     } | |
|                 } | |
|                  | |
|                 framesCounter = 0; | |
|             } | |
|              | |
|             // Enemies logic | |
|             for (int i = 0; i < MAX_ENEMIES; i++) | |
|             { | |
|                 if (enemyActive[i]) | |
|                 { | |
|                     enemyBounds[i].x -= enemySpeed; | |
|                 } | |
|                  | |
|                 // Check enemies out of screen | |
|                 if (enemyBounds[i].x <= 0 - 128) | |
|                 { | |
|                     enemyActive[i] = false; | |
|                     enemyType[i] = GetRandomValue(0, 3); | |
|                     enemyRail[i] = GetRandomValue(0, 4); | |
|                      | |
|                     // Make sure not two consecutive enemies in the same row | |
|                     if (i > 0) while (enemyRail[i] == enemyRail[i - 1]) enemyRail[i] = GetRandomValue(0, 4); | |
|                      | |
|                     enemyBounds[i] = (Rectangle){ screenWidth + 14, 120*enemyRail[i] + 90 + 14, 100, 100 }; | |
|                 } | |
|             } | |
|              | |
|             if (!gameraMode) enemySpeed += 0.005; | |
|              | |
|             // Check collision player vs enemies | |
|             for (int i = 0; i < MAX_ENEMIES; i++) | |
|             { | |
|                 if (enemyActive[i]) | |
|                 { | |
|                     if (CheckCollisionRecs(playerBounds, enemyBounds[i])) | |
|                     {                        | |
|                         if (enemyType[i] < 3)   // Bad enemies | |
|                         { | |
|                             if (gameraMode) | |
|                             { | |
|                                 if (enemyType[i] == 0) score += 50; | |
|                                 else if (enemyType[i] == 1) score += 150; | |
|                                 else if (enemyType[i] == 2) score += 300; | |
|                                  | |
|                                 foodBar += 15; | |
|                              | |
|                                 enemyActive[i] = false; | |
|                                  | |
|                                 // After enemy deactivation, reset enemy parameters to be reused | |
|                                 enemyType[i] = GetRandomValue(0, 3); | |
|                                 enemyRail[i] = GetRandomValue(0, 4); | |
|                                  | |
|                                 // Make sure not two consecutive enemies in the same row | |
|                                 if (i > 0) while (enemyRail[i] == enemyRail[i - 1]) enemyRail[i] = GetRandomValue(0, 4); | |
|                                  | |
|                                 enemyBounds[i] = (Rectangle){ screenWidth + 14, 120*enemyRail[i] + 90 + 14, 100, 100 }; | |
|                                  | |
|                                 PlaySound(eat); | |
|                             } | |
|                             else | |
|                             { | |
|                                 // Player die logic | |
|                                 PlaySound(die); | |
|                              | |
|                                 currentScreen = ENDING; | |
|                                 framesCounter = 0; | |
|                                  | |
|                                 // Save hiscore and hidistance for next game | |
|                                 if (score > hiscore) hiscore = score; | |
|                                 if (distance > hidistance) hidistance = distance; | |
|                             } | |
|                         } | |
|                         else    // Sweet fish | |
|                         { | |
|                             enemyActive[i] = false; | |
|                             enemyType[i] = GetRandomValue(0, 3); | |
|                             enemyRail[i] = GetRandomValue(0, 4); | |
|                              | |
|                             // Make sure not two consecutive enemies in the same row | |
|                             if (i > 0) while (enemyRail[i] == enemyRail[i - 1]) enemyRail[i] = GetRandomValue(0, 4); | |
|                              | |
|                             enemyBounds[i] = (Rectangle){ screenWidth + 14, 120*enemyRail[i] + 90 + 14, 100, 100 }; | |
|                              | |
|                             if (!gameraMode) foodBar += 80; | |
|                             else foodBar += 25; | |
|                              | |
|                             score += 10; | |
|                              | |
|                             if (foodBar == 400) | |
|                             { | |
|                                 gameraMode = true; | |
|                                  | |
|                                 PlaySound(growl); | |
|                             } | |
|                              | |
|                             PlaySound(eat); | |
|                         } | |
|                     } | |
|                 } | |
|             } | |
|              | |
|             // Gamera mode logic | |
|             if (gameraMode) | |
|             { | |
|                 foodBar--; | |
|                  | |
|                 if (foodBar <= 0)  | |
|                 { | |
|                     gameraMode = false; | |
|                     enemySpeed -= 2; | |
|                     if (enemySpeed < 10) enemySpeed = 10; | |
|                 } | |
|             } | |
|      | |
|             // Update distance counter | |
|             distance += 0.5f; | |
|          | |
|         } break; | |
|         case ENDING: | |
|         { | |
|             // Press enter to play again | |
|             if (IsKeyPressed(KEY_ENTER)) | |
|             { | |
|                 currentScreen = GAMEPLAY; | |
|                  | |
|                 // Reset player | |
|                 playerRail = 1; | |
|                 playerBounds = (Rectangle){ 30 + 14, playerRail*120 + 90 + 14, 100, 100 }; | |
|                 gameraMode = false; | |
|                  | |
|                 // Reset enemies data | |
|                 for (int i = 0; i < MAX_ENEMIES; i++) | |
|                 { | |
|                     int enemyProb = GetRandomValue(0, 100); | |
|                      | |
|                     if (enemyProb < 30) enemyType[i] = 0; | |
|                     else if (enemyProb < 60) enemyType[i] = 1; | |
|                     else if (enemyProb < 90) enemyType[i] = 2; | |
|                     else enemyType[i] = 3; | |
|                      | |
|                     //enemyType[i] = GetRandomValue(0, 3); | |
|                     enemyRail[i] = GetRandomValue(0, 4); | |
| 
 | |
|                     // Make sure not two consecutive enemies in the same row | |
|                     if (i > 0) while (enemyRail[i] == enemyRail[i - 1]) enemyRail[i] = GetRandomValue(0, 4); | |
|                      | |
|                     enemyBounds[i] = (Rectangle){ screenWidth + 14, 120*enemyRail[i] + 90 + 14, 100, 100 }; | |
|                     enemyActive[i] = false; | |
|                 } | |
|                  | |
|                 enemySpeed = 10; | |
|                  | |
|                 // Reset game variables | |
|                 score = 0; | |
|                 distance = 0.0; | |
|                 foodBar = 0; | |
|                 framesCounter = 0; | |
|             } | |
|    | |
|         } break; | |
|         default: break; | |
|     } | |
|     //---------------------------------------------------------------------------------- | |
|      | |
|     // Draw | |
|     //---------------------------------------------------------------------------------- | |
|     BeginDrawing(); | |
|      | |
|         ClearBackground(RAYWHITE); | |
|          | |
|         // Draw background (common to all screens) | |
|         DrawTexture(sky, 0, 0, WHITE); | |
|          | |
|         DrawTexture(mountains, backScrolling, 0, WHITE); | |
|         DrawTexture(mountains, screenWidth + backScrolling, 0, WHITE); | |
|          | |
|         if (!gameraMode) | |
|         { | |
|             DrawTexture(sea, seaScrolling, 0, (Color){ 16, 189, blue, 255}); | |
|             DrawTexture(sea, screenWidth + seaScrolling, 0, (Color){ 16, 189, blue, 255}); | |
|         } | |
|         else | |
|         { | |
|             DrawTexture(sea, seaScrolling, 0, (Color){ 255, 113, 66, 255}); | |
|             DrawTexture(sea, screenWidth + seaScrolling, 0, (Color){ 255, 113, 66, 255}); | |
|         } | |
|          | |
|         switch (currentScreen) | |
|         { | |
|             case TITLE: | |
|             { | |
|                 // Draw title | |
|                 DrawTexture(title, screenWidth/2 - title.width/2, screenHeight/2 - title.height/2 - 80, WHITE); | |
|                  | |
|                 // Draw blinking text | |
|                 if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER", (Vector2){ screenWidth/2 - 150, 480 }, font.size, 1, WHITE); | |
|              | |
|             } break; | |
|             case GAMEPLAY: | |
|             { | |
|                 // Draw water lines | |
|                 for (int i = 0; i < 5; i++) DrawRectangle(0, i*120 + 120, screenWidth, 110, Fade(SKYBLUE, 0.1f)); | |
|                  | |
|                 // Draw player | |
|                 if (!gameraMode) DrawTexture(turtle, playerBounds.x - 14, playerBounds.y - 14, WHITE); | |
|                 else DrawTexture(gamera, playerBounds.x - 64, playerBounds.y - 64, WHITE); | |
|                  | |
|                 // Draw player bounding box | |
|                 //if (!gameraMode) DrawRectangleRec(playerBounds, Fade(GREEN, 0.4f)); | |
|                 //else DrawRectangleRec(playerBounds, Fade(ORANGE, 0.4f)); | |
|                  | |
|                 // Draw enemies | |
|                 for (int i = 0; i < MAX_ENEMIES; i++) | |
|                 { | |
|                     if (enemyActive[i])  | |
|                     { | |
|                         // Draw enemies | |
|                         switch(enemyType[i]) | |
|                         { | |
|                             case 0: DrawTexture(shark, enemyBounds[i].x - 14, enemyBounds[i].y - 14, WHITE); break; | |
|                             case 1: DrawTexture(orca, enemyBounds[i].x - 14, enemyBounds[i].y - 14, WHITE); break; | |
|                             case 2: DrawTexture(swhale, enemyBounds[i].x - 14, enemyBounds[i].y - 14, WHITE); break; | |
|                             case 3: DrawTexture(fish, enemyBounds[i].x - 14, enemyBounds[i].y - 14, WHITE); break; | |
|                             default: break; | |
|                         } | |
|                          | |
|                         // Draw enemies bounding boxes | |
|                         /* | |
|                         switch(enemyType[i]) | |
|                         { | |
|                             case 0: DrawRectangleRec(enemyBounds[i], Fade(RED, 0.5f)); break; | |
|                             case 1: DrawRectangleRec(enemyBounds[i], Fade(RED, 0.5f)); break; | |
|                             case 2: DrawRectangleRec(enemyBounds[i], Fade(RED, 0.5f)); break; | |
|                             case 3: DrawRectangleRec(enemyBounds[i], Fade(GREEN, 0.5f)); break; | |
|                             default: break; | |
|                         } | |
|                         */ | |
|                     } | |
|                 } | |
|                  | |
|                 // Draw gameplay interface | |
|                 DrawRectangle(20, 20, 400, 40, Fade(GRAY, 0.4f)); | |
|                 DrawRectangle(20, 20, foodBar, 40, ORANGE); | |
|                 DrawRectangleLines(20, 20, 400, 40, BLACK); | |
|                  | |
|                 DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ screenWidth - 300, 20 }, font.size, -2, ORANGE); | |
|                 DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 550, 20 }, font.size, -2, ORANGE); | |
|                  | |
|                 if (gameraMode) | |
|                 { | |
|                     DrawText("GAMERA MODE", 60, 22, 40, GRAY); | |
|                     DrawTexture(gframe, 0, 0, Fade(WHITE, 0.5f)); | |
|                 } | |
|          | |
|             } break; | |
|             case ENDING: | |
|             { | |
|                 // Draw a transparent black rectangle that covers all screen | |
|                 DrawRectangle(0, 0, screenWidth, screenHeight, Fade(BLACK, 0.4f)); | |
|              | |
|                 DrawTextEx(font, "GAME OVER", (Vector2){ 300, 160 }, font.size*3, -2, MAROON); | |
|                  | |
|                 DrawTextEx(font, FormatText("SCORE: %04i", score), (Vector2){ 680, 350 }, font.size, -2, GOLD); | |
|                 DrawTextEx(font, FormatText("DISTANCE: %04i", (int)distance), (Vector2){ 290, 350 }, font.size, -2, GOLD); | |
|                 DrawTextEx(font, FormatText("HISCORE: %04i", hiscore), (Vector2){ 665, 400 }, font.size, -2, ORANGE); | |
|                 DrawTextEx(font, FormatText("HIDISTANCE: %04i", (int)hidistance), (Vector2){ 270, 400 }, font.size, -2, ORANGE); | |
|                  | |
|                 // Draw blinking text | |
|                 if ((framesCounter/30) % 2) DrawTextEx(font, "PRESS ENTER to REPLAY", (Vector2){ screenWidth/2 - 250, 520 }, font.size, -2, LIGHTGRAY); | |
|                  | |
|             } break; | |
|             default: break; | |
|         } | |
| 
 | |
|     EndDrawing(); | |
|     //---------------------------------------------------------------------------------- | |
| } |