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/simple_pong.py

219 lines
9.0 KiB

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
simple_pong.py
Simple python/Qt5 pong clone
History:
--------
21.10.20/KQ Initial version
"""
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 evalgamepad
def crashvectors(ball, player1, player2):
if ball["delta_x"] < 0: # Ball moves right->left (<----)
if ball["x"] <= player1["x"] + player1["w"]: # Left player #1 in range?
if ball["y"] + ball["h"] >= player1["y"]: # Ball lower than player upper bound?
if ball["y"] <= player1["y"] + player1["h"]: # Ball higher than player lower bound?
ball["delta_x"] = -ball["delta_x"] * 1.2 # Invert direction & speed up
if player1["delta_y"] > 0.0: # Going downwards
if ball["delta_y"] > 0.0: # As well?
ball["delta_y"] = ball["delta_y"] * 1.2 # Increase angle
else:
ball["delta_y"] = ball["delta_y"] * 0.8 # Decrease angle
elif player1["delta_y"] < 0.0:
if ball["delta_y"] < 0.0: # As well?
ball["delta_y"] = ball["delta_y"] * 1.2 # Increase angle
else:
ball["delta_y"] = ball["delta_y"] * 0.8 # Decrease angle
playsound('/usr/share/mint-artwork/sounds/logout.ogg') # Enforce caching ...
else: # Ball moves left->right (---->)
if ball["x"] + ball["w"] >= player2["x"]: # Right player #2 in range?
if ball["y"] + ball["h"] >= player2["y"]: # Ball lower than player upper bound?
if ball["y"] <= player2["y"] + player2["h"]: # Ball higher than player lower bound?
ball["delta_x"] = -ball["delta_x"] * 1.2 # Invert direction & speed up
playsound('/usr/share/mint-artwork/sounds/logout.ogg') # Enforce caching ...
def pong_game(ball, player1, player2):
# 1. Retrieve user entries
bChanged = evalgamepad.eval_gamepad(player1)
if bChanged:
if (player1["state"] & evalgamepad.BTN_BASE4) > 0: # Exit?
print("Player #1 aborted game")
return False
#else:
# print("Player #1: {}".format(hex(player1["state"])))
bChanged = evalgamepad.eval_gamepad(player2) # Exit?
if bChanged:
if (player2["state"] & evalgamepad.BTN_BASE4) > 0:
print("Player #2 aborted game")
return False
#else:
# print("Player #2: {}".format(hex(player2["state"])))
# 2. Adjust player positions
bChanged = evalgamepad.eval_position(player1)
#if bChanged:
# print("Player #1: ", player1["x"], " / ", player1["y"])
bChanged = evalgamepad.eval_position(player2)
#if bChanged:
# print("Player #2: ", player2["x"], " / ", player2["y"])
# 3. Crash analyses
crashvectors(ball, player1, player2)
# 4. Adjust object positions (ball & potentially others ...)
rc = evalgamepad.eval_object(ball)
if rc != 0: # Miss left(-1) or right(1)
if rc == -1: # Player #2: +1
player2["score"] = player2["score"] + 1
evalgamepad.reinit_object(ball, 6 + (random.random() - 0.5) * 4, (random.random() - 0.5) * 10)
playsound('/usr/lib/libreoffice/share/gallery/sounds/laser.wav')
else: # Player #1: +1
player1["score"] = player1["score"] + 1
evalgamepad.reinit_object(ball, -(6 + (random.random() - 0.5) * 4), (random.random() - 0.5) * 10)
playsound('/usr/lib/libreoffice/share/gallery/sounds/laser.wav')
return True
def draw_buttonstate(x, y, player, painter):
if (player["state"] & evalgamepad.BTN_TRIGGER) == evalgamepad.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
if (player["state"] & evalgamepad.BTN_TOP) == evalgamepad.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)
if (player["state"] & evalgamepad.BTN_THUMB) == evalgamepad.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)
if (player["state"] & evalgamepad.BTN_THUMB2) == evalgamepad.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)
class pongWindow(QMainWindow):
def __init__(self):
super().__init__()
self.title = "Simple Pong"
self.top= 0
self.left= 0
self.width = 1920
self.height = 960
self.InitWindow()
def InitWindow(self):
self.setWindowTitle(self.title)
self.setGeometry(self.top, self.left, self.width, self.height)
#self.showFullScreen()
self.pic = QPixmap("pictures/pong_background.png")
# Font metrics assume font is monospaced!
self.fnt = QFont("Monospace",120)
self.fnt.setKerning(False)
self.fnt.setFixedPitch(True)
self.fm = QFontMetrics(self.fnt)
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')
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 ball, player1, player2
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.drawRect(int(ball["x"]), int(ball["y"]), int(ball["w"]), int(ball["h"])) # Ball
painter.drawRect(int(player1["x"]), int(player1["y"]), int(player1["w"]), int(player1["h"])) # Player left
painter.drawRect(int(player2["x"]), int(player2["y"]), int(player2["w"]), int(player2["h"])) # Player right
#painter.drawText(10, 30, "x: {}".format(ball["x"]))
#painter.drawText(10, 40, "y: {}".format(ball["y"]))
painter.drawText(10,50, "Player #1 delta_y: {}".format(player1["delta_y"]))
painter.drawText(10,60, "Player #2 delta_y: {}".format(player2["delta_y"]))
# Game scores
painter.setFont(self.fnt)
# Score player #1
msg = str(player1["score"])
msg_width = self.fm.width(msg)
painter.drawText(800 - msg_width, 154, "{}".format(player1["score"]))
# Score player #2
painter.drawText(evalgamepad.GAMEAREA_MAX_X-840, 154, "{}".format(player2["score"]))
# Indicate Button states
draw_buttonstate(60, 50, player1, painter)
draw_buttonstate(evalgamepad.GAMEAREA_MAX_X - 180, 50, player2, painter)
@pyqtSlot()
def on_timer(self):
'''Qt5 timer event'''
global ball, player1, player2
self.timer.stop() # Block overrun
if pong_game(ball, player1, player2) == False:
sys.exit(0)
self.update() # Redraw
self.timer.start() # Re-enable
if __name__ == '__main__':
try:
# Initialize
random.seed()
evalgamepad.init_gamearea()
ball = evalgamepad.init_object(evalgamepad.GAMEAREA_MAX_X/2, evalgamepad.GAMEAREA_MAX_Y/2, 20, 20, 8.0, 2.5)
player1 = evalgamepad.init_player(sys.argv[1], 10, evalgamepad.GAMEAREA_MAX_Y/2-50, 20, 160)
player2 = evalgamepad.init_player(sys.argv[2], evalgamepad.GAMEAREA_MAX_X-40, evalgamepad.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
evalgamepad.exit_player(player2)
evalgamepad.exit_player(player1)
sys.exit(rc)