#include "raylib.h" #include #define STAR_COUNT 200 typedef struct { int x; int y; float brightness; float phase; } Star; typedef enum { PAUSE_NONE, PAUSE_RESUME, PAUSE_QUIT } PauseAction; /* --- INIT --- */ static void InitStars(Star *stars, int count, int width, int height) { for (int i = 0; i < count; i++) { stars[i].x = GetRandomValue(0, width); stars[i].y = GetRandomValue(0, height * 2 / 3); /* Upper sky. */ stars[i].brightness = (float)GetRandomValue(30, 100) / 100.0f; stars[i].phase = (float)GetRandomValue(0, 628) / 100.0f; /* ~0..2pi */ } } /* --- DRAW: 2D BACKGROUND --- */ static void DrawSky(int width, int height) { /* Two vertical gradients: white->blue (top), blue->black (bottom). Replaces 480 DrawLine calls — fixes the tearing. */ Color white = { 255, 255, 255, 255 }; Color blue = { 40, 80, 160, 255 }; Color black = { 0, 0, 0, 255 }; DrawRectangleGradientV(0, 0, width, height / 2, white, blue); DrawRectangleGradientV(0, height / 2, width, height - height / 2, blue, black); } static void DrawStars(const Star *stars, int count, float time) { for (int i = 0; i < count; i++) { float twinkle = 0.5f + 0.5f * sinf(time * 2.0f + stars[i].phase); unsigned char a = (unsigned char)(255.0f * stars[i].brightness * twinkle); DrawCircle(stars[i].x, stars[i].y, 2.0f * twinkle, (Color){ 255, 255, 255, (unsigned char)(a / 3) }); DrawPixel(stars[i].x, stars[i].y, (Color){ 255, 255, 255, a }); } } static void DrawCrosshair(int width, int height) { int cx = width / 2; int cy = height / 2; Color c = { 255, 255, 255, 120 }; DrawLine(cx - 8, cy, cx - 3, cy, c); DrawLine(cx + 3, cy, cx + 8, cy, c); DrawLine(cx, cy - 8, cx, cy - 3, c); DrawLine(cx, cy + 3, cx, cy + 8, c); } /* --- DRAW: PAUSE MENU --- */ static PauseAction DrawPauseMenu(int width, int height) { /* Dim overlay. */ DrawRectangle(0, 0, width, height, (Color){ 0, 0, 0, 160 }); /* Title. */ const char *title = "PAUSED"; int title_size = 60; int title_w = MeasureText(title, title_size); DrawText(title, (width - title_w) / 2, height / 2 - 130, title_size, RAYWHITE); /* Resume button. */ Rectangle resume_btn = { width / 2 - 100, height / 2 - 20, 200, 50 }; bool resume_hover = CheckCollisionPointRec(GetMousePosition(), resume_btn); DrawRectangleRec(resume_btn, resume_hover ? (Color){ 80, 80, 130, 255 } : (Color){ 50, 50, 90, 255 }); DrawRectangleLinesEx(resume_btn, 2, RAYWHITE); DrawText("RESUME", resume_btn.x + 53, resume_btn.y + 12, 30, RAYWHITE); /* Quit button. */ Rectangle quit_btn = { width / 2 - 100, height / 2 + 50, 200, 50 }; bool quit_hover = CheckCollisionPointRec(GetMousePosition(), quit_btn); DrawRectangleRec(quit_btn, quit_hover ? (Color){ 130, 50, 50, 255 } : (Color){ 90, 30, 30, 255 }); DrawRectangleLinesEx(quit_btn, 2, RAYWHITE); DrawText("QUIT", quit_btn.x + 68, quit_btn.y + 12, 30, RAYWHITE); /* Handle clicks. */ if (resume_hover && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) return PAUSE_RESUME; if (quit_hover && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) return PAUSE_QUIT; return PAUSE_NONE; } /* --- MAIN --- */ int main(int argc, char *argv[]) { (void)argc; (void)argv; const int screen_width = 720; const int screen_height = 480; InitWindow(screen_width, screen_height, "prj tiny"); SetTargetFPS(60); SetExitKey(KEY_NULL); /* Take over ESC ourselves. */ /* 3D Camera. */ Camera3D camera = { 0 }; camera.position = (Vector3){ 0.0f, 2.0f, 8.0f }; camera.target = (Vector3){ 0.0f, 1.0f, 0.0f }; camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; camera.fovy = 60.0f; camera.projection = CAMERA_PERSPECTIVE; Star stars[STAR_COUNT]; InitStars(stars, STAR_COUNT, screen_width, screen_height); bool paused = false; DisableCursor(); /* Capture mouse for camera look. */ while (!WindowShouldClose()) { /* --- INPUT --- */ if (IsKeyPressed(KEY_ESCAPE)) { paused = !paused; if (paused) EnableCursor(); else DisableCursor(); } if (!paused) UpdateCamera(&camera, CAMERA_FIRST_PERSON); /* --- DRAW --- */ float time = (float)GetTime(); BeginDrawing(); ClearBackground(BLACK); DrawSky(screen_width, screen_height); DrawStars(stars, STAR_COUNT, time); BeginMode3D(camera); DrawPlane((Vector3){ 0, 0, 0 }, (Vector2){ 256, 256 }, BEIGE); DrawCube((Vector3){ 0, 1.05f, 0 }, 2, 2, 2, RED); EndMode3D(); if (!paused) { DrawCrosshair(screen_width, screen_height); DrawText("prj tiny - ESC to pause", 10, 10, 20, DARKGRAY); } else { PauseAction action = DrawPauseMenu(screen_width, screen_height); if (action == PAUSE_RESUME) { paused = false; DisableCursor(); } else if (action == PAUSE_QUIT) break; } EndDrawing(); } CloseWindow(); return 0; }