import pygame import random from ..command import Command from .game_base import GameBase import logging BLACK = (0, 0, 0) WHITE = (255, 255, 255) RED = (255, 0, 0) GREEN = (0, 255, 0) BLOCK_SIZE = 20 SPEED = 15 logger = logging.getLogger(__name__) class Snake(GameBase): def __init__(self, screen, serial, instance, is_joint_mode=False): super().__init__(screen, serial, instance, is_joint_mode) self.reset() def reset(self): global BLOCK_SIZE, SPEED min_dimension = min(self.screen_width, self.screen_height) BLOCK_SIZE = max(10, min(20, min_dimension // 30)) SPEED = 15 if self.screen_width >= 400 else 12 self.body = [ [ self.screen_width // 2 - self.screen_width // 2 % BLOCK_SIZE, self.screen_height // 2 - self.screen_height // 2 % BLOCK_SIZE, ] ] self.direction = "RIGHT" self.change_to = self.direction self.score = 0 self.food = self.spawn_food() def spawn_food(self): while True: food = [ random.randrange(0, self.screen_width // BLOCK_SIZE) * BLOCK_SIZE, random.randrange(0, self.screen_height // BLOCK_SIZE) * BLOCK_SIZE, ] if food not in self.body: return food def move(self): if self.change_to == "UP" and self.direction != "DOWN": self.direction = "UP" if self.change_to == "DOWN" and self.direction != "UP": self.direction = "DOWN" if self.change_to == "LEFT" and self.direction != "RIGHT": self.direction = "LEFT" if self.change_to == "RIGHT" and self.direction != "LEFT": self.direction = "RIGHT" head = [self.body[0][0], self.body[0][1]] if self.direction == "UP": head[1] -= BLOCK_SIZE if self.direction == "DOWN": head[1] += BLOCK_SIZE if self.direction == "LEFT": head[0] -= BLOCK_SIZE if self.direction == "RIGHT": head[0] += BLOCK_SIZE self.body.insert(0, head) if head[0] == self.food[0] and head[1] == self.food[1]: logger.debug( f"snake ate food at {self.food}, score increased to {self.score + 1}" ) self.score += 1 self.send_stats(self.score) self.food = self.spawn_food() else: self.body.pop() def check_collision(self): head = self.body[0] return ( head[0] < 0 or head[0] >= self.screen_width or head[1] < 0 or head[1] >= self.screen_height or head in self.body[1:] ) def main_loop(self): clock = pygame.time.Clock() while self.is_running: result = self.update() if result is not None: return result if not (self.waiting or self.score_display_time): for event in pygame.event.get(): result = self.handle_common_events(event) action = self.input_handler.get_input(event) if result is not None: return result if action == "UP": self.change_to = "UP" elif action == "DOWN": self.change_to = "DOWN" elif action == "LEFT": self.change_to = "LEFT" elif action == "RIGHT": self.change_to = "RIGHT" self.check_serial() self.move() if self.check_collision(): self.end_game(self.score) continue self.screen.fill(BLACK) for segment in self.body: pygame.draw.rect( self.screen, GREEN, [segment[0], segment[1], BLOCK_SIZE, BLOCK_SIZE], ) pygame.draw.rect( self.screen, RED, [self.food[0], self.food[1], BLOCK_SIZE, BLOCK_SIZE], ) if not self.is_joint_mode or self.instance != "primary": score_text = self.font.render(f"Score: {self.score}", True, WHITE) if self.is_vertical: self.screen.blit(score_text, (self.screen_width // 2 - score_text.get_width() // 2, 10)) else: self.screen.blit(score_text, (10, 10)) pygame.display.flip() clock.tick(SPEED) return None