diff --git a/game.c b/game.c index 79d845f90ae55b74857d445a7211f6658b77aa6d..b0275ca08b584e922666eeaa647c963f55fe751b 100644 --- a/game.c +++ b/game.c @@ -1,71 +1,154 @@ -#include "game.h" +#include "raylib.h" #include <stdlib.h> +#include <time.h> -Paddle *CreatePaddle(float x, float y, float width, float height, int speed) { - Paddle *p = (Paddle *)malloc(sizeof(Paddle)); - p->rect = (Rectangle){x, y, width, height}; - p->speed = speed; - return p; -} +#define SQUARE_SIZE 20 +#define MAX_SNAKE_LENGTH 256 +#define SCREEN_WIDTH 800 +#define SCREEN_HEIGHT 600 + +typedef struct SnakeSegment { + int x, y; +} SnakeSegment; + +typedef enum Direction { UP, DOWN, LEFT, RIGHT } Direction; + +typedef enum GameState { MENU, GAMEPLAY, GAMEOVER } GameState; -Ball *CreateBall(float x, float y, int radius, float speedX, float speedY) { - Ball *b = (Ball *)malloc(sizeof(Ball)); - b->position = (Vector2){x, y}; - b->speed = (Vector2){speedX, speedY}; - b->radius = radius; - b->score = 0; - b->lives = 3; - b->isGameOver = false; - return b; +int GetSpeedForLevel(int level) { + return 10 + (level - 1) * 3; // Level 1 = 10 FPS, Level 5 = 22 FPS } -void UpdateBall(Ball *ball, Paddle *paddle) { - ball->position.x += ball->speed.x; - ball->position.y += ball->speed.y; +int main(void) { + InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Snake Game - Level Select (raylib)"); + SetTargetFPS(60); // default menu framerate - // Bounce off top and bottom - if (ball->position.y <= 0 || ball->position.y + ball->radius >= 450) { - ball->speed.y *= -1; - } + SnakeSegment snake[MAX_SNAKE_LENGTH]; + int snakeLength = 5; + Direction dir = RIGHT; - // Bounce off paddle - if (CheckCollisionCircleRec(ball->position, ball->radius, paddle->rect)) { - ball->speed.x *= -1; - ball->score++; + SnakeSegment food; - // ✅ Level progression: increase speed every 5 points - if (ball->score % 5 == 0) { - if (ball->speed.x > 0) ball->speed.x += 1; - else ball->speed.x -= 1; + int level = 1; + int score = 0; + int speed = 10; - if (ball->speed.y > 0) ball->speed.y += 1; - else ball->speed.y -= 1; - } - } + GameState gameState = MENU; + + bool gameOver = false; + + while (!WindowShouldClose()) { + switch (gameState) { + case MENU: + // Handle level selection + if (IsKeyPressed(KEY_ONE)) { level = 1; gameState = GAMEPLAY; } + if (IsKeyPressed(KEY_TWO)) { level = 2; gameState = GAMEPLAY; } + if (IsKeyPressed(KEY_THREE)) { level = 3; gameState = GAMEPLAY; } + if (IsKeyPressed(KEY_FOUR)) { level = 4; gameState = GAMEPLAY; } + if (IsKeyPressed(KEY_FIVE)) { level = 5; gameState = GAMEPLAY; } + + if (gameState == GAMEPLAY) { + // Initialize game + snakeLength = 5; + score = 0; + dir = RIGHT; + speed = GetSpeedForLevel(level); + SetTargetFPS(speed); + + for (int i = 0; i < snakeLength; i++) { + snake[i].x = 10 - i; + snake[i].y = 10; + } + + food.x = GetRandomValue(0, SCREEN_WIDTH/SQUARE_SIZE - 1); + food.y = GetRandomValue(0, SCREEN_HEIGHT/SQUARE_SIZE - 1); + gameOver = false; + } + break; + + case GAMEPLAY: + if (!gameOver) { + // Input + if (IsKeyPressed(KEY_UP) && dir != DOWN) dir = UP; + if (IsKeyPressed(KEY_DOWN) && dir != UP) dir = DOWN; + if (IsKeyPressed(KEY_LEFT) && dir != RIGHT) dir = LEFT; + if (IsKeyPressed(KEY_RIGHT) && dir != LEFT) dir = RIGHT; - // Ball missed paddle - if (ball->position.x < 0) { - ball->lives--; - ball->position = (Vector2){400, 225}; + // Move body + for (int i = snakeLength - 1; i > 0; i--) { + snake[i] = snake[i - 1]; + } - // Reset to base speed - ball->speed = (Vector2){4, 4}; + // Move head + if (dir == UP) snake[0].y--; + if (dir == DOWN) snake[0].y++; + if (dir == LEFT) snake[0].x--; + if (dir == RIGHT) snake[0].x++; - if (ball->lives <= 0) { - ball->isGameOver = true; + // Wall collision + if (snake[0].x < 0 || snake[0].x >= SCREEN_WIDTH/SQUARE_SIZE || + snake[0].y < 0 || snake[0].y >= SCREEN_HEIGHT/SQUARE_SIZE) { + gameOver = true; + } + + // Self collision + for (int i = 1; i < snakeLength; i++) { + if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) { + gameOver = true; + } + } + + // Food collision + if (snake[0].x == food.x && snake[0].y == food.y) { + if (snakeLength < MAX_SNAKE_LENGTH) snakeLength++; + score++; + food.x = GetRandomValue(0, SCREEN_WIDTH/SQUARE_SIZE - 1); + food.y = GetRandomValue(0, SCREEN_HEIGHT/SQUARE_SIZE - 1); + } + } else { + if (IsKeyPressed(KEY_ENTER)) { + gameState = MENU; + SetTargetFPS(60); // back to menu framerate + } + } + break; + + default: break; } - } -} -void DrawGame(Paddle *paddle, Ball *ball) { - DrawRectangleRec(paddle->rect, BLUE); - DrawCircleV(ball->position, ball->radius, RED); + // Draw + BeginDrawing(); + ClearBackground(DARKGRAY); + + if (gameState == MENU) { + DrawText("SNAKE GAME", SCREEN_WIDTH/2 - 100, 100, 40, GREEN); + DrawText("Choose Level:", SCREEN_WIDTH/2 - 80, 200, 30, LIGHTGRAY); + DrawText("Press [1] Level 1 (Slow)", SCREEN_WIDTH/2 - 100, 250, 20, WHITE); + DrawText("Press [2] Level 2", SCREEN_WIDTH/2 - 100, 280, 20, WHITE); + DrawText("Press [3] Level 3", SCREEN_WIDTH/2 - 100, 310, 20, WHITE); + DrawText("Press [4] Level 4", SCREEN_WIDTH/2 - 100, 340, 20, WHITE); + DrawText("Press [5] Level 5 (Fast)", SCREEN_WIDTH/2 - 100, 370, 20, WHITE); + } + + if (gameState == GAMEPLAY) { + if (!gameOver) { + for (int i = 0; i < snakeLength; i++) { + DrawRectangle(snake[i].x * SQUARE_SIZE, snake[i].y * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE, i == 0 ? GREEN : LIME); + } + + DrawRectangle(food.x * SQUARE_SIZE, food.y * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE, RED); - DrawText(TextFormat("Score: %d", ball->score), 10, 10, 20, DARKGRAY); - DrawText(TextFormat("Lives: %d", ball->lives), 10, 40, 20, MAROON); + DrawText(TextFormat("SCORE: %d", score), 10, 10, 20, WHITE); + DrawText(TextFormat("LEVEL: %d", level), 10, 40, 20, YELLOW); + } else { + DrawText("GAME OVER!", SCREEN_WIDTH/2 - 100, SCREEN_HEIGHT/2 - 20, 40, RED); + DrawText("Press [ENTER] to go back to Menu", SCREEN_WIDTH/2 - 160, SCREEN_HEIGHT/2 + 30, 20, LIGHTGRAY); + } + } - if (ball->isGameOver) { - DrawText("GAME OVER", 300, 200, 40, RED); - DrawText("Press ESC to quit", 300, 250, 20, DARKGRAY); + EndDrawing(); } -} + + CloseWindow(); + return 0; +} \ No newline at end of file