diff --git a/ROADMAP.md b/ROADMAP.md index c954920..1bfa281 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -3,7 +3,11 @@ This is a living document that tracks the development progress of the AI Snake Game project. ## Current Status -Last Updated: [Initial Version] +Last Updated: [Food System Implementation] +- Added Food class with spawning mechanics +- Integrated food system with main game loop +- Implemented basic scoring system +- Added game over screen with score display ## Phase 1: Project Setup and Basic Structure ✅ - [x] Create project structure and virtual environment @@ -15,16 +19,16 @@ Last Updated: [Initial Version] ## Phase 2: Core Game Development 🔄 - [x] Implement basic game window using Pygame - [x] Create Snake class with movement mechanics -- [ ] Implement food spawning system - - [ ] Create Food class - - [ ] Add random food placement - - [ ] Add collision detection with food +- [x] Implement food spawning system + - [x] Create Food class + - [x] Add random food placement + - [x] Add collision detection with food - [x] Add collision detection (walls and self) -- [ ] Implement scoring system - - [ ] Add score display +- [x] Implement scoring system + - [x] Add score display - [ ] Add high score tracking -- [ ] Add game over conditions - - [ ] Implement game over state transition +- [x] Add game over conditions + - [x] Implement game over state transition - [ ] Add restart functionality ## Phase 3: Game Polish and UI @@ -73,18 +77,18 @@ Last Updated: [Initial Version] - [ ] Final testing and refinements ## Next Steps -1. Implement the food spawning system - - Create Food class - - Add random food placement logic -2. Add scoring system - - Implement score tracking - - Add score display -3. Complete game over conditions - - Add game over state handling - - Implement restart functionality -4. Create main menu interface +1. Add restart functionality + - Implement game restart on key press + - Reset score and snake position +2. Create main menu interface - Design menu layout - Implement menu navigation +3. Add high score system + - Implement score persistence + - Add high score display +4. Add visual and sound effects + - Implement basic animations + - Add game sounds ## Known Issues - None reported yet diff --git a/src/food.py b/src/food.py new file mode 100644 index 0000000..78156fd --- /dev/null +++ b/src/food.py @@ -0,0 +1,52 @@ +import pygame +import random +from typing import Tuple, List + +class Food: + def __init__(self, block_size: int, color: Tuple[int, int, int] = (255, 0, 0)): + self.block_size = block_size + self.color = color + self.position = (0, 0) # Will be set by spawn() + + def spawn(self, width: int, height: int, occupied_positions: List[Tuple[int, int]]) -> None: + """ + Spawn food at a random position that isn't occupied by the snake. + + Args: + width: Game area width + height: Game area height + occupied_positions: List of positions (typically snake body positions) where food shouldn't spawn + """ + # Calculate valid grid positions + valid_x = range(0, width, self.block_size) + valid_y = range(0, height, self.block_size) + + # Create list of all possible positions + all_positions = [ + (x, y) for x in valid_x for y in valid_y + if (x, y) not in occupied_positions + ] + + if not all_positions: + # No valid positions (snake fills screen) - game should be won + return + + # Choose random position + self.position = random.choice(all_positions) + + def draw(self, screen: pygame.Surface) -> None: + """Draw the food on the screen""" + pygame.draw.rect( + screen, + self.color, + pygame.Rect( + self.position[0], + self.position[1], + self.block_size, + self.block_size + ) + ) + + def check_collision(self, position: Tuple[int, int]) -> bool: + """Check if the given position collides with the food""" + return self.position == position \ No newline at end of file diff --git a/src/game.py b/src/game.py index 0564f8b..1f44798 100644 --- a/src/game.py +++ b/src/game.py @@ -1,6 +1,8 @@ import pygame import sys from enum import Enum, auto +from snake import Snake, Direction +from food import Food class GameState(Enum): MENU = auto() @@ -20,9 +22,18 @@ class Game: self.clock = pygame.time.Clock() self.fps = 60 + # Game objects + self.block_size = 20 + self.snake = Snake((self.width // 2, self.height // 2), self.block_size) + self.food = Food(self.block_size) + + # Spawn initial food + self.food.spawn(self.width, self.height, self.snake.body) + # Game state - self.state = GameState.MENU + self.state = GameState.PLAYING # Changed to start in playing state for now self.running = True + self.score = 0 def handle_events(self): for event in pygame.event.get(): @@ -34,37 +45,62 @@ class Game: self.state = GameState.PAUSED elif self.state == GameState.PAUSED: self.state = GameState.PLAYING + elif self.state == GameState.PLAYING: + # Handle snake direction + if event.key == pygame.K_UP: + self.snake.change_direction(Direction.UP) + elif event.key == pygame.K_DOWN: + self.snake.change_direction(Direction.DOWN) + elif event.key == pygame.K_LEFT: + self.snake.change_direction(Direction.LEFT) + elif event.key == pygame.K_RIGHT: + self.snake.change_direction(Direction.RIGHT) def update(self): if self.state == GameState.PLAYING: - # Update game logic here - pass - elif self.state == GameState.MENU: - # Update menu logic here - pass - elif self.state == GameState.GAME_OVER: - # Update game over logic here - pass - elif self.state == GameState.PAUSED: - # Update pause menu logic here - pass + # Move snake + if self.snake.move(pygame.time.get_ticks()): + # Check wall collision + if self.snake.check_collision(self.width, self.height): + self.state = GameState.GAME_OVER + return + + # Check food collision + if self.food.check_collision(self.snake.body[0]): + self.snake.grow() + self.score += 1 + self.food.spawn(self.width, self.height, self.snake.body) def render(self): # Clear screen self.screen.fill((0, 0, 0)) # Black background - if self.state == GameState.PLAYING: - # Render game here - pass - elif self.state == GameState.MENU: - # Render menu here - pass + if self.state == GameState.PLAYING or self.state == GameState.PAUSED: + # Draw game objects + self.snake.draw(self.screen) + self.food.draw(self.screen) + + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + + # Draw pause indicator + if self.state == GameState.PAUSED: + pause_text = font.render('PAUSED', True, (255, 255, 255)) + text_rect = pause_text.get_rect(center=(self.width//2, self.height//2)) + self.screen.blit(pause_text, text_rect) + elif self.state == GameState.GAME_OVER: - # Render game over screen here - pass - elif self.state == GameState.PAUSED: - # Render pause menu here - pass + font = pygame.font.Font(None, 74) + text = font.render('Game Over!', True, (255, 0, 0)) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + + text_rect = text.get_rect(center=(self.width//2, self.height//2 - 50)) + score_rect = score_text.get_rect(center=(self.width//2, self.height//2 + 50)) + + self.screen.blit(text, text_rect) + self.screen.blit(score_text, score_rect) # Update display pygame.display.flip()