2 changed files with 354 additions and 0 deletions
@ -0,0 +1,349 @@
@@ -0,0 +1,349 @@
|
||||
#!/usr/bin/python3 |
||||
|
||||
import sys |
||||
import time |
||||
import enum |
||||
import threading |
||||
import argparse |
||||
import subprocess |
||||
import blup.frame |
||||
import blup.output |
||||
|
||||
class Game(object): |
||||
def __init__(self): |
||||
self.balance = None |
||||
self.pygame = False |
||||
self.output = None |
||||
pass |
||||
|
||||
@property |
||||
def logo(self): |
||||
return self._logo |
||||
|
||||
@property |
||||
def args(self): |
||||
args = [] |
||||
args += ['--players', str(self.players)] |
||||
if self.balance is not None: |
||||
args += ['--balance', self.balance] |
||||
if self.pygame: |
||||
args += ['--pygame'] |
||||
if self.output is not None: |
||||
args += ['--output', self.output] |
||||
return args |
||||
|
||||
class PongGame(Game): |
||||
def __init__(self): |
||||
self.name = 'Pong' |
||||
self.executable = 'balancep0ng.py' |
||||
self.players = 0 |
||||
self._logo = [ |
||||
[1,1,0,0,0,1,1,0,0,1,0,0,1,0,0,1,1,0], |
||||
[1,0,1,0,1,0,0,1,0,1,1,0,1,0,1,0,0,0], |
||||
[1,1,0,0,1,0,0,1,0,1,0,1,1,0,1,0,1,1], |
||||
[1,0,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1], |
||||
[1,0,0,0,0,1,1,0,0,1,0,0,1,0,0,1,1,0], |
||||
] |
||||
|
||||
class TetrisGame(Game): |
||||
def __init__(self): |
||||
self.name = 'Tetris' |
||||
self.executable = 'ttrs.py' |
||||
self.players = 0 |
||||
self._logo = [ |
||||
[1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,0,0,1,1], |
||||
[0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,1,0,0], |
||||
[0,1,0,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,1,0], |
||||
[0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,0,1], |
||||
[0,1,0,0,1,1,0,0,1,0,0,1,0,1,0,1,0,1,1,0], |
||||
] |
||||
|
||||
arrow_up = [ |
||||
[0,0,1,0,0], |
||||
[0,1,1,1,0], |
||||
[1,1,1,1,1], |
||||
] |
||||
arrow_down = list(reversed(arrow_up)) |
||||
|
||||
arrow_left = [ |
||||
[0,0,1], |
||||
[0,1,1], |
||||
[1,1,1], |
||||
[0,1,1], |
||||
[0,0,1], |
||||
] |
||||
arrow_right = [list(reversed(x)) for x in arrow_left] |
||||
|
||||
go = [ |
||||
[0,1,0,0,0,1,0], |
||||
[1,0,0,0,1,0,1], |
||||
[1,0,1,0,1,0,1], |
||||
[0,1,0,0,0,1,0], |
||||
] |
||||
|
||||
select_game = [ |
||||
[0,1,1,0,1,1,0,1,0,0,1,1,0,1,1,0,1,1,1], |
||||
[1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0], |
||||
[0,1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,0,1,0], |
||||
[0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0], |
||||
[1,1,0,0,1,1,0,1,1,0,1,1,0,1,1,0,0,1,0], |
||||
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], |
||||
[0,0,1,1,0,0,0,1,0,0,1,0,0,0,1,0,1,1,0], |
||||
[0,1,0,0,0,0,1,0,1,0,1,1,0,1,1,0,1,0,0], |
||||
[0,1,0,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,0], |
||||
[0,1,0,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0], |
||||
[0,0,1,1,0,0,1,0,1,0,1,0,0,0,1,0,1,1,0], |
||||
] |
||||
|
||||
player2 = [ |
||||
[0,1,1,1,0,0,1,1,1,0,0,0,1,1,0], |
||||
[1,0,0,0,1,0,1,0,0,1,0,1,0,0,1], |
||||
[0,0,0,1,0,0,1,0,0,1,0,0,0,1,0], |
||||
[0,0,1,0,0,0,1,1,1,0,0,0,1,0,0], |
||||
[0,1,0,0,0,0,1,0,0,0,0,0,0,0,0], |
||||
[1,1,1,1,1,0,1,0,0,0,0,0,1,0,0], |
||||
] |
||||
|
||||
def copy_bitmap(bitmap, frame, color, xoffs=0, yoffs=0): |
||||
for x in range(len(bitmap[0])): |
||||
for y in range(len(bitmap)): |
||||
if bitmap[y][x] == 1: |
||||
frame.setPixel(xoffs + x, yoffs + y, color) |
||||
|
||||
def create_init_screen(dimension): |
||||
frame = blup.frame.Frame(dimension) |
||||
|
||||
xoffs = (dimension.size()[0]-len(select_game[0]))//2 |
||||
yoffs = (dimension.size()[1]-len(select_game))//2 |
||||
color = (0, 255, 0) |
||||
copy_bitmap(select_game, frame, color, xoffs, yoffs) |
||||
|
||||
return frame |
||||
|
||||
def create_2player_screen(dimension): |
||||
frame = blup.frame.Frame(dimension) |
||||
|
||||
xoffs = (dimension.size()[0]-len(player2[0]))//2 |
||||
yoffs = (dimension.size()[1]-len(player2))//2 |
||||
color = (0, 255, 0) |
||||
copy_bitmap(player2, frame, color, xoffs, yoffs) |
||||
|
||||
return frame |
||||
|
||||
def create_menu_frame(dimension, game): |
||||
frame = blup.frame.Frame(dimension) |
||||
|
||||
xoffs = (dimension.size()[0]-len(arrow_up[0]))//2 |
||||
yoffs = 0 |
||||
color = (255, 0, 0) |
||||
copy_bitmap(arrow_up, frame, color, xoffs, yoffs) |
||||
|
||||
xoffs = xoffs+len(arrow_up[0])+1 |
||||
color = (255, 0, 0) |
||||
copy_bitmap(go, frame, color, xoffs, yoffs) |
||||
|
||||
xoffs = 0 |
||||
yoffs = dimension.size()[1]-len(arrow_right) |
||||
color = (0, 0, 255) |
||||
copy_bitmap(arrow_left, frame, color, xoffs, yoffs) |
||||
xoffs = dimension.size()[0]-len(arrow_right[0]) |
||||
color = (255, 255, 0) |
||||
copy_bitmap(arrow_right, frame, color, xoffs, yoffs) |
||||
|
||||
xoffs = (dimension.size()[0]-len(game.logo[0]))//2 |
||||
yoffs = (dimension.size()[1]-len(game.logo))//2 |
||||
color = (0, 255, 255) |
||||
copy_bitmap(game.logo, frame, color, xoffs, yoffs) |
||||
|
||||
return frame |
||||
|
||||
InputEvent = enum.Enum('InputEvent', ['UP', 'DOWN', 'LEFT', |
||||
'RIGHT', 'QUIT', 'STEP_ON']) |
||||
|
||||
class AbstractInput(): |
||||
def __init__(self): |
||||
pass |
||||
|
||||
def get_event(self): |
||||
return None |
||||
|
||||
class TestInput(AbstractInput): |
||||
def __init__(self): |
||||
self.__evt = None |
||||
|
||||
import pygame |
||||
self.__pygame = pygame |
||||
self.screen = pygame.display.set_mode((100, 100)) |
||||
pygame.display.update() |
||||
|
||||
self.controls = { |
||||
pygame.K_a: InputEvent.LEFT, |
||||
pygame.K_d: InputEvent.RIGHT, |
||||
pygame.K_w: InputEvent.UP, |
||||
pygame.K_s: InputEvent.STEP_ON, |
||||
pygame.K_ESCAPE: InputEvent.QUIT, |
||||
} |
||||
|
||||
def get_event(self): |
||||
pygame = self.__pygame |
||||
for event in pygame.event.get(): |
||||
if event.type == pygame.KEYDOWN: |
||||
return self.controls.get(event.key, None) |
||||
return None |
||||
|
||||
class BalanceInput(AbstractInput, threading.Thread): |
||||
def __init__(self, addr, player_id): |
||||
self.addr = addr |
||||
self.player_id = player_id |
||||
self.evt = None |
||||
self.oldevt = None |
||||
self.player_present = False |
||||
threading.Thread.__init__(self, daemon=True) |
||||
self.start() |
||||
|
||||
def run(self): |
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||
try: |
||||
sock.connect(self.addr) |
||||
except ConnectionRefusedError: |
||||
print('could not connect to balance server', file=sys.stderr) |
||||
self.evt = InputEvent.QUIT |
||||
return |
||||
self.running = True |
||||
evt = None |
||||
oldevt = None |
||||
lastchange = 0 |
||||
while self.running: |
||||
sock.send(b'a') |
||||
data = sock.recv(4) |
||||
p0x, p0y, p1x, p1y = struct.unpack('bbbb', data) |
||||
if self.player_id == 0: |
||||
xbal, ybal = p0x, p0y |
||||
elif self.player_id == 1: |
||||
xbal, ybal = p1x, p1y |
||||
|
||||
print('player_id=%d xbal=%d ybal=%d' % (self.player_id, xbal, ybal)) |
||||
THRESHOLD = 40 |
||||
MIN_TIMES = { |
||||
InputEvent.LEFT: 0.1, |
||||
InputEvent.RIGHT: 0.1, |
||||
InputEvent.UP: 0.1, |
||||
InputEvent.DOWN: 0.1, |
||||
} |
||||
if self.player_present: |
||||
if xbal == -128 or ybal == -128: |
||||
self.evt = InputEvent.QUIT |
||||
self.player_present = False |
||||
continue |
||||
|
||||
if abs(xbal) < THRESHOLD and abs(ybal) < THRESHOLD: |
||||
evt = None |
||||
else: |
||||
if abs(xbal) < abs(ybal): |
||||
if ybal > 0: |
||||
evt = InputEvent.UP |
||||
else: |
||||
evt = InputEvent.DOWN |
||||
else: |
||||
if xbal > 0: |
||||
evt = InputEvent.RIGHT |
||||
else: |
||||
evt = InputEvent.LEFT |
||||
if evt != oldevt: |
||||
lastchange = time.time() |
||||
oldevt = evt |
||||
|
||||
if time.time() - lastchange < MIN_TIMES.get(evt, 0): |
||||
print('player_id=%d debounce %s' % (self.player_id, evt)) |
||||
continue |
||||
|
||||
self.evt = evt |
||||
print('player_id=%d event=%s' % (self.player_id, self.evt)) |
||||
|
||||
else: |
||||
if xbal != -128 and ybal != -128: |
||||
self.evt = InputEvent.STEP_ON |
||||
self.player_present = True |
||||
continue |
||||
|
||||
def get_event(self): |
||||
evt = self.evt |
||||
self.evt = None |
||||
return evt |
||||
|
||||
def start_game(game, players): |
||||
print('Starting', game.name, 'for', players, 'player(s)') |
||||
game.players = players |
||||
arg = ['./'+game.executable] + game.args |
||||
subprocess.call(arg) |
||||
sys.exit() |
||||
|
||||
if __name__ == '__main__': |
||||
parser = argparse.ArgumentParser(description='Blinkenbunt Game Selection Menu') |
||||
parser.add_argument('--pygame', dest='pygame', action='store_true', |
||||
help='use pygame as input') |
||||
parser.add_argument('--balance', dest='balance', type=str, |
||||
metavar='HOST:PORT', help='use balance input') |
||||
parser.add_argument('--out', dest='out', type=str, metavar='OUTPUT', |
||||
default='e3blp', help='blup output specification') |
||||
args = parser.parse_args() |
||||
|
||||
if args.balance is None and not args.pygame: |
||||
print('please specify an input method', file=sys.stderr) |
||||
sys.exit(1) |
||||
|
||||
w = 22 |
||||
h = 16 |
||||
|
||||
out = blup.output.getOutput(args.out) |
||||
dim = blup.frame.FrameDimension(w, h, 256, 3) |
||||
|
||||
if args.pygame: |
||||
inp1 = TestInput() |
||||
inp2 = TestInput() |
||||
elif args.balance is not None: |
||||
host, port = args.balance.split(':') |
||||
inp1 = BalanceInput((host, int(port)), 0) |
||||
inp2 = BalanceInput((host, int(port)), 1) |
||||
|
||||
while inp1.get_event() != InputEvent.STEP_ON: |
||||
time.sleep(0.05) |
||||
|
||||
init_frame = create_init_screen(dim) |
||||
out.sendFrame(init_frame) |
||||
time.sleep(2) |
||||
games = Game.__subclasses__() |
||||
game_idx = 0 |
||||
while True: |
||||
gamecls = games[game_idx] |
||||
game = gamecls() |
||||
out.sendFrame(create_menu_frame(dim, game)) |
||||
|
||||
evt = inp1.get_event() |
||||
if evt == InputEvent.LEFT: |
||||
game_idx -= 1 |
||||
if game_idx < 0: |
||||
game_idx = len(games)-1 |
||||
if evt == InputEvent.RIGHT: |
||||
game_idx += 1 |
||||
if game_idx >= len(games): |
||||
game_idx = 0 |
||||
if evt == InputEvent.UP: |
||||
game.output = args.out |
||||
game.balance = args.balance |
||||
game.pygame = args.pygame |
||||
break |
||||
if evt == InputEvent.QUIT: |
||||
sys.exit() |
||||
|
||||
p2_frame = create_2player_screen(dim) |
||||
out.sendFrame(p2_frame) |
||||
wait_time = 3 |
||||
start = time.time() |
||||
while time.time() < start+wait_time: |
||||
if inp2.get_event() == InputEvent.STEP_ON: |
||||
start_game(game, 2) |
||||
time.sleep(0.1) |
||||
|
||||
start_game(game, 1) |
||||
|
Loading…
Reference in new issue