foo
This commit is contained in:
parent
27fa6f7c63
commit
6c7d81ed49
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# fork of https://github.com/SmartViking/MaTris by deinkoks
|
||||
# removed everythin but elemental gameplay, added multiplayer controlled via mqtt
|
||||
# most ugly thing: a mqtt client for every player due to callback limitations
|
||||
@ -9,7 +9,7 @@ import os
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
|
||||
from tetrominoes import list_of_tetrominoes
|
||||
from tetrominoes import list_of_tetrominoes, shape_str
|
||||
from tetrominoes import rotate
|
||||
|
||||
from scores import load_score, write_score
|
||||
@ -21,12 +21,16 @@ def get_sound(filename):
|
||||
return pygame.mixer.Sound(os.path.join(os.path.dirname(__file__), "resources", filename))
|
||||
|
||||
ENABLE_STDIO = True #dump game on stdio, not sure if works as intended.
|
||||
ENABLE_MQTT = True # for debugging w/o a broker
|
||||
ENABLE_SOUND = False
|
||||
ENABLE_KEYBOARD_CONTROLS = False # working for player1. mostly
|
||||
MQTT_TOPIC = "deckentetris/"
|
||||
|
||||
PLAYER = 10 # player count, 1 columns per player
|
||||
BGCOLOR = (15, 15, 20)
|
||||
BORDERCOLOR = (140, 140, 140)
|
||||
|
||||
BLOCKSIZE = 16 # set this to 1 if run on the pixeldecke
|
||||
GAMEOVER_COLOR = (140, 100, 100)
|
||||
BLOCKSIZE = 1 # set this to 1 if run on the pixeldecke
|
||||
BORDERWIDTH = 0
|
||||
|
||||
MATRIS_OFFSET = 0
|
||||
@ -34,14 +38,14 @@ MATRIS_OFFSET = 0
|
||||
# we have 8pixel columns with a height of 5*8px for every player
|
||||
# lets use one for the next block, but 2 lines are hidden
|
||||
MATRIX_WIDTH = 8
|
||||
MATRIX_HEIGHT = (4+2)*8
|
||||
MATRIX_HEIGHT = (4)*8
|
||||
|
||||
LEFT_MARGIN = 0
|
||||
|
||||
WIDTH = (MATRIX_WIDTH*BLOCKSIZE + MATRIS_OFFSET*2 + LEFT_MARGIN) * PLAYER
|
||||
HEIGHT = (MATRIX_HEIGHT-2)*BLOCKSIZE + MATRIS_OFFSET*2
|
||||
HEIGHT += BLOCKSIZE*8 # additional tile for preview above game
|
||||
|
||||
HEIGHT += 2 # height fix for reasons
|
||||
TRICKY_CENTERX = WIDTH-(WIDTH-(MATRIS_OFFSET+BLOCKSIZE*MATRIX_WIDTH))/2
|
||||
|
||||
VISIBLE_MATRIX_HEIGHT = MATRIX_HEIGHT - 2
|
||||
@ -60,22 +64,18 @@ class Matris(object):
|
||||
self.request_movement('left')
|
||||
elif payload == "right":
|
||||
self.request_movement('right')
|
||||
else:
|
||||
pass #print the matrix
|
||||
elif payload == "update":
|
||||
self.mqtt.publish(MQTT_TOPIC+str(offset)+"/current", payload=shape_str(self.current_tetromino.shape), qos=0, retain=False)
|
||||
self.mqtt.publish(MQTT_TOPIC+str(offset)+"/next", payload=shape_str(self.next_tetromino.shape), qos=0, retain=False)
|
||||
|
||||
def __init__(self, offset):
|
||||
self.surface = screen.subsurface(Rect((MATRIX_WIDTH * BLOCKSIZE*offset, 8*BLOCKSIZE),
|
||||
(MATRIX_WIDTH * BLOCKSIZE, (MATRIX_HEIGHT-2) * BLOCKSIZE)))
|
||||
self.mqtt = mqtt.Client()
|
||||
self.mqtt.connect("mqtt.chaospott.de", port=1883, keepalive=60, bind_address="")
|
||||
self.offset = offset
|
||||
self.matrix = dict()
|
||||
for y in range(MATRIX_HEIGHT):
|
||||
for x in range(MATRIX_WIDTH):
|
||||
self.matrix[(y,x)] = None
|
||||
self.mqtt.subscribe("deckentetris/"+str(offset)+"/action", 2)
|
||||
self.mqtt.on_message = self.on_msg
|
||||
self.mqtt.loop_start()
|
||||
"""
|
||||
`self.matrix` is the current state of the tetris board, that is, it records which squares are
|
||||
currently occupied. It does not include the falling tetromino. The information relating to the
|
||||
@ -109,6 +109,15 @@ class Matris(object):
|
||||
self.linescleared_sound = get_sound("linecleared.wav")
|
||||
self.highscorebeaten_sound = get_sound("highscorebeaten.wav")
|
||||
|
||||
if ENABLE_MQTT:
|
||||
self.mqtt = mqtt.Client()
|
||||
self.mqtt.connect("mqtt.chaospott.de", port=1883, keepalive=60, bind_address="")
|
||||
self.mqtt.subscribe(MQTT_TOPIC+str(offset)+"/action", 2)
|
||||
self.mqtt.on_message = self.on_msg
|
||||
self.mqtt.loop_start()
|
||||
self.mqtt.publish(MQTT_TOPIC+str(offset)+"/current", payload=shape_str(self.current_tetromino.shape), qos=0, retain=False)
|
||||
self.mqtt.publish(MQTT_TOPIC+str(offset)+"/next", payload=shape_str(self.next_tetromino.shape), qos=0, retain=False)
|
||||
|
||||
|
||||
def set_tetrominoes(self):
|
||||
self.current_tetromino = self.next_tetromino
|
||||
@ -132,43 +141,45 @@ class Matris(object):
|
||||
def update(self, timepassed):
|
||||
self.needs_redraw = False
|
||||
|
||||
pressed = lambda key: event.type == pygame.KEYDOWN and event.key == key
|
||||
unpressed = lambda key: event.type == pygame.KEYUP and event.key == key
|
||||
#self.mqtt.loop()
|
||||
events = pygame.event.get()
|
||||
if ENABLE_KEYBOARD_CONTROLS:
|
||||
pressed = lambda key: event.type == pygame.KEYDOWN and event.key == key
|
||||
unpressed = lambda key: event.type == pygame.KEYUP and event.key == key
|
||||
|
||||
for event in events:
|
||||
if pressed(pygame.K_p):
|
||||
self.surface.fill((0,0,0))
|
||||
self.needs_redraw = True
|
||||
self.paused = not self.paused
|
||||
elif event.type == pygame.QUIT:
|
||||
self.gameover(full_exit=True)
|
||||
elif pressed(pygame.K_ESCAPE):
|
||||
self.gameover()
|
||||
events = pygame.event.get()
|
||||
|
||||
for event in events:
|
||||
if pressed(pygame.K_p):
|
||||
self.surface.fill((0,0,0))
|
||||
self.needs_redraw = True
|
||||
self.paused = not self.paused
|
||||
elif event.type == pygame.QUIT:
|
||||
self.gameover(full_exit=True)
|
||||
elif pressed(pygame.K_ESCAPE):
|
||||
self.gameover()
|
||||
|
||||
if self.paused:
|
||||
return self.needs_redraw
|
||||
|
||||
for event in events:
|
||||
if pressed(pygame.K_SPACE):
|
||||
self.hard_drop()
|
||||
elif pressed(pygame.K_UP) or pressed(pygame.K_w):
|
||||
self.request_rotation()
|
||||
if ENABLE_KEYBOARD_CONTROLS:
|
||||
for event in events:
|
||||
if pressed(pygame.K_SPACE):
|
||||
self.hard_drop()
|
||||
elif pressed(pygame.K_UP) or pressed(pygame.K_w):
|
||||
self.request_rotation()
|
||||
|
||||
elif pressed(pygame.K_LEFT) or pressed(pygame.K_a):
|
||||
self.request_movement('left')
|
||||
self.movement_keys['left'] = 1
|
||||
elif pressed(pygame.K_RIGHT) or pressed(pygame.K_d):
|
||||
self.request_movement('right')
|
||||
self.movement_keys['right'] = 1
|
||||
elif pressed(pygame.K_LEFT) or pressed(pygame.K_a):
|
||||
self.request_movement('left')
|
||||
self.movement_keys['left'] = 1
|
||||
elif pressed(pygame.K_RIGHT) or pressed(pygame.K_d):
|
||||
self.request_movement('right')
|
||||
self.movement_keys['right'] = 1
|
||||
|
||||
elif unpressed(pygame.K_LEFT) or unpressed(pygame.K_a):
|
||||
self.movement_keys['left'] = 0
|
||||
self.movement_keys_timer = (-self.movement_keys_speed)*2
|
||||
elif unpressed(pygame.K_RIGHT) or unpressed(pygame.K_d):
|
||||
self.movement_keys['right'] = 0
|
||||
self.movement_keys_timer = (-self.movement_keys_speed)*2
|
||||
elif unpressed(pygame.K_LEFT) or unpressed(pygame.K_a):
|
||||
self.movement_keys['left'] = 0
|
||||
self.movement_keys_timer = (-self.movement_keys_speed)*2
|
||||
elif unpressed(pygame.K_RIGHT) or unpressed(pygame.K_d):
|
||||
self.movement_keys['right'] = 0
|
||||
self.movement_keys_timer = (-self.movement_keys_speed)*2
|
||||
|
||||
|
||||
|
||||
@ -176,8 +187,12 @@ class Matris(object):
|
||||
self.downwards_speed = self.base_downwards_speed ** (1 + self.level/10.)
|
||||
|
||||
self.downwards_timer += timepassed
|
||||
downwards_speed = self.downwards_speed*0.10 if any([pygame.key.get_pressed()[pygame.K_DOWN],
|
||||
pygame.key.get_pressed()[pygame.K_s]]) else self.downwards_speed
|
||||
|
||||
if ENABLE_KEYBOARD_CONTROLS:
|
||||
downwards_speed = self.downwards_speed*0.10 if any([pygame.key.get_pressed()[pygame.K_DOWN],
|
||||
pygame.key.get_pressed()[pygame.K_s]]) else self.downwards_speed
|
||||
else:
|
||||
downwards_speed = self.downwards_speed
|
||||
if self.downwards_timer > downwards_speed:
|
||||
if not self.request_movement('down'):
|
||||
self.lock_tetromino()
|
||||
@ -185,11 +200,12 @@ class Matris(object):
|
||||
self.downwards_timer %= downwards_speed
|
||||
|
||||
|
||||
if any(self.movement_keys.values()):
|
||||
self.movement_keys_timer += timepassed
|
||||
if self.movement_keys_timer > self.movement_keys_speed:
|
||||
self.request_movement('right' if self.movement_keys['right'] else 'left')
|
||||
self.movement_keys_timer %= self.movement_keys_speed
|
||||
if ENABLE_KEYBOARD_CONTROLS:
|
||||
if any(self.movement_keys.values()):
|
||||
self.movement_keys_timer += timepassed
|
||||
if self.movement_keys_timer > self.movement_keys_speed:
|
||||
self.request_movement('right' if self.movement_keys['right'] else 'left')
|
||||
self.movement_keys_timer %= self.movement_keys_speed
|
||||
|
||||
return self.needs_redraw
|
||||
|
||||
@ -216,13 +232,15 @@ class Matris(object):
|
||||
is responsible for checking if it's game over.
|
||||
"""
|
||||
|
||||
write_score(self.score)
|
||||
|
||||
if full_exit:
|
||||
exit()
|
||||
else:
|
||||
raise GameOver("Sucker!")
|
||||
#write_score(self.score)
|
||||
|
||||
#if full_exit:
|
||||
# exit()
|
||||
#else:
|
||||
# raise GameOver("Sucker!")
|
||||
self.paused = True
|
||||
self.surface.fill(GAMEOVER_COLOR)
|
||||
self.needs_redraw =True
|
||||
def place_shadow(self):
|
||||
posY, posX = self.tetromino_position
|
||||
while self.blend(position=(posY, posX)):
|
||||
@ -333,17 +351,18 @@ class Matris(object):
|
||||
self.lines += lines_cleared
|
||||
|
||||
if lines_cleared:
|
||||
if lines_cleared >= 4:
|
||||
if lines_cleared >= 4 and ENABLE_SOUND:
|
||||
self.linescleared_sound.play()
|
||||
self.score += 100 * (lines_cleared**2) * self.combo
|
||||
|
||||
if not self.played_highscorebeaten_sound and self.score > self.highscore:
|
||||
if self.highscore != 0:
|
||||
if self.highscore != 0 and ENABLE_SOUND:
|
||||
self.highscorebeaten_sound.play()
|
||||
self.played_highscorebeaten_sound = True
|
||||
|
||||
if self.lines >= self.level*10:
|
||||
self.levelup_sound.play()
|
||||
if ENABLE_SOUND:
|
||||
self.levelup_sound.play()
|
||||
self.level += 1
|
||||
|
||||
self.combo = self.combo + 1 if lines_cleared else 1
|
||||
@ -351,7 +370,8 @@ class Matris(object):
|
||||
self.set_tetrominoes()
|
||||
|
||||
if not self.blend():
|
||||
self.gameover_sound.play()
|
||||
if ENABLE_SOUND:
|
||||
self.gameover_sound.play()
|
||||
self.gameover()
|
||||
|
||||
self.needs_redraw = True
|
||||
@ -450,8 +470,9 @@ class Game(object):
|
||||
|
||||
pygame.display.flip()
|
||||
if ENABLE_STDIO:
|
||||
#print(screen.get_view('2'))
|
||||
os.write(1, screen.get_view('2'))
|
||||
#print("-------------")
|
||||
#print(pygame.image.tostring(screen, "RGB", False))
|
||||
os.write(1, pygame.image.tostring(screen, "RGB", False))
|
||||
|
||||
|
||||
def blit_next_tetromino(self, tetromino_surf, offset):
|
||||
@ -498,9 +519,14 @@ def construct_nightmare(size):
|
||||
|
||||
if __name__ == '__main__':
|
||||
pygame.init()
|
||||
|
||||
print("Width:", WIDTH, "Height:", HEIGHT, "Playercount:", PLAYER)
|
||||
if ENABLE_MQTT or True:
|
||||
print("MQTT enabled:")
|
||||
print("TOPIC:", MQTT_TOPIC+"<playerid>/action", " PAYLOAD: left|right|rotate|drop|update")
|
||||
print("TOPIC:", MQTT_TOPIC+"<playerid>/current", "Show the current tetromino. Updated by update @ /action.")
|
||||
print("TOPIC:", MQTT_TOPIC+"<playerid>/next", "Show the current tetromino. Updated by update @ /action.")
|
||||
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption("MaTris")
|
||||
pygame.display.set_caption("Deckentetris")
|
||||
# Menu().main(screen)
|
||||
Game().main(screen)
|
||||
|
||||
|
@ -17,9 +17,9 @@ uint32_t hash32(uint32_t d) {
|
||||
}
|
||||
|
||||
// must be the next prime after NUM_TOTAL_LEDS
|
||||
#define IDLE_PRIME 1931
|
||||
#define IDLE_PRIME 3203
|
||||
// must be a primitive element of the prime residue field |N/IDLE_PRIM
|
||||
#define IDLE_PRIM_ELEM 283
|
||||
#define IDLE_PRIM_ELEM 777
|
||||
|
||||
int IDLE_rand(int *seed){
|
||||
return *seed = (*seed * IDLE_PRIM_ELEM ) % IDLE_PRIME;
|
||||
@ -75,4 +75,4 @@ int main(int argc, char **argv) {
|
||||
usleep(1000*sleepms);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
apps/pong.py
20
apps/pong.py
@ -9,8 +9,8 @@ import random
|
||||
|
||||
PADDLE_LEN = 6
|
||||
|
||||
Nx = int(sys.argv[1])
|
||||
Ny = int(sys.argv[2])
|
||||
Ny = int(sys.argv[1])
|
||||
Nx = int(sys.argv[2])
|
||||
param = sys.argv[3]
|
||||
|
||||
speed = 1.0
|
||||
@ -21,8 +21,10 @@ except:
|
||||
|
||||
pygame.init()
|
||||
pygame.joystick.init()
|
||||
j = pygame.joystick.Joystick(0)
|
||||
j.init()
|
||||
j1 = pygame.joystick.Joystick(0)
|
||||
j2 = pygame.joystick.Joystick(1)
|
||||
j1.init()
|
||||
j2.init()
|
||||
|
||||
numbers = [
|
||||
int("0b111101101101111", 2),
|
||||
@ -69,14 +71,14 @@ while True:
|
||||
|
||||
time.sleep(0.016)
|
||||
|
||||
if j.get_axis(0) > 0 and player1+PADDLE_LEN < Nx:
|
||||
if j1.get_axis(0) > 0.2 and player1+PADDLE_LEN < Nx:
|
||||
player1 += 1
|
||||
if j.get_axis(0) < 0 and player1 > 0 :
|
||||
if j1.get_axis(0) < -0.2 and player1 > 0 :
|
||||
player1 -= 1
|
||||
|
||||
if j.get_axis(1) > 0 and player2+PADDLE_LEN < Nx:
|
||||
if j2.get_axis(0) > 0.2 and player2+PADDLE_LEN < Nx:
|
||||
player2 += 1
|
||||
if j.get_axis(1) < 0 and player2 > 0 :
|
||||
if j2.get_axis(0) < -0.2 and player2 > 0 :
|
||||
player2 -= 1
|
||||
|
||||
x += dx
|
||||
@ -114,7 +116,7 @@ while True:
|
||||
|
||||
buffer = bytearray(b"\x00"*(3*Nx*Ny))
|
||||
def SetPixel(x, y, r, g, b):
|
||||
idx = 3*(x+Nx*y)
|
||||
idx = 3*(y+Ny*x)
|
||||
buffer[idx+0] = r
|
||||
buffer[idx+1] = g
|
||||
buffer[idx+2] = b
|
||||
|
@ -1,2 +1,6 @@
|
||||
#!/bin/sh
|
||||
youtube-dl --no-progress --output - ${3} | ffmpeg -f alsa default -re -i - -pix_fmt rgb24 -vf "scale=${1}x${2}" -sws_flags bicubic -sws_dither bayer -vcodec rawvideo -f image2pipe -
|
||||
#!/bin/bash
|
||||
export PATH="$PATH:/home/deckensteuerung/.config/bin"
|
||||
youtube-dl --no-progress --output - ${3} | ffmpeg -f alsa default -re -i - -pix_fmt rgb24 -vf "scale=${1}x${2}" -sws_flags bicubic -sws_dither bayer -vcodec rawvideo -f image2pipe -
|
||||
#youtube-dl --no-progress --output - ${3} | ffmpeg -re -i - -pix_fmt rgb24 -vf "scale=${1}x${2}" -sws_flags bicubic -sws_dither bayer -vcodec rawvideo -f image2pipe -
|
||||
|
||||
exit 0
|
||||
|
25
config.py
25
config.py
@ -1,7 +1,7 @@
|
||||
import logging
|
||||
|
||||
#width
|
||||
ScreenX = 48
|
||||
ScreenX = 80
|
||||
#height
|
||||
ScreenY = 40
|
||||
|
||||
@ -13,19 +13,26 @@ NoDataTimeout = 40
|
||||
LogLevel = logging.DEBUG
|
||||
|
||||
UseGui = True
|
||||
GuiScaleFactor = 20
|
||||
GuiScaleFactor = 15
|
||||
|
||||
WebHost = "localhost"
|
||||
WebHost = "0.0.0.0"
|
||||
WebPort = 8000
|
||||
|
||||
# first app is always running in IDLE
|
||||
# first app is always running in IDLE
|
||||
Apps = [
|
||||
{"guiname": "Dual moodlight", "name": "bimood", "cmd": "apps/bimood", "persistent": False},
|
||||
{"guiname": "IDLE", "name": "pixelflut", "cmd": "apps/idle.py", "persistent": False},
|
||||
{"guiname": "IDLE2", "name": "idlec", "cmd": "apps/idle2"},
|
||||
{"guiname": "YoutubeDL", "name": "youtubedl", "cmd": "apps/youtubedl.sh"},
|
||||
{"guiname": "Snake", "name": "snake", "cmd": "apps/snake.py"},
|
||||
{"guiname": "Tetris", "name": "tetris", "cmd": "apps/deckentetris/deckentetris.py"}
|
||||
{"guiname": "Strobo", "name": "strobo", "cmd": "apps/strobo.py"},
|
||||
{"guiname": "YoutubeDL", "name": "youtubedl", "cmd": "apps/youtubedl.sh", "persistent": False},
|
||||
{"guiname": "Stream", "name": "stream", "cmd": "apps/stream.sh", "persistent": False},
|
||||
{"guiname": "Wget Video/Gif/Images", "name": "wget", "cmd": "apps/wget.sh", "persistent": False},
|
||||
{"guiname": "Tetris", "name": "tetris", "cmd": "apps/deckentetris/deckentetris.py", "persistent": False},
|
||||
{"guiname": "SkyScrapper", "name": "sky", "cmd": "apps/weather/main.py"},
|
||||
{"guiname": "Strobo", "name": "strobo", "cmd": "apps/strobo.py", "persistent": False},
|
||||
{"guiname": "Snake", "name": "snake", "cmd": "apps/snake.py", "persistent": False},
|
||||
{"name": "pong", "cmd": "apps/pong.py"},
|
||||
{"name": "framebuffer", "cmd": ["apps/fbcp", "/dev/fb0"]},
|
||||
]
|
||||
{"name": "gif", "cmd": "apps/gif.sh"},
|
||||
{"name": "colormap", "cmd": "apps/colormap.py"},
|
||||
{"name": "fibonacci-clock", "cmd": "apps/fibonacci-clock.py"}
|
||||
]
|
||||
|
5
main.py
Normal file → Executable file
5
main.py
Normal file → Executable file
@ -1,3 +1,4 @@
|
||||
|
||||
import config
|
||||
import subprocess
|
||||
import os
|
||||
@ -94,6 +95,7 @@ class SerialWriter(threading.Thread):
|
||||
data = self.datasource.getData()
|
||||
ser.write(b"\01")
|
||||
ser.write(data)
|
||||
ser.flush()
|
||||
except Exception as e:
|
||||
if ser != None:
|
||||
ser.close()
|
||||
@ -138,8 +140,9 @@ class LogReader(threading.Thread):
|
||||
logging.info("LogReader started")
|
||||
while running and self.running:
|
||||
try:
|
||||
self.log += runner.app.stderr.read(1).decode("utf-8")
|
||||
self.log += self.runner.app.stderr.read(1).decode("utf-8")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
time.sleep(1)
|
||||
logging.info("LogReader closed")
|
||||
def stop(self):
|
||||
|
Loading…
Reference in New Issue
Block a user