A gamepad usage example
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
Pandemic_Pong/pandemic_pong.py

241 lines
11 KiB

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
pandemic_pong.py
Pandemic python/Qt5 pong clone
History:
--------
21.11.20/KQ Initial version
25.11.20/KQ Class based version w/ scaling ;)
"""
import sys, os, fcntl, time, random
import os
import time
from playsound import playsound
from PyQt5.QtGui import (QPixmap, QPaintDevice, QImage, QMouseEvent, QColor)
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QTimer, pyqtSlot, QEvent
from PyQt5.QtGui import QPainter, QBrush, QPen, QFont, QFontMetrics
import pong_constants as pgc # Pong global constants
import pong_globalvars as pgv # Pong global variables
from pong_player import PongPlayer
from pong_object import PongObject
from pong_game import PongGame
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(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(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(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(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.win_width = 1920
self.win_height = 960
self.InitWindow()
def InitWindow(self):
self.setWindowTitle(self.title)
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)
self.fntLarge.setKerning(False)
self.fntLarge.setFixedPitch(True)
self.fm = QFontMetrics(self.fntLarge)
self.fntMedium = QFont("Monospace", 40)
self.fntMedium.setKerning(False)
self.fntMedium.setFixedPitch(True)
self.show()
# 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
self.timer.setTimerType(Qt.PreciseTimer)
self.timer.timeout.connect(self.on_timer)
self.timer.start()
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
# 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(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(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 * 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
painter.setBrush(QBrush(Qt.white, Qt.SolidPattern)) # Fill
elif player1.color == pgc.COL_BLUE:
painter.setPen(QPen(Qt.blue, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
painter.setBrush(QBrush(Qt.blue, Qt.SolidPattern)) # Fill
elif player1.color == pgc.COL_GREEN:
painter.setPen(QPen(Qt.green, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
painter.setBrush(QBrush(Qt.green, Qt.SolidPattern)) # Fill
elif player1.color == pgc.COL_RED:
painter.setPen(QPen(Qt.red, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
painter.setBrush(QBrush(Qt.red, Qt.SolidPattern)) # Fill
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 * 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
painter.setBrush(QBrush(Qt.white, Qt.SolidPattern)) # Fill
elif player2.color == pgc.COL_BLUE:
painter.setPen(QPen(Qt.blue, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
painter.setBrush(QBrush(Qt.blue, Qt.SolidPattern)) # Fill
elif player2.color == pgc.COL_GREEN:
painter.setPen(QPen(Qt.green, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
painter.setBrush(QBrush(Qt.green, Qt.SolidPattern)) # Fill
elif player2.color == pgc.COL_RED:
painter.setPen(QPen(Qt.red, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
painter.setBrush(QBrush(Qt.red, Qt.SolidPattern)) # Fill
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 * 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))
# Game scores
painter.setFont(self.fntLarge)
# Score player #1
msg = str(player1.score)
msg_width = self.fm.width(msg)
painter.drawText(int((800 - msg_width) * scale_x), int(154 * scale_y), "{}".format(msg))
# Score player #2
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, 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(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(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(int(50 * scale_x), int(pgv.GAMEAREA_MAX_Y / 2 * scale_x), "Bye!")
@pyqtSlot()
def on_timer(self):
'''Qt5 timer event'''
global game, ball, player1, player2
self.timer.stop() # Block overrun
if game.pong_game(ball, player1, player2) == False:
sys.exit(0)
self.update() # Redraw
self.timer.start() # Re-enable
if __name__ == '__main__':
try:
# Initialize
random.seed()
game = PongGame()
ball = PongObject(pgv.GAMEAREA_MAX_X/2, pgv.GAMEAREA_MAX_Y/2, 20, 20, 8.0, 2.5)
player1 = PongPlayer(sys.argv[1], 10, pgv.GAMEAREA_MAX_Y/2-50, 20, 160)
player2 = PongPlayer(sys.argv[2], pgv.GAMEAREA_MAX_X-40, pgv.GAMEAREA_MAX_Y/2-50, 20, 160)
except IOError as e:
import errno
if e.errno == errno.EACCES:
print("Insufficient permissions to access {} or {}".format(path1, path2))
elif e.errno == errno.ENOENT:
print("Device {} or {} does not exist".format(path1, path2))
else:
raise e
sys.exit(-1)
app = QApplication(sys.argv) # Eval command line args
window = pongWindow() # Create Qt5 GUI
rc = app.exec_() # & run logic
# Quit gracefully
player2.exit()
player1.exit()
sys.exit(rc)