Class based full functioning version
parent
9698defbb2
commit
b48fcd90ff
|
@ -1 +1,2 @@
|
|||
__pycache__/*
|
||||
backup/*
|
||||
|
|
388
evalgamepad.py
388
evalgamepad.py
|
@ -1,388 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# evalgamepad.py
|
||||
# Reading two USB gamepads & making sense of it (try pong)...
|
||||
#
|
||||
#-----------------------------------------------------------------------
|
||||
# 'lsusb' ouput: Bus 002 Device 003: ID 0079:0011 DragonRise Inc. Gamepad
|
||||
# Bus 002 Device 002: ID 0079:0011 DragonRise Inc. Gamepad
|
||||
#
|
||||
# input devices: /dev/input/event6
|
||||
# /dev/input/event7
|
||||
#
|
||||
|
||||
import sys, os, fcntl, time, random
|
||||
import libevdev
|
||||
|
||||
from playsound import playsound
|
||||
|
||||
# Buttons in 'state<n>'
|
||||
BTN_TRIGGER = 1 # [Blue/X]
|
||||
BTN_THUMB = 2 # [Red/A]
|
||||
BTN_THUMB2 = 4 # [Yellow/B]
|
||||
BTN_TOP = 8 # [Green/Y]
|
||||
BTN_TOP2 = 16 # [Frontal left]
|
||||
BTN_PINKIE = 32 # [Frontal right]
|
||||
BTN_BASE3 = 64 # [Centre left]
|
||||
BTN_BASE4 = 128 # [Centre right]
|
||||
|
||||
GAMEAREA_MIN_X = 0 # Game area definition
|
||||
GAMEAREA_MAX_X = 1920 # Assume FHD resolution
|
||||
GAMEAREA_MIN_Y = 15
|
||||
GAMEAREA_MAX_Y = 940 #-GAMEAREA_MIN_Y
|
||||
|
||||
COL_WHITE = 0
|
||||
COL_BLUE = 1
|
||||
COL_GREEN = 2
|
||||
COL_RED = 3
|
||||
COL_YELLOW = 4
|
||||
|
||||
COLORDELAY = 100
|
||||
|
||||
def init_player(path, x, y, w, h):
|
||||
# Gamepad init.
|
||||
fd = open(path, "rb")
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
dev = libevdev.Device(fd)
|
||||
|
||||
return {
|
||||
"fd" : fd, # File descriptor to close (later ...)
|
||||
"dev" : dev, # Actual gamepad of this player
|
||||
"state" : 0, # Button mask (as above)
|
||||
"delta_x" : 0, # Current delta setting
|
||||
"delta_y" : 0,
|
||||
"color" : COL_WHITE, # 'Infection' colour
|
||||
"delay" : 0, # 'Infectious' time
|
||||
"x" : x, # Current actual position
|
||||
"y" : y, # Start at center
|
||||
"w" : w,
|
||||
"h" : h,
|
||||
"score" : 0
|
||||
}
|
||||
|
||||
def reinit_player(player, x, y, delta_x, delta_y):
|
||||
player["x"] = x
|
||||
player["y"] = y
|
||||
player["delta_x"] = delta_x
|
||||
player["delta_y"] = delta_y
|
||||
player["state"] = 0
|
||||
player["color"] = COL_WHITE
|
||||
player["delay"] = 0
|
||||
|
||||
def exit_player(player):
|
||||
player["fd"].close()
|
||||
|
||||
|
||||
def init_object(x, y, w, h, delta_x, delta_y):
|
||||
return {
|
||||
"delta_x" : delta_x, # Current movement
|
||||
"delta_y" : (random.random() - 0.5) * 10,
|
||||
"color" : COL_WHITE,
|
||||
"delay" : 0,
|
||||
"x" : x, # Current position
|
||||
"y" : y,
|
||||
"w" : w, # Size of object
|
||||
"h" : h,
|
||||
}
|
||||
|
||||
def reinit_object(obj, delta_x, delta_y):
|
||||
obj["x"] = GAMEAREA_MAX_X/2 - obj["w"]/2
|
||||
obj["y"] = GAMEAREA_MAX_Y/2 - obj["h"]/2
|
||||
obj["delta_x"] = delta_x
|
||||
obj["delta_y"] = delta_y
|
||||
obj["color"] = COL_WHITE
|
||||
obj["delay"] = 0
|
||||
|
||||
|
||||
def print_event(e):
|
||||
print("Event: time {}.{:06d}, ".format(e.sec, e.usec), end='')
|
||||
if e.matches(libevdev.EV_SYN):
|
||||
if e.matches(libevdev.EV_SYN.SYN_MT_REPORT):
|
||||
print("++++++++++++++ {} ++++++++++++".format(e.code.name))
|
||||
elif e.matches(libevdev.EV_SYN.SYN_DROPPED):
|
||||
print(">>>>>>>>>>>>>> {} >>>>>>>>>>>>".format(e.code.name))
|
||||
else:
|
||||
print("-------------- {} ------------".format(e.code.name))
|
||||
else:
|
||||
print("type {:02x} {} code {:03x} {:20s} value {:4d}".format(e.type.value, e.type.name, e.code.value, e.code.name, e.value))
|
||||
|
||||
|
||||
def eval_gamepad(player):
|
||||
bChanged = False
|
||||
try:
|
||||
for e in player["dev"].events():
|
||||
#print_event(e)
|
||||
|
||||
# Event type 1 (EV_KEY)
|
||||
# Event code 288 (BTN_TRIGGER) <- 1=[Blue/X]
|
||||
# Event code 289 (BTN_THUMB) <- 1=[Red/A]
|
||||
# Event code 290 (BTN_THUMB2) <- 1=[Yellow/B]
|
||||
# Event code 291 (BTN_TOP) <- 1=[Green/Y]
|
||||
# Event code 292 (BTN_TOP2) <- 1=[Frontal left]
|
||||
# Event code 293 (BTN_PINKIE) <- 1=[Frontal right]
|
||||
# Event code 294 (BTN_BASE)
|
||||
# Event code 295 (BTN_BASE2)
|
||||
# Event code 296 (BTN_BASE3) <- 1=[Centre left]
|
||||
# Event code 297 (BTN_BASE4) <- 1=[Centre right]
|
||||
if e.type.value == 1: # Non-Cross events
|
||||
if e.value == 1: # Simple buttons may act as toggles
|
||||
if e.code.value == 288: # BTN_TRIGGER
|
||||
if player["delay"] <= 0: # As long as we're not infectious ...
|
||||
player["state"] = BTN_TRIGGER # player["state"] ^ BTN_TRIGGER
|
||||
player["color"] = COL_BLUE # Infect 'blue'
|
||||
player["delay"] = COLORDELAY # Start infectious time immediately ...
|
||||
elif e.code.value == 289: # BTN_THUMB
|
||||
if player["delay"] <= 0: # As long as we're not infectious ...
|
||||
player["state"] = BTN_THUMB # player["state"] ^ BTN_THUMB
|
||||
player["color"] = COL_RED
|
||||
player["delay"] = COLORDELAY
|
||||
elif e.code.value == 290: # BTN_THUMB2
|
||||
if player["delay"] <= 0: # As long as we're not infectious ...
|
||||
player["state"] = BTN_THUMB2 # player["state"] ^ BTN_THUMB2
|
||||
player["color"] = COL_YELLOW
|
||||
player["delay"] = COLORDELAY
|
||||
elif e.code.value == 291: # BTN_TOP
|
||||
if player["delay"] <= 0: # As long as we're not infectious ...
|
||||
player["state"] = BTN_TOP # player["state"] ^ BTN_TOP
|
||||
player["color"] = COL_GREEN
|
||||
player["delay"] = COLORDELAY
|
||||
|
||||
elif e.code.value == 292: # BTN_TOP2
|
||||
player["state"] = player["state"] ^ BTN_TOP2
|
||||
elif e.code.value == 293: # BTN_PINKIE
|
||||
player["state"] = player["state"] ^ BTN_PINKIE
|
||||
elif e.code.value == 296: # BTN_BASE3
|
||||
player["state"] = player["state"] ^ BTN_BASE3
|
||||
elif e.code.value == 297: # BTN_BASE4
|
||||
player["state"] = player["state"] ^ BTN_BASE4
|
||||
bChanged = True
|
||||
|
||||
# Event type 3 (EV_ABS)
|
||||
# Event code 0 (ABS_X) <- Cross: 127=Neutral, 0=[Left], 255=[Right]
|
||||
# Event code 1 (ABS_Y) <- Cross: 127=Neutral, 0=[Top], 255=[Down]
|
||||
elif e.type.value == 3: # EV_ABS
|
||||
if e.code.value == 0: # ABS_X
|
||||
if e.value == 0:
|
||||
player["delta_x"] = player["delta_x"] - 1
|
||||
elif e.value == 255:
|
||||
player["delta_x"] = player["delta_x"] + 1
|
||||
else: # 127/Neutral
|
||||
player["delta_x"] = 0
|
||||
else: # ABS_Y
|
||||
if e.value == 0:
|
||||
player["delta_y"] = player["delta_y"] - 1
|
||||
elif e.value == 255:
|
||||
player["delta_y"] = player["delta_y"] + 1
|
||||
else: # 127/Neutral
|
||||
player["delta_y"] = 0
|
||||
bChanged = True
|
||||
|
||||
#if bChanged:
|
||||
# print("State=",player["state"], "X=", player["delta_x"], "Y=", player["delta_y"])
|
||||
|
||||
except libevdev.EventsDroppedException:
|
||||
print("Dropped!")
|
||||
for e in player["dev"].sync():
|
||||
print_event(e)
|
||||
|
||||
return bChanged
|
||||
|
||||
|
||||
def eval_position(player, min_x, max_x):
|
||||
bChanged = False
|
||||
|
||||
sum_x = player["x"] + player["delta_x"] * 10 #255
|
||||
if sum_x < min_x:
|
||||
sum_x = min_x
|
||||
elif sum_x + player["w"] > max_x:
|
||||
sum_x = max_x - player["w"]
|
||||
|
||||
sum_y = player["y"] + player["delta_y"] * 10 #255
|
||||
if sum_y < GAMEAREA_MIN_Y:
|
||||
sum_y = GAMEAREA_MIN_Y
|
||||
elif sum_y + player["h"] > GAMEAREA_MAX_Y:
|
||||
sum_y = GAMEAREA_MAX_Y - player["h"]
|
||||
|
||||
if (sum_x != player["x"]) or (sum_y != player["y"]):
|
||||
bChanged = True
|
||||
player["x"] = sum_x
|
||||
player["y"] = sum_y
|
||||
|
||||
return bChanged
|
||||
|
||||
|
||||
def eval_object(obj):
|
||||
|
||||
bChanged = 0
|
||||
sum_x = obj["x"] + obj["delta_x"]
|
||||
sum_y = obj["y"] + obj["delta_y"]
|
||||
|
||||
if sum_x < GAMEAREA_MIN_X:
|
||||
#sum_x = GAMEAREA_MIN_X
|
||||
#obj["delta_x"] = -obj["delta_x"]
|
||||
bChanged = -1 # Miss left
|
||||
elif sum_x + obj["w"] > GAMEAREA_MAX_X:
|
||||
#sum_x = GAMEAREA_MAX_X - obj["w"]
|
||||
#obj["delta_x"] = -obj["delta_x"]
|
||||
bChanged = 1 # Miss right
|
||||
|
||||
if sum_y < GAMEAREA_MIN_Y:
|
||||
sum_y = GAMEAREA_MIN_Y
|
||||
obj["delta_y"] = -obj["delta_y"]
|
||||
playsound('/usr/share/mint-artwork/sounds/logout.ogg')
|
||||
elif sum_y + obj["h"] > GAMEAREA_MAX_Y:
|
||||
sum_y = GAMEAREA_MAX_Y - obj["h"]
|
||||
obj["delta_y"] = -obj["delta_y"]
|
||||
playsound('/usr/share/mint-artwork/sounds/logout.ogg')
|
||||
|
||||
obj["x"] = sum_x
|
||||
obj["y"] = sum_y
|
||||
return bChanged
|
||||
|
||||
def draw_objects(ball, player1, player2): # Update objects on playground
|
||||
print("\rB: ", ball["x"], "/", ball["y"], end="")
|
||||
print(" P1: ", player1["x"], "/", player1["y"], " S:", hex(player1["state"]), " ", end="")
|
||||
print(" P2: ", player2["x"], "/", player2["y"], " S:", hex(player2["state"]), " ", end="")
|
||||
|
||||
|
||||
def gameloop(ball, player1, player2):
|
||||
while True:
|
||||
# 1. Retrieve user entries
|
||||
bChanged = eval_gamepad(player1)
|
||||
if bChanged:
|
||||
if (player1["state"] & BTN_BASE4) > 0: # Exit?
|
||||
print("Player #1 aborted game")
|
||||
break
|
||||
bChanged = eval_gamepad(player2) # Exit?
|
||||
if bChanged:
|
||||
if (player2["state"] & BTN_BASE4) > 0:
|
||||
print("Player #2 aborted game")
|
||||
break
|
||||
|
||||
# 2. Adjust player positions
|
||||
bChanged = eval_position(player1)
|
||||
if bChanged:
|
||||
print("Player #1: ", player1["x"], " / ", player1["y"])
|
||||
bChanged = eval_position(player2)
|
||||
if bChanged:
|
||||
print("Player #2: ", player2["x"], " / ", player2["y"])
|
||||
|
||||
# 3. Adjust object positions
|
||||
eval_object(ball)
|
||||
|
||||
# 4. Refresh game area drawing
|
||||
draw_objects(ball, player1, player2)
|
||||
|
||||
# 5. Little delay for testing
|
||||
time.sleep(0.1)
|
||||
|
||||
STATE_WELCOME = 0
|
||||
STATE_START = 1
|
||||
STATE_PLAY = 2
|
||||
STATE_GAMERESULTS = 3
|
||||
STATE_FINALRESULTS = 4
|
||||
STATE_RESTART = 5
|
||||
STATE_EXIT = 6
|
||||
|
||||
def init_game(): # Create base playground
|
||||
return {
|
||||
"state" : STATE_WELCOME, # State of game
|
||||
"delay" : 100,
|
||||
"p1_game" : 0, # Results
|
||||
"p2_game" : 0
|
||||
}
|
||||
|
||||
def next_gamestate(ga, player1, player2):
|
||||
if ga["state"] == STATE_WELCOME:
|
||||
ga["delay"] = ga["delay"] - 1
|
||||
if ga["delay"] < 1:
|
||||
ga["state"] = STATE_START
|
||||
|
||||
elif ga["state"] == STATE_START: # Start new game
|
||||
if (player1["state"] & BTN_BASE4) > 0 or (player2["state"] & BTN_BASE4) > 0: # [Start] pressed?
|
||||
reinit_player(player1, 10, GAMEAREA_MAX_Y/2-50, 0, 0)
|
||||
reinit_player(player2, GAMEAREA_MAX_X-40, GAMEAREA_MAX_Y/2-50, 0, 0)
|
||||
ga["p1_game"] = 0
|
||||
ga["p2_game"] = 0
|
||||
player1["score"] = 0
|
||||
player2["score"] = 0
|
||||
ga["state"] = STATE_PLAY
|
||||
|
||||
elif ga["state"] == STATE_PLAY: # Remain playing 'til 10 points
|
||||
if player1["delay"] > 0: # Infectious time running?
|
||||
player1["delay"] = player1["delay"] - 1 # Yap!
|
||||
if player1["delay"] <= 0:
|
||||
player1["color"] = COL_WHITE
|
||||
player1["state"] = 0
|
||||
if player2["delay"] > 0: # for both players ...
|
||||
player2["delay"] = player2["delay"] - 1
|
||||
if player2["delay"] <= 0:
|
||||
player2["color"] = COL_WHITE
|
||||
player2["state"] = 0
|
||||
|
||||
if player1["score"] > 9 or (player2["score"] > 9):
|
||||
if player1["score"] > 9: # Figure out winner
|
||||
ga["p1_game"] = ga["p1_game"] + 1 # & count game accordingly
|
||||
else:
|
||||
ga["p2_game"] = ga["p2_game"] + 1
|
||||
ga["delay"] = 100
|
||||
ga["state"] = STATE_GAMERESULTS
|
||||
|
||||
elif ga["state"] == STATE_GAMERESULTS:
|
||||
ga["delay"] = ga["delay"] - 1
|
||||
if ga["delay"] < 1:
|
||||
if (ga["p1_game"] > 2) or (ga["p2_game"] > 2): # Set won?
|
||||
ga["state"] = STATE_FINALRESULTS # Yap!
|
||||
else:
|
||||
player1["score"] = 0
|
||||
player2["score"] = 0
|
||||
reinit_player(player1, GAMEAREA_MAX_X-40, GAMEAREA_MAX_Y/2-50, 0, 0)
|
||||
reinit_player(player2, 10, GAMEAREA_MAX_Y/2-50, 0, 0)
|
||||
ga["state"] = STATE_PLAY # Nope, move on to next game
|
||||
|
||||
elif ga["state"] == STATE_FINALRESULTS:
|
||||
if (player1["state"] & BTN_BASE3) > 0 or (player2["state"] & BTN_BASE3) > 0:
|
||||
return False
|
||||
elif ((player1["state"] & BTN_BASE4) > 0) or ((player2["state"] & BTN_BASE4) > 0):
|
||||
player1["state"] = 0
|
||||
player2["state"] = 0
|
||||
ga["state"] = STATE_START # Continue by start button press
|
||||
|
||||
#if ga["state"] >= STATE_EXIT: not used ...
|
||||
# return False
|
||||
return True
|
||||
|
||||
def main(args):
|
||||
try:
|
||||
# Initialize
|
||||
init_gamearea()
|
||||
ball = init_object(10, 10, 15, 15, 2.0, 1.5)
|
||||
player1 = init_player(args[1],10, GAMEAREA_MAX_Y/2, 10, 160)
|
||||
player2 = init_player(args[2],GAMEAREA_MAX_X-30, GAMEAREA_MAX_Y/2, 10, 160)
|
||||
|
||||
# Work ...
|
||||
gameloop(ball, player1, player2)
|
||||
|
||||
# Quit gracefully
|
||||
exit_player(player2)
|
||||
exit_player(player1)
|
||||
|
||||
except KeyboardInterrupt: # Never comes ... (?!)
|
||||
pass
|
||||
|
||||
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
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 3:
|
||||
print("usage: ./evalgamepad.py /dev/input/event<n> /dev/input/event<m>")
|
||||
sys.exit(1)
|
||||
main(sys.argv)
|
|
@ -7,7 +7,8 @@ Pandemic python/Qt5 pong clone
|
|||
|
||||
History:
|
||||
--------
|
||||
21.10.20/KQ Initial version
|
||||
21.11.20/KQ Initial version
|
||||
25.11.20/KQ Class based version ;)
|
||||
"""
|
||||
|
||||
import sys, os, fcntl, time, random
|
||||
|
@ -21,110 +22,27 @@ 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"]) and (ball["x"] > player1["x"]): # 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?
|
||||
|
||||
if ball["color"] == evalgamepad.COL_WHITE:
|
||||
ball["color"] = player1["color"] # Pick up 'infection' (if any)
|
||||
elif ball["color"] != player1["color"]: # Infectious ball!
|
||||
return # w/o vaccine -> no save!
|
||||
|
||||
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"]) and (ball["x"] < player2["x"] + player2["w"]): # 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?
|
||||
|
||||
if ball["color"] == evalgamepad.COL_WHITE:
|
||||
ball["color"] = player2["color"] # Pick up 'infection' (if any)
|
||||
elif ball["color"] != player2["color"]: # Infectious ball!
|
||||
return # w/o vaccine -> no save!
|
||||
|
||||
ball["delta_x"] = -ball["delta_x"] * 1.2 # Invert direction & speed up
|
||||
if player2["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 player2["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 ...
|
||||
|
||||
|
||||
def pong_game(game, ball, player1, player2):
|
||||
|
||||
if evalgamepad.next_gamestate(game, player1, player2) == False: # Exit
|
||||
return False
|
||||
|
||||
#print("Game state: {}".format(game["state"]))
|
||||
|
||||
# 1. Retrieve user entries
|
||||
bChanged = evalgamepad.eval_gamepad(player1)
|
||||
bChanged = evalgamepad.eval_gamepad(player2) # Exit?
|
||||
|
||||
if game["state"] == evalgamepad.STATE_PLAY: # Actually playing?
|
||||
# 2. Adjust player positions
|
||||
bChanged = evalgamepad.eval_position(player1, evalgamepad.GAMEAREA_MIN_X, evalgamepad.GAMEAREA_MAX_X/2-50)
|
||||
#if bChanged:
|
||||
# print("Player #1: ", player1["x"], " / ", player1["y"])
|
||||
bChanged = evalgamepad.eval_position(player2, evalgamepad.GAMEAREA_MAX_X/2+50, evalgamepad.GAMEAREA_MAX_X)
|
||||
#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
|
||||
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):
|
||||
if (player["state"] & evalgamepad.BTN_TRIGGER) == evalgamepad.BTN_TRIGGER:
|
||||
"""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
|
||||
if (player["state"] & evalgamepad.BTN_TOP) == evalgamepad.BTN_TOP:
|
||||
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)
|
||||
if (player["state"] & evalgamepad.BTN_THUMB) == evalgamepad.BTN_THUMB:
|
||||
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)
|
||||
if (player["state"] & evalgamepad.BTN_THUMB2) == evalgamepad.BTN_THUMB2:
|
||||
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)
|
||||
|
@ -175,111 +93,90 @@ class pongWindow(QMainWindow):
|
|||
|
||||
#painter.drawText(10,30, "Game state: {} ({}) Scores: P1={} P2={}".format(game["state"], game["delay"], game["p1_game"], game["p2_game"]))
|
||||
|
||||
if game["state"] == evalgamepad.STATE_WELCOME: # Welcome screen
|
||||
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(evalgamepad.GAMEAREA_MAX_Y / 2)-100, "PANDEMIC")
|
||||
painter.drawText(int(evalgamepad.GAMEAREA_MAX_X / 2) + 300, int(evalgamepad.GAMEAREA_MAX_Y / 2)+100, "PONG")
|
||||
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")
|
||||
|
||||
elif game["state"] == evalgamepad.STATE_START: # Wait for start button pressed
|
||||
elif game.state == pgc.STATE_START: # Wait for start button pressed
|
||||
painter.setFont(self.fntMedium)
|
||||
painter.drawText(300, int(evalgamepad.GAMEAREA_MAX_Y / 2), "Press [Start] ...")
|
||||
painter.drawText(int(evalgamepad.GAMEAREA_MAX_X/2)+100, int(evalgamepad.GAMEAREA_MAX_Y / 5), "Press [color] button")
|
||||
painter.drawText(int(evalgamepad.GAMEAREA_MAX_X/2)+100, int(evalgamepad.GAMEAREA_MAX_Y / 5 * 2), "to infect player,")
|
||||
painter.drawText(int(evalgamepad.GAMEAREA_MAX_X/2)+100, int(evalgamepad.GAMEAREA_MAX_Y / 5 * 3), "ball will pickup virus!")
|
||||
painter.drawText(int(evalgamepad.GAMEAREA_MAX_X/2)+100, int(evalgamepad.GAMEAREA_MAX_Y / 5 * 4), "Match color to deflect!")
|
||||
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!")
|
||||
|
||||
elif game["state"] == evalgamepad.STATE_PLAY: # Actual play 'til score reaches 10 points
|
||||
""" Ball gives NO indication ...
|
||||
if ball["color"] == evalgamepad.COL_WHITE:
|
||||
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
|
||||
|
||||
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 ball["color"] == evalgamepad.COL_BLUE:
|
||||
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 ball["color"] == evalgamepad.COL_GREEN:
|
||||
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 ball["color"] == evalgamepad.COL_RED:
|
||||
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 ball["color"] == evalgamepad.COL_YELLOW:
|
||||
painter.setPen(QPen(Qt.yellow, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
|
||||
painter.setBrush(QBrush(Qt.yellow, Qt.SolidPattern)) # Fill
|
||||
"""
|
||||
painter.drawRect(int(ball["x"]), int(ball["y"]), int(ball["w"]), int(ball["h"])) # Ball
|
||||
|
||||
if player1["color"] == evalgamepad.COL_WHITE:
|
||||
painter.setPen(QPen(Qt.white, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
|
||||
painter.setBrush(QBrush(Qt.white, Qt.SolidPattern)) # Fill
|
||||
elif player1["color"] == evalgamepad.COL_BLUE:
|
||||
painter.setPen(QPen(Qt.blue, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
|
||||
painter.setBrush(QBrush(Qt.blue, Qt.SolidPattern)) # Fill
|
||||
elif player1["color"] == evalgamepad.COL_GREEN:
|
||||
painter.setPen(QPen(Qt.green, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
|
||||
painter.setBrush(QBrush(Qt.green, Qt.SolidPattern)) # Fill
|
||||
elif player1["color"] == evalgamepad.COL_RED:
|
||||
painter.setPen(QPen(Qt.red, 1, Qt.SolidLine)) # Color/Linewidth/Pattern
|
||||
painter.setBrush(QBrush(Qt.red, Qt.SolidPattern)) # Fill
|
||||
elif player1["color"] == evalgamepad.COL_YELLOW:
|
||||
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), int(player1.y), int(player1.w), int(player1.h)) # Player left
|
||||
|
||||
if player2["color"] == evalgamepad.COL_WHITE:
|
||||
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"] == evalgamepad.COL_BLUE:
|
||||
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"] == evalgamepad.COL_GREEN:
|
||||
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"] == evalgamepad.COL_RED:
|
||||
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"] == evalgamepad.COL_YELLOW:
|
||||
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), int(player2.y), int(player2.w), int(player2.h)) # Player right
|
||||
|
||||
painter.setPen(QPen(Qt.white, 1, Qt.SolidLine)) # Reset standard colour
|
||||
painter.setBrush(QBrush(Qt.white, Qt.SolidPattern))
|
||||
|
||||
#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.fntLarge)
|
||||
# Score player #1
|
||||
msg = str(player1["score"])
|
||||
msg = str(player1.score)
|
||||
msg_width = self.fm.width(msg)
|
||||
painter.drawText(800 - msg_width, 154, "{}".format(player1["score"]))
|
||||
painter.drawText(800 - msg_width, 154, "{}".format(msg))
|
||||
# Score player #2
|
||||
painter.drawText(evalgamepad.GAMEAREA_MAX_X-840, 154, "{}".format(player2["score"]))
|
||||
painter.drawText(pgv.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)
|
||||
elif game["state"] == evalgamepad.STATE_GAMERESULTS: # Display winner of this game
|
||||
draw_buttonstate(pgv.GAMEAREA_MAX_X - 180, 50, player2, painter)
|
||||
elif game.state == pgc.STATE_GAMERESULTS: # Display winner of this game
|
||||
painter.setFont(self.fntMedium)
|
||||
if player1["score"] > 9:
|
||||
if player1.score > 9:
|
||||
msg = "Game player #1"
|
||||
else:
|
||||
msg = "Game player #2"
|
||||
painter.drawText(50, int(evalgamepad.GAMEAREA_MAX_Y / 2), msg)
|
||||
elif game["state"] == evalgamepad.STATE_FINALRESULTS: # Display set winner
|
||||
painter.drawText(50, int(pgv.GAMEAREA_MAX_Y / 2), msg)
|
||||
elif game.state == pgc.STATE_FINALRESULTS: # Display set winner
|
||||
painter.setFont(self.fntMedium)
|
||||
if game["p1_game"] > 2:
|
||||
if game.p1_game > 2:
|
||||
msg = "Match player #1"
|
||||
else:
|
||||
msg = "Match player #2"
|
||||
painter.drawText(50, int(evalgamepad.GAMEAREA_MAX_Y / 2), msg)
|
||||
elif game["state"] == evalgamepad.STATE_EXIT: # Indicate good bye ...
|
||||
painter.drawText(50, int(pgv.GAMEAREA_MAX_Y / 2), msg)
|
||||
elif game.state == pgc.STATE_EXIT: # Indicate good bye ...
|
||||
painter.setFont(self.fntMedium)
|
||||
painter.drawText(50, int(evalgamepad.GAMEAREA_MAX_Y / 2), "Bye!")
|
||||
painter.drawText(50, int(pgv.GAMEAREA_MAX_Y / 2), "Bye!")
|
||||
|
||||
|
||||
@pyqtSlot()
|
||||
|
@ -289,7 +186,7 @@ class pongWindow(QMainWindow):
|
|||
|
||||
self.timer.stop() # Block overrun
|
||||
|
||||
if pong_game(game, ball, player1, player2) == False:
|
||||
if game.pong_game(ball, player1, player2) == False:
|
||||
sys.exit(0)
|
||||
|
||||
self.update() # Redraw
|
||||
|
@ -300,10 +197,10 @@ if __name__ == '__main__':
|
|||
try:
|
||||
# Initialize
|
||||
random.seed()
|
||||
game = evalgamepad.init_game()
|
||||
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)
|
||||
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
|
||||
|
@ -320,7 +217,7 @@ if __name__ == '__main__':
|
|||
rc = app.exec_() # & run logic
|
||||
|
||||
# Quit gracefully
|
||||
evalgamepad.exit_player(player2)
|
||||
evalgamepad.exit_player(player1)
|
||||
|
||||
player2.exit()
|
||||
player1.exit()
|
||||
|
||||
sys.exit(rc)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
pandemic_pong_client.py
|
||||
|
||||
Pandemic Pong Client
|
||||
|
||||
"""
|
||||
|
||||
import pong_player, pong_object
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
pandemic_pong_server.py
|
||||
|
||||
Pandemic Pong Server
|
||||
|
||||
"""
|
||||
|
||||
import pong_game
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
pong_constants.py
|
||||
|
||||
Pandemic Pong global constants
|
||||
|
||||
"""
|
||||
|
||||
"""Buttons in 'state<n>'"""
|
||||
BTN_STATE_NONE = 0 # No Button pressed ...
|
||||
BTN_TRIGGER = 1 # [Blue/X]
|
||||
BTN_THUMB = 2 # [Red/A]
|
||||
BTN_THUMB2 = 4 # [Yellow/B]
|
||||
BTN_TOP = 8 # [Green/Y]
|
||||
BTN_TOP2 = 16 # [Frontal left]
|
||||
BTN_PINKIE = 32 # [Frontal right]
|
||||
BTN_BASE3 = 64 # [Centre left]
|
||||
BTN_BASE4 = 128 # [Centre right]
|
||||
|
||||
# Colors to be used
|
||||
COL_WHITE = 0 # White = not infectious
|
||||
COL_BLUE = 1 # Virus color
|
||||
COL_GREEN = 2 # Virus color
|
||||
COL_RED = 3 # Virus color
|
||||
COL_YELLOW = 4 # virus color
|
||||
|
||||
"""Infectiousness time"""
|
||||
COLORDELAY = 100
|
||||
|
||||
"""Game states"""
|
||||
STATE_WELCOME = 0
|
||||
STATE_START = 1
|
||||
STATE_PLAY = 2
|
||||
STATE_GAMERESULTS = 3
|
||||
STATE_FINALRESULTS = 4
|
||||
STATE_RESTART = 5
|
||||
STATE_EXIT = 6
|
|
@ -0,0 +1,171 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
pong_game.py
|
||||
|
||||
Pandemic Pong Game Engine
|
||||
|
||||
"""
|
||||
|
||||
from random import random
|
||||
from playsound import playsound
|
||||
|
||||
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
|
||||
|
||||
class PongGame:
|
||||
def __init__(self):
|
||||
self.state = pgc.STATE_WELCOME # State of game
|
||||
self.delay = 100 # Automatically leave splash screen ...
|
||||
self.p1_game = 0 # Results (reset)
|
||||
self.p2_game = 0
|
||||
|
||||
def game_fsm(self, player1, player2):
|
||||
"""Game engine state machine"""
|
||||
|
||||
if self.state == pgc.STATE_WELCOME:
|
||||
self.delay = self.delay - 1
|
||||
if self.delay < 1:
|
||||
self.state = pgc.STATE_START
|
||||
|
||||
elif self.state == pgc.STATE_START: # Start new game
|
||||
if (player1.state & pgc.BTN_BASE4) > 0 or (player2.state & pgc.BTN_BASE4) > 0: # [Start] pressed?
|
||||
player1.reinit(10, pgv.GAMEAREA_MAX_Y/2-50, 0, 0)
|
||||
player2.reinit(pgv.GAMEAREA_MAX_X-40, pgv.GAMEAREA_MAX_Y/2-50, 0, 0)
|
||||
self.p1_game = 0
|
||||
self.p2_game = 0
|
||||
player1.score = 0
|
||||
player2.score = 0
|
||||
self.state = pgc.STATE_PLAY
|
||||
|
||||
elif self.state == pgc.STATE_PLAY: # Remain playing 'til 10 points
|
||||
if player1.delay > 0: # Infectious time running?
|
||||
player1.delay = player1.delay - 1 # Yap!
|
||||
if player1.delay <= 0:
|
||||
player1.color = pgc.COL_WHITE
|
||||
player1.state = 0
|
||||
if player2.delay > 0: # for both players ...
|
||||
player2.delay = player2.delay - 1
|
||||
if player2.delay <= 0:
|
||||
player2.color = pgc.COL_WHITE
|
||||
player2.state = 0
|
||||
|
||||
if player1.score > 9 or (player2.score > 9):
|
||||
if player1.score > 9: # Figure out winner
|
||||
self.p1_game = self.p1_game + 1 # & count game accordingly
|
||||
else:
|
||||
self.p2_game = self.p2_game + 1
|
||||
self.delay = 100
|
||||
self.state = pgc.STATE_GAMERESULTS
|
||||
|
||||
elif self.state == pgc.STATE_GAMERESULTS:
|
||||
self.delay = self.delay - 1
|
||||
if self.delay < 1:
|
||||
if (self.p1_game > 2) or (self.p2_game > 2): # Set won?
|
||||
self.state = pgc.STATE_FINALRESULTS # Yap!
|
||||
else:
|
||||
player1.score = 0
|
||||
player2.score = 0
|
||||
player1.reinit(10, pgv.GAMEAREA_MAX_Y/2-50, 0, 0)
|
||||
player2.reinit(pgv.GAMEAREA_MAX_X-40, pgv.GAMEAREA_MAX_Y/2-50, 0, 0)
|
||||
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):
|
||||
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
|
||||
return True
|
||||
|
||||
def crashvectors(self, ball, player1, player2):
|
||||
"""Collission detection"""
|
||||
|
||||
if ball.delta_x < 0: # Ball moves right->left (<----)
|
||||
if (ball.x <= player1.x + player1.w) and (ball.x > player1.x): # 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?
|
||||
|
||||
if ball.color == pgc.COL_WHITE:
|
||||
ball.color = player1.color # Pick up 'infection' (if any)
|
||||
elif ball.color != player1.color: # Infectious ball!
|
||||
return # w/o vaccine -> no save!
|
||||
|
||||
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) and (ball.x < player2.x + player2.w): # 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?
|
||||
|
||||
if ball.color == pgc.COL_WHITE:
|
||||
ball.color = player2.color # Pick up 'infection' (if any)
|
||||
elif ball.color != player2.color: # Infectious ball!
|
||||
return # w/o vaccine -> no save!
|
||||
|
||||
ball.delta_x = -ball.delta_x * 1.2 # Invert direction & speed up
|
||||
if player2.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 player2.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 ...
|
||||
|
||||
def pong_game(self, ball, player1, player2):
|
||||
|
||||
if self.game_fsm(player1, player2) == False: # Exit
|
||||
return False
|
||||
|
||||
# 1. Retrieve user entries
|
||||
bChanged = player1.eval_gamepad()
|
||||
bChanged = player2.eval_gamepad()
|
||||
|
||||
if self.state == pgc.STATE_PLAY: # Actually playing?
|
||||
# 2. Adjust player positions
|
||||
bChanged = player1.eval_position(pgv.GAMEAREA_MIN_X, pgv.GAMEAREA_MAX_X/2-50)
|
||||
bChanged = player2.eval_position(pgv.GAMEAREA_MAX_X/2+50, pgv.GAMEAREA_MAX_X)
|
||||
|
||||
# 3. Crash analyses
|
||||
self.crashvectors(ball, player1, player2)
|
||||
|
||||
# 4. Adjust object positions (ball & potentially others ...)
|
||||
rc = ball.eval_object()
|
||||
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')
|
||||
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')
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("pong_game has no function, call 'pandemic_pong.py'")
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
pong_globalvars.py
|
||||
|
||||
Pandemic Pong global variables
|
||||
|
||||
"""
|
||||
|
||||
""" Game area dimensions, shall be mutable to adjust for window resize (later)"""
|
||||
GAMEAREA_MIN_X = 0 # Game area left border
|
||||
GAMEAREA_MAX_X = 1920 # Assume FHD resolution by default
|
||||
GAMEAREA_MIN_Y = 15 # Game area top border
|
||||
GAMEAREA_MAX_Y = 940 # Game area bottom range
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
pong_object.py
|
||||
|
||||
Pandemic Pong Objects logic (i.e. ball ;)
|
||||
|
||||
"""
|
||||
|
||||
from random import random # For random start data ...
|
||||
from playsound import playsound # Play some sounds
|
||||
import pong_constants as pgc # Pong global constants
|
||||
import pong_globalvars as pgv # Pong global variables
|
||||
|
||||
class PongObject:
|
||||
def __init__(self, x, y, w, h, delta_x, delta_y):
|
||||
"""Initialize non-player object (i.e. 'ball' - but maybe more objects later!)"""
|
||||
|
||||
self.x = x # Current position
|
||||
self.y = y
|
||||
self.w = w # Size of object
|
||||
self.h = h
|
||||
self.delta_x = delta_x # Current movement
|
||||
self.delta_y = (random() - 0.5) * 10 # TODO: Move logic to caller ...
|
||||
self.color = pgc.COL_WHITE
|
||||
self.delay = 0
|
||||
|
||||
def reinit(self, delta_x, delta_y):
|
||||
"""Re-Initialize object for next game"""
|
||||
|
||||
self.x = pgv.GAMEAREA_MAX_X/2 - self.w/2
|
||||
self.y = pgv.GAMEAREA_MAX_Y/2 - self.h/2
|
||||
self.delta_x = delta_x
|
||||
self.delta_y = delta_y
|
||||
self.color = pgc.COL_WHITE
|
||||
self.delay = 0
|
||||
|
||||
def eval_object(self):
|
||||
"""Object movement w/ sound support"""
|
||||
|
||||
bChanged = 0
|
||||
sum_x = self.x + self.delta_x
|
||||
sum_y = self.y + self.delta_y
|
||||
|
||||
if sum_x < pgv.GAMEAREA_MIN_X:
|
||||
#sum_x = GAMEAREA_MIN_X
|
||||
#self.delta_x = -self.delta_x
|
||||
bChanged = -1 # Miss left
|
||||
elif sum_x + self.w > pgv.GAMEAREA_MAX_X:
|
||||
#sum_x = GAMEAREA_MAX_X - self.w
|
||||
#self.delta_x = -self.delta_x
|
||||
bChanged = 1 # Miss right
|
||||
|
||||
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')
|
||||
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')
|
||||
|
||||
self.x = sum_x
|
||||
self.y = sum_y
|
||||
return bChanged
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("***** pong_object has no function, call 'pandemic_pong.py'!")
|
|
@ -0,0 +1,175 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
pong_player.py
|
||||
|
||||
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
|
||||
|
||||
def print_event(e):
|
||||
"""Sample from libevdev docs, useful for testing ..."""
|
||||
|
||||
print("Event: time {}.{:06d}, ".format(e.sec, e.usec), end='')
|
||||
if e.matches(libevdev.EV_SYN):
|
||||
if e.matches(libevdev.EV_SYN.SYN_MT_REPORT):
|
||||
print("++++++++++++++ {} ++++++++++++".format(e.code.name))
|
||||
elif e.matches(libevdev.EV_SYN.SYN_DROPPED):
|
||||
print(">>>>>>>>>>>>>> {} >>>>>>>>>>>>".format(e.code.name))
|
||||
else:
|
||||
print("-------------- {} ------------".format(e.code.name))
|
||||
else:
|
||||
print("type {:02x} {} code {:03x} {:20s} value {:4d}".format(e.type.value, e.type.name, e.code.value, e.code.name, e.value))
|
||||
|
||||
class PongPlayer:
|
||||
"""The player consists of gamepad input & variables"""
|
||||
|
||||
def __init__(self, path, x, y, w, h):
|
||||
# Gamepad init.
|
||||
self.fd = open(path, "rb") # File descriptor to close (later ...)
|
||||
fcntl.fcntl(self.fd, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
self.dev = libevdev.Device(self.fd) # Actual gamepad of this player
|
||||
self.state = pgc.BTN_STATE_NONE # Button mask (as listed above)
|
||||
self.x = x # Current position
|
||||
self.y = y
|
||||
self.w = w # Dimensions
|
||||
self.h = h
|
||||
self.delta_x = 0 # Current delta (speed) settings
|
||||
self.delta_y = 0
|
||||
self.color = pgc.COL_WHITE # 'Infection' colour (white = cleared)
|
||||
self.delay = 0 # 'Infectious' time
|
||||
self.score = 0 # Current score points of this player
|
||||
|
||||
def reinit(self, x, y, delta_x, delta_y):
|
||||
"""Re-initialize player for next game"""
|
||||
|
||||
self.state = 0
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.delta_x = delta_x
|
||||
self.delta_y = delta_y
|
||||
self.color = pgc.COL_WHITE
|
||||
self.delay = 0
|
||||
|
||||
def exit(self):
|
||||
"""To quit gracefully, we should close the event queues ..."""
|
||||
|
||||
self.fd.close()
|
||||
|
||||
def eval_gamepad(self):
|
||||
"""Decode gamepad events (if any ...)"""
|
||||
bChanged = False
|
||||
try:
|
||||
for e in self.dev.events():
|
||||
#print_event(e)
|
||||
|
||||
# Event type 1 (EV_KEY)
|
||||
# Event code 288 (BTN_TRIGGER) <- 1=[Blue/X]
|
||||
# Event code 289 (BTN_THUMB) <- 1=[Red/A]
|
||||
# Event code 290 (BTN_THUMB2) <- 1=[Yellow/B]
|
||||
# Event code 291 (BTN_TOP) <- 1=[Green/Y]
|
||||
# Event code 292 (BTN_TOP2) <- 1=[Frontal left]
|
||||
# Event code 293 (BTN_PINKIE) <- 1=[Frontal right]
|
||||
# Event code 294 (BTN_BASE)
|
||||
# Event code 295 (BTN_BASE2)
|
||||
# Event code 296 (BTN_BASE3) <- 1=[Centre left]
|
||||
# Event code 297 (BTN_BASE4) <- 1=[Centre right]
|
||||
if e.type.value == 1: # Non-Cross events
|
||||
if e.value == 1: # Simple buttons may act as toggles
|
||||
if e.code.value == 288: # BTN_TRIGGER
|
||||
if self.delay <= 0: # As long as we're not infectious ...
|
||||
self.state = pgc.BTN_TRIGGER # self.state ^ pgc.BTN_TRIGGER
|
||||
self.color = pgc.COL_BLUE # Infect 'blue'
|
||||
self.delay = pgc.COLORDELAY # Start infectious time immediately ...
|
||||
elif e.code.value == 289: # BTN_THUMB
|
||||
if self.delay <= 0: # As long as we're not infectious ...
|
||||
self.state = pgc.BTN_THUMB # self.state ^ pgc.BTN_THUMB
|
||||
self.color = pgc.COL_RED
|
||||
self.delay = pgc.COLORDELAY
|
||||
elif e.code.value == 290: # BTN_THUMB2
|
||||
if self.delay <= 0: # As long as we're not infectious ...
|
||||
self.state = pgc.BTN_THUMB2 # self.state ^ pgc.BTN_THUMB2
|
||||
self.color = pgc.COL_YELLOW
|
||||
self.delay = pgc.COLORDELAY
|
||||
elif e.code.value == 291: # BTN_TOP
|
||||
if self.delay <= 0: # As long as we're not infectious ...
|
||||
self.state = pgc.BTN_TOP # self.state ^ pgc.BTN_TOP
|
||||
self.color = pgc.COL_GREEN
|
||||
self.delay = pgc.COLORDELAY
|
||||
|
||||
elif e.code.value == 292: # BTN_TOP2
|
||||
self.state = self.state ^ pgc.BTN_TOP2
|
||||
elif e.code.value == 293: # BTN_PINKIE
|
||||
self.state = self.state ^ pgc.BTN_PINKIE
|
||||
elif e.code.value == 296: # BTN_BASE3
|
||||
self.state = self.state ^ pgc.BTN_BASE3
|
||||
elif e.code.value == 297: # BTN_BASE4
|
||||
self.state = self.state ^ pgc.BTN_BASE4
|
||||
bChanged = True
|
||||
|
||||
# Event type 3 (EV_ABS)
|
||||
# Event code 0 (ABS_X) <- Cross: 127=Neutral, 0=[Left], 255=[Right]
|
||||
# Event code 1 (ABS_Y) <- Cross: 127=Neutral, 0=[Top], 255=[Down]
|
||||
elif e.type.value == 3: # EV_ABS
|
||||
if e.code.value == 0: # ABS_X
|
||||
if e.value == 0:
|
||||
self.delta_x = self.delta_x - 1
|
||||
elif e.value == 255:
|
||||
self.delta_x = self.delta_x + 1
|
||||
else: # 127/Neutral
|
||||
self.delta_x = 0
|
||||
else: # ABS_Y
|
||||
if e.value == 0:
|
||||
self.delta_y = self.delta_y - 1
|
||||
elif e.value == 255:
|
||||
self.delta_y = self.delta_y + 1
|
||||
else: # 127/Neutral
|
||||
self.delta_y = 0
|
||||
bChanged = True
|
||||
|
||||
#if bChanged:
|
||||
# print("State=",self.state, "X=", self.delta_x, "Y=", self.delta_y)
|
||||
|
||||
except libevdev.EventsDroppedException:
|
||||
print("Dropped!")
|
||||
for e in self.dev.sync():
|
||||
print_event(e)
|
||||
|
||||
return bChanged
|
||||
|
||||
def eval_position(self, min_x, max_x):
|
||||
"""Player movement w/ area restrictions"""
|
||||
bChanged = False
|
||||
|
||||
# Left/right positioning
|
||||
sum_x = self.x + self.delta_x * 10
|
||||
if sum_x < min_x:
|
||||
sum_x = min_x
|
||||
elif sum_x + self.w > max_x:
|
||||
sum_x = max_x - self.w
|
||||
|
||||
# Top/bottom positioning
|
||||
sum_y = self.y + self.delta_y * 10
|
||||
if sum_y < pgv.GAMEAREA_MIN_Y:
|
||||
sum_y = pgv.GAMEAREA_MIN_Y
|
||||
elif sum_y + self.h > pgv.GAMEAREA_MAX_Y:
|
||||
sum_y = pgv.GAMEAREA_MAX_Y - self.h
|
||||
|
||||
# Movement indication (TODO: may be removed later ...)
|
||||
if (sum_x != self.x) or (sum_y != self.y):
|
||||
bChanged = True
|
||||
self.x = sum_x
|
||||
self.y = sum_y
|
||||
|
||||
return bChanged
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("***** pong_player has no function, call 'pandemic_pong.py'!")
|
Loading…
Reference in New Issue