import pygame import json from ..command import Command import logging from ..input import Input import os logger = logging.getLogger(__name__) class GameBase: def __init__(self, screen, serial, instance, is_joint_mode=False): self.screen = screen self.serial = serial self.instance = instance self.is_joint_mode = is_joint_mode self.font = pygame.font.Font(None, 36) self.is_running = True self.opponent_dead = False self.my_score = 0 self.opponent_score = 0 self.waiting = False self.score_display_time = 0 self.BLACK = (0, 0, 0) self.WHITE = (255, 255, 255) self.input_handler = Input(debug=os.getenv("DEVELOPMENT", "").lower() != "") self.screen_width = screen.get_width() self.screen_height = screen.get_height() self.is_vertical = is_joint_mode def handle_common_events(self, event): action = self.input_handler.get_input(event) if event.type == pygame.QUIT: return {"command": Command.QUIT.value, "action": None, "value": None} elif event.type == pygame.KEYDOWN and action == "QUIT": return None return None def check_serial(self): if self.serial.in_waiting() > 0: data = self.serial.readline().decode("utf-8").strip() logger.debug(f"received serial data during check_serial: {data}") message = json.loads(data) if message.get("command") == Command.SCORE.value: self.opponent_dead = True self.opponent_score = message.get("value", 0) return True elif message.get("command") == Command.QUIT.value: return {"command": Command.QUIT.value, "action": None, "value": None} return False def end_game(self, score): if self.is_joint_mode: self.is_running = False if self.instance == "primary": self.serial.write( json.dumps({"command": Command.GAME_ENDED.value}).encode("utf-8") + b"\n" ) else: self.my_score = score self.serial.write( json.dumps( { "command": Command.SCORE.value, "action": None, "value": self.my_score, } ).encode("utf-8") + b"\n" ) if self.opponent_dead: self.score_display_time = pygame.time.get_ticks() logger.debug("opponent already dead, starting score display") else: self.waiting = True logger.debug("waiting for opponent to finish") def send_stats(self, value): if self.is_joint_mode and self.instance == "primary": self.serial.write( json.dumps({"command": Command.STATS.value, "value": value}).encode( "utf-8" ) + b"\n" ) def update_screen_dimensions(self): current_width = self.screen.get_width() current_height = self.screen.get_height() if (current_width != self.screen_width or current_height != self.screen_height): self.screen_width = current_width self.screen_height = current_height self.is_vertical = current_height > current_width * 1.5 self.reset() logger.debug(f"screen dimensions updated: {self.screen_width}x{self.screen_height}, vertical: {self.is_vertical}") def update(self): self.update_screen_dimensions() if self.is_joint_mode: return None if self.waiting: self.screen.fill(self.BLACK) text = self.font.render("Waiting for opponent ...", True, self.WHITE) self.screen.blit( text, ( self.screen.get_width() // 2 - text.get_width() // 2, self.screen.get_height() // 2, ), ) pygame.display.flip() if self.serial.in_waiting() > 0: data = self.serial.readline().decode("utf-8").strip() logger.debug(f"received serial data while waiting: {data}") message = json.loads(data) if message.get("command") == Command.SCORE.value: self.opponent_score = message.get("value", 0) self.waiting = False self.score_display_time = pygame.time.get_ticks() logger.debug("received opponent's score, starting score display") elif message.get("command") == Command.QUIT.value: logger.info("received quit command while waiting") return { "command": Command.QUIT.value, "action": None, "value": None, } elif self.score_display_time: self.screen.fill(self.BLACK) my_text = self.font.render(f"Your Score: {self.my_score}", True, self.WHITE) opp_text = self.font.render( f"Your Opponent's Score: {self.opponent_score}", True, self.WHITE ) self.screen.blit( my_text, ( self.screen.get_width() // 2 - my_text.get_width() // 2, self.screen.get_height() // 2 - 20, ), ) self.screen.blit( opp_text, ( self.screen.get_width() // 2 - opp_text.get_width() // 2, self.screen.get_height() // 2 + 20, ), ) pygame.display.flip() if pygame.time.get_ticks() - self.score_display_time > 3000: logger.debug("score display timeout reached, exiting game") self.is_running = False return None return None def main_loop(self): raise NotImplementedError