import time
import random
from Displays import *
from Buzzer import *
from Button import *
from LightStrip import *
from Log import *
# Game Constants
MAX_SCORE = 10
BALL_SPEEDS = [0.3, 0.5, 0.7] # Different speeds for ball movement
# Game Classes
class DisplayManager:
def __init__(self, sda_pin, scl_pin):
self.display = LCDDisplay(sda=sda_pin, scl=scl_pin)
self.display.reset()
def update_score(self, player1_score, player2_score):
self.display.clear()
self.display.showText(f"P1: {player1_score}", 0, 0)
self.display.showText(f"P2: {player2_score}", 1, 0)
def show_message(self, message):
self.display.clear()
self.display.showText(message, 0, 0)
class SoundManager:
def __init__(self, pin):
self.buzzer = PassiveBuzzer(pin)
def play_hit_sound(self):
self.buzzer.play(500)
time.sleep(0.1)
self.buzzer.stop()
def play_miss_sound(self):
self.buzzer.play(300)
time.sleep(0.2)
self.buzzer.stop()
def play_foul_sound(self):
self.buzzer.play(100)
time.sleep(0.3)
self.buzzer.stop()
class Ball:
def __init__(self, pin, num_leds=8):
self.light_strip = LightStrip(pin, 'neo', num_leds)
self.position = 0
self.direction = 1 # 1 for right, -1 for left
self.speed = random.choice(BALL_SPEEDS)
def reset_position(self, starting_position):
self.position = starting_position
self.direction = 1 if starting_position == 0 else -1
self.light_strip.off()
self.light_strip.setPixel(self.position, (0, 255, 0))
def move(self):
self.light_strip.off()
self.position += self.direction
if self.position >=0 and self.position <=7:
self.light_strip.setPixel(self.position, (0, 255, 0))
# Randomly adjust speed to make the game interesting
if random.random() > 0.8:
self.speed = random.choice(BALL_SPEEDS)
time.sleep(self.speed)
class Player:
def __init__(self, name, position):
self.name = name
self.position = position
self.score = 0
def increment_score(self):
self.score += 1
def reset_score(self):
self.score = 0
class ButtonHandler:
def __init__(self, game_controller):
self.game_controller = game_controller
def buttonPressed(self, name):
self.game_controller.handle_button_press(name)
def buttonReleased(self, name):
pass # We only care about button presses for this game.
class GameController:
def __init__(self):
# Initialize Components
self.display = DisplayManager(sda_pin=0, scl_pin=1)
self.sound = SoundManager(pin=16)
self.ball = Ball(pin=2)
# Player instances
self.player1 = Player(name="player1", position=0)
self.player2 = Player(name="player2", position=7)
# Buttons for each player
self.button_handler = ButtonHandler(self)
self.player1_button = Button(pin=3, name="player1", handler=self.button_handler)
self.player2_button = Button(pin=4, name="player2", handler=self.button_handler)
# Game state
self.server = self.player1 # Player who serves
self.running = False
self.update_display_score()
self.new_round()
def update_display_score(self):
self.display.update_score(self.player1.score, self.player2.score)
def new_round(self):
self.display.show_message(f"{self.server.name} to Serve")
self.ball.reset_position(self.server.position)
def handle_button_press(self, player_name):
# Start game movement if server presses
if not self.running and player_name == self.server.name:
self.start_ball_movement()
return
Log.d(f'press from {player_name}')
# Check for hit or foul
player = self.player1 if player_name == "player1" else self.player2
if player.position == self.ball.position:
self.handle_hit(player)
else:
self.handle_foul(player)
def start_ball_movement(self):
self.running = True
while self.running:
self.ball.move()
if self.ball.position < self.player1.position:
self.handle_miss(self.player2)
elif self.ball.position > self.player2.position:
self.handle_miss(self.player1)
def handle_hit(self, player):
self.sound.play_hit_sound()
self.ball.direction *= -1 # Reverse ball direction
def handle_miss(self, player):
self.sound.play_miss_sound()
opponent = self.player1 if player == self.player2 else self.player2
self.update_score(opponent)
self.running = False
self.new_round()
def handle_foul(self, player):
self.sound.play_foul_sound()
opponent = self.player1 if player == self.player2 else self.player2
self.update_score(opponent)
self.running = False
self.new_round()
def update_score(self, player):
player.increment_score()
self.update_display_score()
# Check for game over
if player.score >= MAX_SCORE:
self.display.show_message(f"{player.name} Wins!")
self.running = False
# Initialize Game
game = GameController()