diff --git a/pandemic_pong.py b/pandemic_pong.py index 801b5a8..1797392 100755 --- a/pandemic_pong.py +++ b/pandemic_pong.py @@ -8,7 +8,7 @@ Pandemic python/Qt5 pong clone History: -------- 21.11.20/KQ Initial version -25.11.20/KQ Class based version ;) +25.11.20/KQ Class based version w/ scaling ;) """ import sys, os, fcntl, time, random @@ -28,39 +28,40 @@ from pong_player import PongPlayer from pong_object import PongObject from pong_game import PongGame -def draw_buttonstate(x, y, player, painter): + +def draw_buttonstate(x, y, player, painter, scale_x, scale_y): """Indicate last button pressed (not strictly necessary ...)""" if (player.state & pgc.BTN_TRIGGER) == pgc.BTN_TRIGGER: painter.setPen(QPen(Qt.blue, 1, Qt.SolidLine)) # Color/Linewidth/Pattern painter.setBrush(QBrush(Qt.blue, Qt.SolidPattern)) # Fill - painter.drawEllipse(x, y, 20, 20) # Blue button + painter.drawEllipse(int(x * scale_x), int(y * scale_y), int(20 * scale_x), int(20 * scale_y)) # Blue button if (player.state & pgc.BTN_TOP) == pgc.BTN_TOP: painter.setPen(QPen(Qt.green, 1, Qt.SolidLine)) # Green painter.setBrush(QBrush(Qt.green, Qt.SolidPattern)) - painter.drawEllipse(x + 30, y, 20, 20) + painter.drawEllipse(int((x + 30) * scale_x), int(y * scale_y), int(20 * scale_x), int(20 * scale_y)) if (player.state & pgc.BTN_THUMB) == pgc.BTN_THUMB: painter.setPen(QPen(Qt.red, 1, Qt.SolidLine)) # Red painter.setBrush(QBrush(Qt.red, Qt.SolidPattern)) - painter.drawEllipse(x + 60, y, 20, 20) + painter.drawEllipse(int((x + 60) * scale_x), int(y * scale_y), int(20 * scale_x), int(20 * scale_y)) if (player.state & pgc.BTN_THUMB2) == pgc.BTN_THUMB2: painter.setPen(QPen(Qt.yellow, 1, Qt.SolidLine)) # Yellow painter.setBrush(QBrush(Qt.yellow, Qt.SolidPattern)) - painter.drawEllipse(x + 90, y, 20, 20) + painter.drawEllipse(int((x + 90) * scale_x), int(y * scale_y), int(20 * scale_x), int(20 * scale_y)) class pongWindow(QMainWindow): def __init__(self): super().__init__() self.title = "Pandemic Pong" - self.top= 0 - self.left= 0 - self.width = 1920 - self.height = 960 + self.top = 0 + self.left = 0 + self.win_width = 1920 + self.win_height = 960 self.InitWindow() def InitWindow(self): self.setWindowTitle(self.title) - self.setGeometry(self.top, self.left, self.width, self.height) - #self.showFullScreen() + self.setGeometry(self.top, self.left, self.win_width, self.win_height) + self.showFullScreen() self.pic = QPixmap("pictures/pong_background.png") # Font metrics assume font is monospaced! self.fntLarge = QFont("Monospace", 120) @@ -72,9 +73,16 @@ class pongWindow(QMainWindow): self.fntMedium.setFixedPitch(True) self.show() - playsound('/usr/share/mint-artwork/sounds/close.oga') - playsound('/usr/lib/libreoffice/share/gallery/sounds/laser.wav') # Enforce caching ... - playsound('/usr/share/mint-artwork/sounds/logout.ogg') + + # Enforce caching ... + playsound(pgc.game_win) + playsound(pgc.match_win) + playsound(pgc.player_contact) + playsound(pgc.player_miss) + playsound(pgc.wall_contact) + playsound(pgc.game_exit) + time.sleep(0.5) + playsound(pgc.game_splash) self.timer = QTimer() # Start processing 'loop' self.timer.setInterval(25) # 25ms @@ -85,31 +93,42 @@ class pongWindow(QMainWindow): def paintEvent(self, event): global game, ball, player1, player2 + scale_x = self.width() / pgv.GAMEAREA_MAX_X + scale_y = self.height() / (pgv.GAMEAREA_MAX_Y + 20) # Compensate header + painter = QPainter(self) # Painter need's to be freshly picked ... painter.setPen(QPen(Qt.white, 1, Qt.SolidLine)) # Color/Linewidth/Pattern painter.setBrush(QBrush(Qt.white, Qt.SolidPattern)) # Fill painter.drawPixmap(self.rect(), self.pic) # Game background - #painter.drawText(10,30, "Game state: {} ({}) Scores: P1={} P2={}".format(game["state"], game["delay"], game["p1_game"], game["p2_game"])) + # Font metrics assume font is monospaced! + self.fntLarge = QFont("Monospace", int(120 * scale_y)) + self.fntLarge.setKerning(False) + self.fntLarge.setFixedPitch(True) + self.fm = QFontMetrics(self.fntLarge) + self.fntMedium = QFont("Monospace", int(40 * scale_y)) + self.fntMedium.setKerning(False) + self.fntMedium.setFixedPitch(True) if game.state == pgc.STATE_WELCOME: # Welcome screen painter.drawPixmap(self.rect(), QPixmap("pictures/pandemic_pong.png")) painter.setFont(self.fntLarge) - painter.drawText(50, int(pgv.GAMEAREA_MAX_Y / 2)-100, "PANDEMIC") - painter.drawText(int(pgv.GAMEAREA_MAX_X / 2) + 300, int(pgv.GAMEAREA_MAX_Y / 2)+100, "PONG") + painter.drawText(int(50 * scale_x), int((pgv.GAMEAREA_MAX_Y / 2 - 100) * scale_y), "PANDEMIC") + painter.drawText(int((pgv.GAMEAREA_MAX_X / 2 + 300) * scale_x), int((pgv.GAMEAREA_MAX_Y / 2 + 100) * scale_y), "PONG") elif game.state == pgc.STATE_START: # Wait for start button pressed painter.setFont(self.fntMedium) - painter.drawText(300, int(pgv.GAMEAREA_MAX_Y / 2), "Press [Start] ...") - painter.drawText(int(pgv.GAMEAREA_MAX_X/2)+100, int(pgv.GAMEAREA_MAX_Y / 5), "Press [color] button") - painter.drawText(int(pgv.GAMEAREA_MAX_X/2)+100, int(pgv.GAMEAREA_MAX_Y / 5 * 2), "to infect player,") - painter.drawText(int(pgv.GAMEAREA_MAX_X/2)+100, int(pgv.GAMEAREA_MAX_Y / 5 * 3), "ball will pickup virus!") - painter.drawText(int(pgv.GAMEAREA_MAX_X/2)+100, int(pgv.GAMEAREA_MAX_Y / 5 * 4), "Match color to deflect!") + painter.drawText(int(150 * scale_x), int((pgv.GAMEAREA_MAX_Y / 2 - 100) * scale_y), "Press [Start] ...") + painter.drawText(int(50 * scale_x), int((pgv.GAMEAREA_MAX_Y / 2 + 100) * scale_y), "Press [Select] to abort") + painter.drawText(int((pgv.GAMEAREA_MAX_X / 2 + 100) * scale_x), int(pgv.GAMEAREA_MAX_Y / 5 * scale_y), "Press [color] button") + painter.drawText(int((pgv.GAMEAREA_MAX_X / 2 + 100) * scale_x), int(pgv.GAMEAREA_MAX_Y / 5 * 2 * scale_y), "to infect player,") + painter.drawText(int((pgv.GAMEAREA_MAX_X / 2 + 100) * scale_x), int(pgv.GAMEAREA_MAX_Y / 5 * 3 * scale_y), "ball will pickup virus!") + painter.drawText(int((pgv.GAMEAREA_MAX_X / 2 + 100) * scale_x), int(pgv.GAMEAREA_MAX_Y / 5 * 4 * scale_y), "Match color to deflect!") elif game.state == pgc.STATE_PLAY: # Actual play 'til score reaches 10 points # Ball gives NO indication ... - painter.drawRect(int(ball.x), int(ball.y), int(ball.w), int(ball.h)) # Ball + painter.drawRect(int(ball.x * scale_x), int(ball.y * scale_y), int(ball.w * scale_x), int(ball.h * scale_y)) # Ball if player1.color == pgc.COL_WHITE: painter.setPen(QPen(Qt.white, 1, Qt.SolidLine)) # Color/Linewidth/Pattern @@ -126,7 +145,7 @@ class pongWindow(QMainWindow): elif player1.color == pgc.COL_YELLOW: painter.setPen(QPen(Qt.yellow, 1, Qt.SolidLine)) # Color/Linewidth/Pattern painter.setBrush(QBrush(Qt.yellow, Qt.SolidPattern)) # Fill - painter.drawRect(int(player1.x), int(player1.y), int(player1.w), int(player1.h)) # Player left + painter.drawRect(int(player1.x * scale_x), int(player1.y * scale_y), int(player1.w * scale_x), int(player1.h * scale_y)) # Player left if player2.color == pgc.COL_WHITE: painter.setPen(QPen(Qt.white, 1, Qt.SolidLine)) # Color/Linewidth/Pattern @@ -143,7 +162,7 @@ class pongWindow(QMainWindow): elif player2.color == pgc.COL_YELLOW: painter.setPen(QPen(Qt.yellow, 1, Qt.SolidLine)) # Color/Linewidth/Pattern painter.setBrush(QBrush(Qt.yellow, Qt.SolidPattern)) # Fill - painter.drawRect(int(player2.x), int(player2.y), int(player2.w), int(player2.h)) # Player right + painter.drawRect(int(player2.x * scale_x), int(player2.y * scale_y), int(player2.w * scale_x), int(player2.h * scale_y)) # Player right painter.setPen(QPen(Qt.white, 1, Qt.SolidLine)) # Reset standard colour painter.setBrush(QBrush(Qt.white, Qt.SolidPattern)) @@ -153,31 +172,30 @@ class pongWindow(QMainWindow): # Score player #1 msg = str(player1.score) msg_width = self.fm.width(msg) - painter.drawText(800 - msg_width, 154, "{}".format(msg)) + painter.drawText(int((800 - msg_width) * scale_x), int(154 * scale_y), "{}".format(msg)) # Score player #2 - painter.drawText(pgv.GAMEAREA_MAX_X - 840, 154, "{}".format(player2.score)) + painter.drawText(int((pgv.GAMEAREA_MAX_X - 840) * scale_x), int(154 * scale_y), "{}".format(player2.score)) # Indicate Button states - draw_buttonstate(60, 50, player1, painter) - draw_buttonstate(pgv.GAMEAREA_MAX_X - 180, 50, player2, painter) + draw_buttonstate(60, 50, player1, painter, scale_x, scale_y) + draw_buttonstate(pgv.GAMEAREA_MAX_X - 180, 50, player2, painter, scale_x, scale_y) elif game.state == pgc.STATE_GAMERESULTS: # Display winner of this game painter.setFont(self.fntMedium) if player1.score > 9: msg = "Game player #1" else: msg = "Game player #2" - painter.drawText(50, int(pgv.GAMEAREA_MAX_Y / 2), msg) + painter.drawText(int(50 * scale_x), int(pgv.GAMEAREA_MAX_Y / 2 * scale_y), msg) elif game.state == pgc.STATE_FINALRESULTS: # Display set winner painter.setFont(self.fntMedium) if game.p1_game > 2: msg = "Match player #1" else: msg = "Match player #2" - painter.drawText(50, int(pgv.GAMEAREA_MAX_Y / 2), msg) + painter.drawText(int(50 * scale_x), int(pgv.GAMEAREA_MAX_Y / 2 * scale_y), msg) elif game.state == pgc.STATE_EXIT: # Indicate good bye ... painter.setFont(self.fntMedium) - painter.drawText(50, int(pgv.GAMEAREA_MAX_Y / 2), "Bye!") - + painter.drawText(int(50 * scale_x), int(pgv.GAMEAREA_MAX_Y / 2 * scale_x), "Bye!") @pyqtSlot() def on_timer(self): diff --git a/pandemic_pong_client.py b/pandemic_pong_client.py deleted file mode 100644 index 63e3ba5..0000000 --- a/pandemic_pong_client.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -pandemic_pong_client.py - -Pandemic Pong Client - -""" - -import pong_player, pong_object \ No newline at end of file diff --git a/pandemic_pong_server.py b/pandemic_pong_server.py deleted file mode 100644 index 3961b50..0000000 --- a/pandemic_pong_server.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -pandemic_pong_server.py - -Pandemic Pong Server - -""" - -import pong_game diff --git a/pong_constants.py b/pong_constants.py index 6b950c6..7c85410 100644 --- a/pong_constants.py +++ b/pong_constants.py @@ -36,3 +36,12 @@ STATE_GAMERESULTS = 3 STATE_FINALRESULTS = 4 STATE_RESTART = 5 STATE_EXIT = 6 + +"""File paths""" +wall_contact = './sounds/contact.ogg' # player & wall actually +player_contact = wall_contact +player_miss = './sounds/miss.wav' +game_splash = './sounds/splash.wav' +game_exit = './sounds/bye.wav' +game_win = './sounds/gamewin.wav' +match_win = './sounds/matchwin.wav' diff --git a/pong_game.py b/pong_game.py index 1d3b795..1a807fd 100644 --- a/pong_game.py +++ b/pong_game.py @@ -25,6 +25,12 @@ class PongGame: def game_fsm(self, player1, player2): """Game engine state machine""" + if (player1.state & pgc.BTN_BASE3) > 0 or (player2.state & pgc.BTN_BASE3) > 0: + player1.state = 0 # Don't play me again + player2.state = 0 + self.delay = 50 # Say good bye! + self.state = pgc.STATE_EXIT + if self.state == pgc.STATE_WELCOME: self.delay = self.delay - 1 if self.delay < 1: @@ -61,9 +67,12 @@ class PongGame: self.state = pgc.STATE_GAMERESULTS elif self.state == pgc.STATE_GAMERESULTS: + if self.delay == 90: + playsound(pgc.game_win) self.delay = self.delay - 1 if self.delay < 1: - if (self.p1_game > 2) or (self.p2_game > 2): # Set won? + if (self.p1_game > 2) or (self.p2_game > 2): # Set won? + self.delay = 100 self.state = pgc.STATE_FINALRESULTS # Yap! else: player1.score = 0 @@ -73,15 +82,21 @@ class PongGame: self.state = pgc.STATE_PLAY # Nope, move on to next game elif self.state == pgc.STATE_FINALRESULTS: - if (player1.state & pgc.BTN_BASE3) > 0 or (player2.state & pgc.BTN_BASE3) > 0: - return False - elif ((player1.state & pgc.BTN_BASE4) > 0) or ((player2.state & pgc.BTN_BASE4) > 0): + if self.delay == 90: + playsound(pgc.match_win) + self.delay = self.delay - 1 + if self.delay < 1: player1.state = 0 player2.state = 0 self.state = pgc.STATE_START # Continue by start button press - #if self.state >= pgc.STATE_EXIT: not used ... - # return False + elif self.state == pgc.STATE_EXIT: + if self.delay == 40: + playsound(pgc.game_exit) + self.delay = self.delay - 1 + if self.delay < 1: + return False + return True def crashvectors(self, ball, player1, player2): @@ -109,7 +124,7 @@ class PongGame: else: ball.delta_y = ball.delta_y * 0.8 # Decrease angle - playsound('/usr/share/mint-artwork/sounds/logout.ogg') # Enforce caching ... + playsound(pgc.player_contact) # Enforce caching ... else: # Ball moves left->right (---->) if (ball.x + ball.w >= player2.x) and (ball.x < player2.x + player2.w): # Right player #2 in range? @@ -133,7 +148,7 @@ class PongGame: else: ball.delta_y = ball.delta_y * 0.8 # Decrease angle - playsound('/usr/share/mint-artwork/sounds/logout.ogg') # Enforce caching ... + playsound(pgc.player_contact) # Enforce caching ... def pong_game(self, ball, player1, player2): @@ -157,12 +172,12 @@ class PongGame: if rc != 0: # Miss left(-1) or right(1) if rc == -1: # Player #2: +1 player2.score = player2.score + 1 - ball.reinit(6 + (random() - 0.5) * 4, (random() - 0.5) * 10) - playsound('/usr/lib/libreoffice/share/gallery/sounds/laser.wav') + ball.reinit(8 + (random() - 0.5) * 4, (random() - 0.5) * 10) + playsound(pgc.player_miss) else: # Player #1: +1 player1.score = player1.score + 1 - ball.reinit(-(6 + (random() - 0.5) * 4), (random() - 0.5) * 10) - playsound('/usr/lib/libreoffice/share/gallery/sounds/laser.wav') + ball.reinit(-(8 + (random() - 0.5) * 4), (random() - 0.5) * 10) + playsound(pgc.player_miss) return True diff --git a/pong_object.py b/pong_object.py index 127e46d..c41f972 100644 --- a/pong_object.py +++ b/pong_object.py @@ -54,11 +54,11 @@ class PongObject: if sum_y < pgv.GAMEAREA_MIN_Y: sum_y = pgv.GAMEAREA_MIN_Y self.delta_y = -self.delta_y - playsound('/usr/share/mint-artwork/sounds/logout.ogg') + playsound(pgc.wall_contact) elif sum_y + self.h > pgv.GAMEAREA_MAX_Y: sum_y = pgv.GAMEAREA_MAX_Y - self.h self.delta_y = -self.delta_y - playsound('/usr/share/mint-artwork/sounds/logout.ogg') + playsound(pgc.wall_contact) self.x = sum_x self.y = sum_y diff --git a/pong_player.py b/pong_player.py index b7dbaac..6ab2d81 100644 --- a/pong_player.py +++ b/pong_player.py @@ -9,7 +9,6 @@ Pandemic Pong Player Logic import os, fcntl import libevdev -from playsound import playsound import pong_constants as pgc # Pong global constants import pong_globalvars as pgv # Pong global variables diff --git a/sounds/bye.wav b/sounds/bye.wav new file mode 100644 index 0000000..8f9de06 Binary files /dev/null and b/sounds/bye.wav differ diff --git a/sounds/contact.ogg b/sounds/contact.ogg new file mode 100644 index 0000000..b110375 Binary files /dev/null and b/sounds/contact.ogg differ diff --git a/sounds/gamewin.wav b/sounds/gamewin.wav new file mode 100644 index 0000000..8a691f1 Binary files /dev/null and b/sounds/gamewin.wav differ diff --git a/sounds/matchwin.wav b/sounds/matchwin.wav new file mode 100644 index 0000000..6e1fb73 Binary files /dev/null and b/sounds/matchwin.wav differ diff --git a/sounds/miss.wav b/sounds/miss.wav new file mode 100644 index 0000000..2ecf822 Binary files /dev/null and b/sounds/miss.wav differ diff --git a/sounds/splash.wav b/sounds/splash.wav new file mode 100644 index 0000000..8e7cec5 Binary files /dev/null and b/sounds/splash.wav differ