import pygame import random from ..command import Command from .game_base import GameBase import logging BLACK = (0, 0, 0) WHITE = (255, 255, 255) PADDLE_WIDTH = 100 PADDLE_HEIGHT = 10 BALL_SIZE = 10 PADDLE_SPEED = 10 AI_SPEED = 4 BALL_SPEED = 5 logger = logging.getLogger(__name__) class Pong(GameBase): def __init__(self, screen, serial, instance, is_joint_mode=False): super().__init__(screen, serial, instance, is_joint_mode) self.player_score = 0 self.ai_score = 0 self.score_display_time = 0 self.reset() def reset(self): global PADDLE_WIDTH, PADDLE_HEIGHT, BALL_SIZE, PADDLE_SPEED, AI_SPEED, BALL_SPEED scale_factor = min(self.screen_width / 640, self.screen_height / 480) if self.is_vertical: PADDLE_WIDTH = min(100, int(80 * scale_factor)) PADDLE_SPEED = max(5, min(8, int(8 * scale_factor))) else: PADDLE_WIDTH = min(100, int(100 * scale_factor)) PADDLE_SPEED = max(8, min(10, int(10 * scale_factor))) PADDLE_HEIGHT = max(8, int(10 * scale_factor)) BALL_SIZE = max(6, int(10 * scale_factor)) AI_SPEED = max(3, min(4, int(4 * scale_factor))) BALL_SPEED = max(4, min(5, int(5 * scale_factor))) self.player_paddle = [ self.screen_width // 2 - PADDLE_WIDTH // 2, self.screen_height - 40, ] self.ai_paddle = [self.screen_width // 2 - PADDLE_WIDTH // 2, 40] self.ball = [self.screen_width // 2, self.screen_height // 2] self.ball_dx = random.choice([-BALL_SPEED, BALL_SPEED]) self.ball_dy = BALL_SPEED def move_player_paddle(self, dx): self.player_paddle[0] += dx if self.player_paddle[0] < 0: self.player_paddle[0] = 0 if self.player_paddle[0] > self.screen_width - PADDLE_WIDTH: self.player_paddle[0] = self.screen_width - PADDLE_WIDTH def move_ai_paddle(self): if random.random() < 0.8: if self.ai_paddle[0] + PADDLE_WIDTH // 2 < self.ball[0]: self.ai_paddle[0] += AI_SPEED elif self.ai_paddle[0] + PADDLE_WIDTH // 2 > self.ball[0]: self.ai_paddle[0] -= AI_SPEED if self.ai_paddle[0] < 0: self.ai_paddle[0] = 0 if self.ai_paddle[0] > self.screen_width - PADDLE_WIDTH: self.ai_paddle[0] = self.screen_width - PADDLE_WIDTH def move_ball(self): self.ball[0] += self.ball_dx self.ball[1] += self.ball_dy if self.ball[0] <= BALL_SIZE or self.ball[0] >= self.screen_width - BALL_SIZE: self.ball_dx *= -1 player_rect = pygame.Rect( self.player_paddle[0], self.player_paddle[1], PADDLE_WIDTH, PADDLE_HEIGHT ) ai_rect = pygame.Rect( self.ai_paddle[0], self.ai_paddle[1], PADDLE_WIDTH, PADDLE_HEIGHT ) ball_rect = pygame.Rect( self.ball[0] - BALL_SIZE, self.ball[1] - BALL_SIZE, BALL_SIZE * 2, BALL_SIZE * 2, ) if ball_rect.colliderect(player_rect) and self.ball_dy > 0: self.ball_dy *= -1 hit_pos = (self.ball[0] - self.player_paddle[0]) / PADDLE_WIDTH self.ball_dx = BALL_SPEED * (hit_pos - 0.5) * 2 elif ball_rect.colliderect(ai_rect) and self.ball_dy < 0: self.ball_dy *= -1 hit_pos = (self.ball[0] - self.ai_paddle[0]) / PADDLE_WIDTH self.ball_dx = BALL_SPEED * (hit_pos - 0.5) * 2 if self.ball[1] <= 0: self.player_score += 1 self.send_stats(self.player_score) self.reset_ball() elif self.ball[1] >= self.screen_height: self.ai_score += 1 self.send_stats(self.player_score) self.reset_ball() def reset_ball(self): self.ball = [self.screen_width // 2, self.screen_height // 2] self.ball_dx = random.choice([-BALL_SPEED, BALL_SPEED]) self.ball_dy = random.choice([-BALL_SPEED, BALL_SPEED]) def check_game_over(self): if self.player_score >= 5: return "win" if self.ai_score >= 5: return "lose" return None def update(self): self.update_screen_dimensions() if self.score_display_time: self.screen.fill(BLACK) result_text = "You Won!" if self.player_score >= 5 else "You Lost!" result_display = self.font.render(result_text, True, WHITE) player_score_text = self.font.render( f"Your Score: {self.player_score}", True, WHITE ) ai_score_text = self.font.render(f"AI Score: {self.ai_score}", True, WHITE) vertical_spacing = 30 if self.is_vertical else 20 self.screen.blit( result_display, ( self.screen_width // 2 - result_display.get_width() // 2, self.screen_height // 2 - vertical_spacing * 2, ), ) self.screen.blit( player_score_text, ( self.screen_width // 2 - player_score_text.get_width() // 2, self.screen_height // 2, ), ) self.screen.blit( ai_score_text, ( self.screen_width // 2 - ai_score_text.get_width() // 2, self.screen_height // 2 + vertical_spacing, ), ) pygame.display.flip() if pygame.time.get_ticks() - self.score_display_time > 3000: logger.debug("score display timeout reached, exiting pong") self.is_running = False return None 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.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 == "LEFT": self.move_player_paddle(-PADDLE_SPEED) elif action == "RIGHT": self.move_player_paddle(PADDLE_SPEED) keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: self.move_player_paddle(-PADDLE_SPEED) elif keys[pygame.K_RIGHT]: self.move_player_paddle(PADDLE_SPEED) self.move_ai_paddle() self.move_ball() game_over = self.check_game_over() if game_over: if self.is_joint_mode and self.instance == "primary": self.send_stats(self.player_score) self.end_game(self.player_score) 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)) pygame.display.flip() clock.tick(60) return None