diff options
Diffstat (limited to 'src/splitscreen_duo/games')
| -rw-r--r-- | src/splitscreen_duo/games/benchmark.py | 50 | ||||
| -rw-r--r-- | src/splitscreen_duo/games/breakout.py | 57 | ||||
| -rw-r--r-- | src/splitscreen_duo/games/game_base.py | 120 | ||||
| -rw-r--r-- | src/splitscreen_duo/games/pong.py | 99 | ||||
| -rw-r--r-- | src/splitscreen_duo/games/snake.py | 56 |
5 files changed, 229 insertions, 153 deletions
diff --git a/src/splitscreen_duo/games/benchmark.py b/src/splitscreen_duo/games/benchmark.py index efe48c3..13b14f7 100644 --- a/src/splitscreen_duo/games/benchmark.py +++ b/src/splitscreen_duo/games/benchmark.py @@ -1,10 +1,12 @@ import pygame import random +import os from splitscreen_duo.command import Command BLACK = (0, 0, 0) WHITE = (255, 255, 255) +ROTATION_ENABLED = os.getenv("DEVELOPMENT", "") in ["", "0"] BALL_SIZE = 25 @@ -16,10 +18,34 @@ class Ball: self.change_y = random.randrange(-2, 3) +def draw_game(surface, ball_list, fps, balls, is_vertical, screen_width, screen_height): + surface.fill(BLACK) + + for ball in ball_list: + pygame.draw.circle(surface, WHITE, [int(ball.x), int(ball.y)], BALL_SIZE) + + fps_text = pygame.font.render(f"FPS: {fps:.1f}", True, WHITE) + ball_text = pygame.font.render(f"Balls: {balls}", True, WHITE) + + if is_vertical: + surface.blit(fps_text, (screen_width // 2 - fps_text.get_width() // 2, 10)) + surface.blit(ball_text, (screen_width // 2 - ball_text.get_width() // 2, 40)) + else: + surface.blit(fps_text, (10, 10)) + surface.blit(ball_text, (10, 40)) + def main_loop(screen, serial): clock = pygame.time.Clock() screen_width = screen.get_width() screen_height = screen.get_height() + instance = os.getenv("INSTANCE", "Unknown") + rotation_angle = 0 + + if ROTATION_ENABLED: + if instance == "primary": + rotation_angle = 90 # Right is down + elif instance == "secondary": + rotation_angle = -90 # Left is down global BALL_SIZE @@ -76,21 +102,23 @@ def main_loop(screen, serial): if b.y > screen_height - BALL_SIZE: b.y = screen_height - BALL_SIZE - screen.fill(BLACK) + fps = clock.get_fps() - for ball in ball_list: - pygame.draw.circle(screen, WHITE, [int(ball.x), int(ball.y)], BALL_SIZE) + if ROTATION_ENABLED and rotation_angle != 0 and not is_vertical: + render_surface = pygame.Surface((screen_width, screen_height)) - fps = clock.get_fps() - fps_text = font.render(f"FPS: {fps:.1f}", True, WHITE) - ball_text = font.render(f"Balls: {balls}", True, WHITE) + draw_game(render_surface, ball_list, fps, balls, is_vertical, screen_width, screen_height) + + rotated = pygame.transform.rotate(render_surface, rotation_angle) + + screen.fill(BLACK) + + pos_x = (screen_width - rotated.get_width()) // 2 + pos_y = (screen_height - rotated.get_height()) // 2 - if is_vertical: - screen.blit(fps_text, (screen_width // 2 - fps_text.get_width() // 2, 10)) - screen.blit(ball_text, (screen_width // 2 - ball_text.get_width() // 2, 40)) + screen.blit(rotated, (pos_x, pos_y)) else: - screen.blit(fps_text, (10, 10)) - screen.blit(ball_text, (10, 40)) + draw_game(screen, ball_list, fps, balls, is_vertical, screen_width, screen_height) pygame.display.flip() # clock.tick(60) diff --git a/src/splitscreen_duo/games/breakout.py b/src/splitscreen_duo/games/breakout.py index 6a5e2cc..8506b75 100644 --- a/src/splitscreen_duo/games/breakout.py +++ b/src/splitscreen_duo/games/breakout.py @@ -124,6 +124,31 @@ class Breakout(GameBase): return None + def draw_game(self, surface): + surface.fill(BLACK) + pygame.draw.rect( + surface, + BLUE, + [self.paddle[0], self.paddle[1], PADDLE_WIDTH, PADDLE_HEIGHT], + ) + pygame.draw.circle( + surface, + WHITE, + [int(self.ball[0]), int(self.ball[1])], + BALL_SIZE, + ) + + for brick in self.bricks: + pygame.draw.rect(surface, RED, brick) + + 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: + surface.blit(score_text, (self.screen_width // 2 - score_text.get_width() // 2, 10)) + else: + surface.blit(score_text, (10, 10)) + def main_loop(self): clock = pygame.time.Clock() @@ -135,11 +160,10 @@ class Breakout(GameBase): 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) + action = self.handle_common_events(event) - if result is not None: - return result + if isinstance(action, dict) and action.get("command") is not None: + return action if action == "LEFT": self.move_paddle(-20) @@ -159,30 +183,7 @@ class Breakout(GameBase): continue - self.screen.fill(BLACK) - pygame.draw.rect( - self.screen, - BLUE, - [self.paddle[0], self.paddle[1], PADDLE_WIDTH, PADDLE_HEIGHT], - ) - pygame.draw.circle( - self.screen, - WHITE, - [int(self.ball[0]), int(self.ball[1])], - BALL_SIZE, - ) - - for brick in self.bricks: - pygame.draw.rect(self.screen, RED, brick) - - 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)) - + self.render_rotated(self.draw_game) pygame.display.flip() clock.tick(60) diff --git a/src/splitscreen_duo/games/game_base.py b/src/splitscreen_duo/games/game_base.py index a539ba0..20387c2 100644 --- a/src/splitscreen_duo/games/game_base.py +++ b/src/splitscreen_duo/games/game_base.py @@ -7,6 +7,8 @@ import os logger = logging.getLogger(__name__) +ROTATION_ENABLED = os.getenv("DEVELOPMENT", "") in ["", "0"] + class GameBase: def __init__(self, screen, serial, instance, is_joint_mode=False): @@ -23,20 +25,29 @@ class GameBase: 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 + self.rotation_angle = 0 + self.rotated_surface = None + + if ROTATION_ENABLED and not is_joint_mode: + if instance == "primary": + self.rotation_angle = 90 # Right is down + elif instance == "secondary": + self.rotation_angle = -90 # Left is down + + self.input_handler = Input(debug=os.getenv("DEVELOPMENT", "").lower() != "") def handle_common_events(self, event): - action = self.input_handler.get_input(event) + action = self.input_handler.get_input(event, self.rotation_angle, self.is_joint_mode) 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 + return action def check_serial(self): if self.serial.in_waiting() > 0: @@ -103,10 +114,56 @@ class GameBase: 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.is_vertical = self.is_joint_mode or current_height > current_width * 1.5 + + if ROTATION_ENABLED and not self.is_joint_mode: + if self.instance == "primary": + self.rotation_angle = 90 + elif self.instance == "secondary": + self.rotation_angle = -90 + else: + self.rotation_angle = 0 self.reset() - logger.debug(f"screen dimensions updated: {self.screen_width}x{self.screen_height}, vertical: {self.is_vertical}") + logger.debug(f"screen dimensions updated: {self.screen_width}x{self.screen_height}, vertical: {self.is_vertical}, rotation: {self.rotation_angle}°") + + def draw_waiting_screen(self, surface): + surface.fill(self.BLACK) + + text = self.font.render("Waiting for opponent ...", True, self.WHITE) + + surface.blit( + text, + ( + self.screen_width // 2 - text.get_width() // 2, + self.screen_height // 2, + ), + ) + + def draw_score_display(self, surface): + surface.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 + ) + + spacing = 30 if self.is_vertical else 20 + + surface.blit( + my_text, + ( + self.screen_width // 2 - my_text.get_width() // 2, + self.screen_height // 2 - spacing, + ), + ) + surface.blit( + opp_text, + ( + self.screen_width // 2 - opp_text.get_width() // 2, + self.screen_height // 2 + spacing, + ), + ) def update(self): self.update_screen_dimensions() @@ -115,17 +172,7 @@ class GameBase: 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, - ), - ) + self.render_rotated(self.draw_waiting_screen) pygame.display.flip() if self.serial.in_waiting() > 0: @@ -150,27 +197,7 @@ class GameBase: "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, - ), - ) + self.render_rotated(self.draw_score_display) pygame.display.flip() if pygame.time.get_ticks() - self.score_display_time > 3000: @@ -182,5 +209,24 @@ class GameBase: return None + def render_rotated(self, draw_function): + if ROTATION_ENABLED and not self.is_joint_mode and self.rotation_angle != 0: + render_surface = pygame.Surface((self.screen_width, self.screen_height)) + + render_surface.fill(self.BLACK) + + draw_function(render_surface) + + rotated = pygame.transform.rotate(render_surface, self.rotation_angle) + + self.screen.fill(self.BLACK) + + pos_x = (self.screen_width - rotated.get_width()) // 2 + pos_y = (self.screen_height - rotated.get_height()) // 2 + + self.screen.blit(rotated, (pos_x, pos_y)) + else: + draw_function(self.screen) + def main_loop(self): raise NotImplementedError diff --git a/src/splitscreen_duo/games/pong.py b/src/splitscreen_duo/games/pong.py index d82cdc7..c912197 100644 --- a/src/splitscreen_duo/games/pong.py +++ b/src/splitscreen_duo/games/pong.py @@ -127,6 +127,52 @@ class Pong(GameBase): return None + def draw_game(self, surface): + surface.fill(BLACK) + pygame.draw.rect( + surface, + WHITE, + [ + self.player_paddle[0], + self.player_paddle[1], + PADDLE_WIDTH, + PADDLE_HEIGHT, + ], + ) + pygame.draw.rect( + surface, + WHITE, + [self.ai_paddle[0], self.ai_paddle[1], PADDLE_WIDTH, PADDLE_HEIGHT], + ) + pygame.draw.circle( + surface, + WHITE, + [int(self.ball[0]), int(self.ball[1])], + BALL_SIZE, + ) + + if not self.is_joint_mode or self.instance != "primary": + player_score_text = self.font.render( + f"Player: {self.player_score}", True, WHITE + ) + ai_score_text = self.font.render( + f"AI: {self.ai_score}", True, WHITE + ) + + if self.is_vertical: + surface.blit( + player_score_text, + (self.screen_width // 2 - player_score_text.get_width() // 2, + self.screen_height - 40) + ) + surface.blit( + ai_score_text, + (self.screen_width // 2 - ai_score_text.get_width() // 2, 10) + ) + else: + surface.blit(player_score_text, (10, self.screen_height - 40)) + surface.blit(ai_score_text, (10, 10)) + def update(self): self.update_screen_dimensions() @@ -182,11 +228,10 @@ class Pong(GameBase): if not self.score_display_time: for event in pygame.event.get(): - result = self.handle_common_events(event) - action = self.input_handler.get_input(event) + action = self.handle_common_events(event) - if result is not None: - return result + if isinstance(action, dict) and action.get("command") is not None: + return action if action == "LEFT": self.move_player_paddle(-PADDLE_SPEED) @@ -213,51 +258,7 @@ class Pong(GameBase): continue - self.screen.fill(BLACK) - pygame.draw.rect( - self.screen, - WHITE, - [ - self.player_paddle[0], - self.player_paddle[1], - PADDLE_WIDTH, - PADDLE_HEIGHT, - ], - ) - pygame.draw.rect( - self.screen, - WHITE, - [self.ai_paddle[0], self.ai_paddle[1], PADDLE_WIDTH, PADDLE_HEIGHT], - ) - pygame.draw.circle( - self.screen, - WHITE, - [int(self.ball[0]), int(self.ball[1])], - BALL_SIZE, - ) - - if not self.is_joint_mode or self.instance != "primary": - player_score_text = self.font.render( - f"Player: {self.player_score}", True, WHITE - ) - ai_score_text = self.font.render( - f"AI: {self.ai_score}", True, WHITE - ) - - if self.is_vertical: - self.screen.blit( - player_score_text, - (self.screen_width // 2 - player_score_text.get_width() // 2, - self.screen_height - 40) - ) - self.screen.blit( - ai_score_text, - (self.screen_width // 2 - ai_score_text.get_width() // 2, 10) - ) - else: - self.screen.blit(player_score_text, (10, self.screen_height - 40)) - self.screen.blit(ai_score_text, (10, 10)) - + self.render_rotated(self.draw_game) pygame.display.flip() clock.tick(60) diff --git a/src/splitscreen_duo/games/snake.py b/src/splitscreen_duo/games/snake.py index 11b66f7..fe34143 100644 --- a/src/splitscreen_duo/games/snake.py +++ b/src/splitscreen_duo/games/snake.py @@ -94,6 +94,30 @@ class Snake(GameBase): or head in self.body[1:] ) + def draw_game(self, surface): + surface.fill(BLACK) + + for segment in self.body: + pygame.draw.rect( + surface, + GREEN, + [segment[0], segment[1], BLOCK_SIZE, BLOCK_SIZE], + ) + + pygame.draw.rect( + surface, + 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: + surface.blit(score_text, (self.screen_width // 2 - score_text.get_width() // 2, 10)) + else: + surface.blit(score_text, (10, 10)) + def main_loop(self): clock = pygame.time.Clock() @@ -105,11 +129,10 @@ class Snake(GameBase): 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) + action = self.handle_common_events(event) - if result is not None: - return result + if isinstance(action, dict) and action.get("command") is not None: + return action if action == "UP": self.change_to = "UP" @@ -125,32 +148,9 @@ class Snake(GameBase): 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)) - + self.render_rotated(self.draw_game) pygame.display.flip() clock.tick(SPEED) |