# WS2812 LED Matrix Gamecontrol (Tetris, Snake, Pong) # by M Oehler # https://hackaday.io/project/11064-raspberry-pi-retro-gaming-led-display # ported from # Tetromino (a Tetris clone) # By Al Sweigart al@inventwithpython.com # http://inventwithpython.com/pygame # Released under a "Simplified BSD" license import random, time, sys, os, pickle from PIL import Image # If Pi = False the script runs in simulation mode using pygame lib PI = True import pygame from pygame.locals import * if PI: os.environ["SDL_VIDEODRIVER"] = "dummy" #dummy display for pygame joystick usage import board import neopixel import subprocess from luma.led_matrix.device import max7219 from luma.core.interface.serial import spi, noop from luma.core.render import canvas from luma.core.virtual import viewport from luma.core.legacy import text, show_message from luma.core.legacy.font import proportional, CP437_FONT, TINY_FONT, SINCLAIR_FONT, LCD_FONT # only modify this two values for size adaption! PIXEL_X=10 PIXEL_Y=20 SIZE= 20 FPS = 15 BOXSIZE = 20 WINDOWWIDTH = BOXSIZE * PIXEL_X WINDOWHEIGHT = BOXSIZE * PIXEL_Y BOARDWIDTH = PIXEL_X BOARDHEIGHT = PIXEL_Y BLANK = '.' MOVESIDEWAYSFREQ = 0.15 MOVEDOWNFREQ = 0.15 FALLING_SPEED = 0.8 LED_BRIGHTNESS = 0.6 # R G B WHITE = (255, 255, 255) GRAY = (185, 185, 185) BLACK = ( 0, 0, 0) RED = (255, 0, 0) LIGHTRED = (175, 20, 20) GREEN = ( 0, 255, 0) LIGHTGREEN = ( 20, 175, 20) BLUE = ( 0, 0, 255) LIGHTBLUE = ( 20, 20, 175) YELLOW = (255, 255, 0) LIGHTYELLOW = (175, 175, 20) CYAN = ( 0, 255, 255) MAGENTA = (255, 0, 255) ORANGE = (255, 100, 0) SCORES =(0,40,100,300,1200) BORDERCOLOR = BLUE BGCOLOR = BLACK TEXTCOLOR = WHITE TEXTSHADOWCOLOR = GRAY COLORS = (BLUE,GREEN,RED,YELLOW,CYAN,MAGENTA,ORANGE) LIGHTCOLORS = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW) #assert len(COLORS) == len(LIGHTCOLORS) # each color must have light color TEMPLATEWIDTH = 5 TEMPLATEHEIGHT = 5 S_SHAPE_TEMPLATE = [['.....', '.....', '..OO.', '.OO..', '.....'], ['.....', '..O..', '..OO.', '...O.', '.....']] Z_SHAPE_TEMPLATE = [['.....', '.....', '.OO..', '..OO.', '.....'], ['.....', '..O..', '.OO..', '.O...', '.....']] I_SHAPE_TEMPLATE = [['..O..', '..O..', '..O..', '..O..', '.....'], ['.....', '.....', 'OOOO.', '.....', '.....']] O_SHAPE_TEMPLATE = [['.....', '.....', '.OO..', '.OO..', '.....']] J_SHAPE_TEMPLATE = [['.....', '.O...', '.OOO.', '.....', '.....'], ['.....', '..OO.', '..O..', '..O..', '.....'], ['.....', '.....', '.OOO.', '...O.', '.....'], ['.....', '..O..', '..O..', '.OO..', '.....']] L_SHAPE_TEMPLATE = [['.....', '...O.', '.OOO.', '.....', '.....'], ['.....', '..O..', '..O..', '..OO.', '.....'], ['.....', '.....', '.OOO.', '.O...', '.....'], ['.....', '.OO..', '..O..', '..O..', '.....']] T_SHAPE_TEMPLATE = [['.....', '..O..', '.OOO.', '.....', '.....'], ['.....', '..O..', '..OO.', '..O..', '.....'], ['.....', '.....', '.OOO.', '..O..', '.....'], ['.....', '..O..', '.OO..', '..O..', '.....']] PIECES = {'S': S_SHAPE_TEMPLATE, 'Z': Z_SHAPE_TEMPLATE, 'I': I_SHAPE_TEMPLATE, 'J': J_SHAPE_TEMPLATE, 'L': L_SHAPE_TEMPLATE, 'O': O_SHAPE_TEMPLATE, 'T': T_SHAPE_TEMPLATE} PIECES_ORDER = {'S': 0,'Z': 1,'I': 2,'J': 3,'L': 4,'O': 5,'T': 6} # snake constants # UP = 'up' DOWN = 'down' LEFT = 'left' RIGHT = 'right' HEAD = 0 # syntactic sugar: index of the worm's head # font clock # clock_font = [ 0x1F, 0x11, 0x1F, 0x00, 0x00, 0x1F, 0x1D, 0x15, 0x17, 0x15, 0x15, 0x1F, 0x07, 0x04, 0x1F, 0x17, 0x15, 0x1D, 0x1F, 0x15, 0x1D, 0x01, 0x01, 0x1F, 0x1F, 0x15, 0x1F, 0x17, 0x15, 0x1F] theTetrisFont = [ 0x78,0x78,0x1E,0x1E, #S 0x1E,0x1E,0x78,0x78, #Z 0x00,0xFF,0xFF,0x00, #I 0x06,0x06,0x7E,0x7E, #J 0x7E,0x7E,0x06,0x06, #L 0x3C,0x3C,0x3C,0x3C, #O 0x7E,0x7E,0x18,0x18, #T ] if PI: serial = spi(port=0, device=0, gpio=noop()) device = max7219(serial, cascaded=4, blocks_arranged_in_reverse_order=True) pixel_pin = board.D18 # The number of NeoPixels num_pixels = PIXEL_X*PIXEL_Y ORDER = neopixel.GRB pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=LED_BRIGHTNESS, auto_write=False,pixel_order=ORDER) # key server for controller # QKEYDOWN=0 QKEYUP=1 JKEY_X=3 JKEY_Y=4 JKEY_A=0 JKEY_B=1 JKEY_R=7 JKEY_L=6 JKEY_SEL=10 JKEY_START=11 mykeys = { K_1: JKEY_A, K_2: JKEY_B, K_3: JKEY_Y, K_4: JKEY_X, K_x: JKEY_SEL, K_s: JKEY_START } mask = bytearray([1,2,4,8,16,32,64,128]) # main # def main(): global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT global a1_counter ,RUNNING a1_counter=0 RUNNING=True joystick_detected=False joystick_cnt=0 if not PI: pygame.init() FPSCLOCK = pygame.time.Clock() DISPLAYSURF = pygame.display.set_mode((PIXEL_X*SIZE, PIXEL_Y*SIZE)) BASICFONT = pygame.font.Font('freesansbold.ttf', 18) BIGFONT = pygame.font.Font('freesansbold.ttf', 100) pygame.display.set_caption('Pi Games') DISPLAYSURF.fill(BGCOLOR) pygame.display.update() drawImage('pi.bmp') time.sleep(2) else: device.contrast(200) pygame.init() drawImage('/home/pi/pi.bmp') pygame.joystick.init() while joystick_detected==False: show_message(device,"Waiting for controller...",fill="white", font=proportional(CP437_FONT), scroll_delay=0.01) pygame.joystick.quit() pygame.joystick.init() try: joystick = pygame.joystick.Joystick(0) # create a joystick instance joystick.init() # init instance # print("Initialized joystick: {}".format(joystick.get_name())) joystick_detected = True except pygame.error: print("no joystick found.") joystick_detected = False clearScreen() drawClock(1) if PI: show_message(device,"Let's play",fill="white", font=proportional(CP437_FONT)) while True: clearScreen() #drawSymbols() if PI: drawImage('/home/pi/select.bmp') else: drawImage('select.bmp') updateScreen() if not PI: checkForQuit() #check if joystick is still connected if PI: if joystick_cnt==50: joystick_cnt=0 pygame.joystick.quit() pygame.joystick.init() try: joystick = pygame.joystick.Joystick(0) # create a joystick instance joystick.init() # init instance # print("Initialized joystick: {}".format(joystick.get_name())) joystick_detected = True except pygame.error: print("no joystick found.") joystick_detected = False else: joystick_cnt+=1 pygame.event.pump() for event in pygame.event.get(): # print("event detected {}".format(event)) if event.type == pygame.JOYBUTTONDOWN or event.type == KEYDOWN: if event.type == pygame.JOYBUTTONDOWN: myevent = event.button else: if event.key in mykeys: myevent = mykeys[event.key] else: myevent = -1 if (myevent == JKEY_B): drawClock(1) if (myevent == JKEY_A): runPongGame() if (myevent == JKEY_X): runTetrisGame() if (myevent == JKEY_Y): runSnakeGame() if (myevent == JKEY_START): shutdownScreen() if event.type == pygame.QUIT: # get all the QUIT events terminate() # terminate if any QUIT events are present time.sleep(.1) terminate() # gaming main routines # def runPongGame(): down = 0 up = 1 left = 0 right = 1 lowerbarx = PIXEL_X//2 upperbarx = PIXEL_X//2 score1 = 0 score2 = 0 ballx = PIXEL_X//2 bally = PIXEL_Y//2 directiony = down directionx = left movingRightUpper = False movingLeftUpper = False movingRightLower = False movingLeftLower = False restart=False lastLowerMoveSidewaysTime = time.time() lastUpperMoveSidewaysTime = time.time() while True: # main game loop pygame.event.pump() for event in pygame.event.get(): if event.type == pygame.JOYAXISMOTION: axis = event.axis val = round(event.value) if (axis == 0 and val == -1): movingLeftLower = True movingRightLower = False if (axis == 0 and val == 1): movingLeftLower = False movingRightLower = True if (val == 0): movingLeftLower = False movingRightLower = False if event.type == pygame.JOYBUTTONDOWN: # print("Joystick button pressed: {}".format(event.button)) if (event.button == JKEY_A): movingLeftUpper = True movingRightUpper = False if (event.button == JKEY_B): movingLeftUpper = False movingRightUpper = True if (event.button == JKEY_SEL): # quit game return if event.type == pygame.JOYBUTTONUP: movingLeftUpper = False movingRightUpper = False if event.type == pygame.KEYDOWN: if(event.key==K_LEFT): movingLeftLower = True movingRightLower = False if(event.key==K_RIGHT): movingLeftLower = False movingRightLower = True if(event.key==K_1): movingLeftUpper = True movingRightUpper = False if(event.key==K_2): movingLeftUpper = False movingRightUpper = True if(event.key==K_s): return if event.type == pygame.KEYUP: movingLeftLower = False movingRightLower = False movingLeftUpper = False movingRightUpper = False if (movingLeftLower) and time.time() - lastLowerMoveSidewaysTime > MOVESIDEWAYSFREQ: if lowerbarx >1: lowerbarx-=1; lastLowerMoveSidewaysTime = time.time() if (movingRightLower) and time.time() - lastLowerMoveSidewaysTime > MOVESIDEWAYSFREQ: if lowerbarx <PIXEL_X-2: lowerbarx+=1; lastLowerMoveSidewaysTime = time.time() if (movingLeftUpper) and time.time() - lastUpperMoveSidewaysTime > MOVESIDEWAYSFREQ: if upperbarx >1: upperbarx-=1; lastUpperMoveSidewaysTime = time.time() if (movingRightUpper) and time.time() - lastUpperMoveSidewaysTime > MOVESIDEWAYSFREQ: if upperbarx <PIXEL_X-2: upperbarx+=1; lastUpperMoveSidewaysTime = time.time() if not PI: checkForQuit() if (directiony == up): if (bally>1): bally-=1 else: if (abs(ballx-upperbarx)<2): directiony = down if (ballx==upperbarx+1): if (directionx==left): directionx=right if (ballx==upperbarx-1): if (directionx==right): directionx=left elif ((ballx-upperbarx==2) and (directionx==left)): directionx=right directiony = down elif ((ballx-upperbarx==-2) and (directionx==right)): directionx=left directiony = down else: bally-=1 score1+=1 restart = True else: if (bally<PIXEL_Y-2): bally+=1 else: if (abs(ballx-lowerbarx)<2): directiony = up if (ballx==lowerbarx+1): if (directionx==left): directionx=right if (ballx==lowerbarx-1): if (directionx==right): directionx=left elif ((ballx-lowerbarx==2) and (directionx==left)): directionx=right directiony = up elif ((ballx-lowerbarx==-2) and (directionx==right)): directionx=left directiony = up else: bally+=1 score2+=1 restart = True if (directionx == left): if (ballx>0): if (ballx==1): ballx-=1 else: ballx-=random.randint(1,2) else: directionx = right ballx+=1 if(directiony == up): if(bally>2): bally-=1 if(directiony == down): if(bally<PIXEL_Y-2): bally+=1 else: if (ballx<PIXEL_X-1): if (ballx==8): ballx+=1 else: ballx+=random.randint(1,2) else: directionx = left ballx-=random.randint(1,2) if(directiony == up): if(bally>3): bally-=random.randint(0,2) if(directiony == down): if(bally<PIXEL_Y-3): bally+=random.randint(0,2) clearScreen() drawBall(ballx,bally) drawBar(upperbarx,0) drawBar(lowerbarx,PIXEL_Y-1) twoscoreText(score1,score2) updateScreen() if (score1 == 9) or (score2 == 9): time.sleep(3) return if restart: time.sleep(1) ballx=PIXEL_X//2 bally=PIXEL_Y//2 if directiony==down: directiony = up else: directiony = down restart=False else: time.sleep(.1) def runSnakeGame(): # Set a random start point. startx = random.randint(2, BOARDWIDTH-2 ) starty = random.randint(2, BOARDHEIGHT -2 ) wormCoords = [{'x': startx, 'y': starty}, {'x': startx - 1, 'y': starty}, {'x': startx - 2, 'y': starty}] direction = RIGHT score = 0 if os.path.isfile('/home/pi/hs_snake.p')==True: try: highscore = pickle.load(open("/home/pi/hs_snake.p","rb")) except EOFError: highscore = 0 else: highscore=0 if PI: show_message(device,"Snake Highscore: " + str(highscore),fill="white", font=proportional(CP437_FONT), scroll_delay=0.01) # Start the apple in a random place. apple = getRandomLocation(wormCoords) while True: # main game loop olddirection = direction pygame.event.pump() for event in pygame.event.get(): if event.type == pygame.JOYAXISMOTION: if (olddirection== direction): #only one direction change per step axis = event.axis val = round(event.value) if (axis == 0 and val == -1): if direction != RIGHT: direction = LEFT if (axis == 0 and val == 1): if direction != LEFT: direction = RIGHT if (axis == 1 and val == 1): if direction != UP: direction = DOWN if (axis == 1 and val == -1): if direction != DOWN: direction = UP if event.type == pygame.KEYDOWN: if (event.key==K_LEFT): if direction != RIGHT: direction = LEFT if (event.key==K_RIGHT): if direction != LEFT: direction = RIGHT if (event.key==K_DOWN): if direction != UP: direction = DOWN if (event.key==K_UP): if direction != DOWN: direction = UP if (event.key == JKEY_SEL): #quit game return if event.type == pygame.JOYBUTTONDOWN: if (event.button==JKEY_SEL): # quit game return # check if the worm has hit itself or the edge if wormCoords[HEAD]['x'] == -1 or wormCoords[HEAD]['x'] == BOARDWIDTH or wormCoords[HEAD]['y'] == -1 or wormCoords[HEAD]['y'] == BOARDHEIGHT: time.sleep(1.5) if score > highscore: highscore = score if PI: pickle.dump(highscore, open("/home/pi/hs_snake.p", "wb")) show_message(device,"New Highscore !!!",fill="white", font=proportional(CP437_FONT), scroll_delay=0.01) return # game over for wormBody in wormCoords[1:]: if wormBody['x'] == wormCoords[HEAD]['x'] and wormBody['y'] == wormCoords[HEAD]['y']: time.sleep(1.5) if score > highscore: highscore = score if PI: pickle.dump(highscore, open("/home/pi/hs_snake.p", "wb")) show_message(device,"New Highscore !!!",fill="white", font=proportional(CP437_FONT), scroll_delay=0.01) return # game over # check if worm has eaten an apple if wormCoords[HEAD]['x'] == apple['x'] and wormCoords[HEAD]['y'] == apple['y']: # don't remove worm's tail segment score += 1 apple = getRandomLocation(wormCoords) # set a new apple somewhere else: del wormCoords[-1] # remove worm's tail segment # move the worm by adding a segment in the direction it is moving if direction == UP: if wormCoords[HEAD]['y'] == 0 : newHead = {'x': wormCoords[HEAD]['x'], 'y': BOARDHEIGHT-1} else: newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1} elif direction == DOWN: if wormCoords[HEAD]['y'] == BOARDHEIGHT-1 : newHead = {'x': wormCoords[HEAD]['x'], 'y': 0} else: newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1} elif direction == LEFT: if wormCoords[HEAD]['x'] == 0 : newHead = {'x': BOARDWIDTH -1, 'y': wormCoords[HEAD]['y'] } else: newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']} elif direction == RIGHT: if wormCoords[HEAD]['x'] == BOARDWIDTH-1: newHead = {'x': 0, 'y': wormCoords[HEAD]['y']} else: newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']} if not PI: checkForQuit() wormCoords.insert(0, newHead) clearScreen() drawWorm(wormCoords) drawApple(apple) scoreText(score) updateScreen() time.sleep(.15) def runTetrisGame(): # setup varia # bles for the start of the game #if PI: #device.contrast(255) #device.show() board = getBlankBoard() lastMoveDownTime = time.time() lastMoveSidewaysTime = time.time() lastFallTime = time.time() movingDown = False # note: there is no movingUp variable movingLeft = False movingRight = False score = 0 oldscore = -1 oldpiece = 10 lines = 0 level, fallFreq = calculateLevelAndFallFreq(lines) if os.path.isfile('/home/pi/hs_tetris.p')==True: try: highscore = pickle.load(open("/home/pi/hs_tetris.p","rb")) except EOFError: highscore = 0 else: highscore=0 if PI: show_message(device,"Tetris Highscore: " + str(highscore),fill="white", font=proportional(CP437_FONT), scroll_delay=0.01) fallingPiece = getNewPiece() nextPiece = getNewPiece() while True: # game loop if fallingPiece == None: # No falling piece in play, so start a new piece at the top fallingPiece = nextPiece nextPiece = getNewPiece() lastFallTime = time.time() # reset lastFallTime if not isValidPosition(board, fallingPiece): time.sleep(2) if score > highscore: highscore = score if PI: pickle.dump(highscore, open("/home/pi/hs_tetris.p", "wb")) show_message(device,"New Highscore !!!",fill="white", font=proportional(CP437_FONT), scroll_delay=0.01) return # can't fit a new piece on the board, so game over if not PI: checkForQuit() pygame.event.pump() for event in pygame.event.get(): # print("event detected {}".format(event)) if event.type == pygame.JOYAXISMOTION: axis = event.axis val = round(event.value) if (axis == 0 and val == 0): # no motion or down motion movingLeft = movingRight = False if (axis == 1 and val == 0) : movingDown = False if (axis==0 and val== -1) and isValidPosition(board, fallingPiece, adjX=-1): fallingPiece['x'] -= 1 movingLeft = True movingRight = False lastMoveSidewaysTime = time.time() if (axis == 0 and val== 1) and isValidPosition(board, fallingPiece, adjX=1): fallingPiece['x'] += 1 movingLeft = False movingRight = True lastMoveSidewaysTime = time.time() if (axis==1 and val == 1): movingDown = True if isValidPosition(board, fallingPiece, adjY=1): fallingPiece['y'] += 1 lastMoveDownTime = time.time() if (axis==1 and val == -1): fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) if not isValidPosition(board, fallingPiece): fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']]) if event.type == pygame.KEYDOWN: if (event.key==K_LEFT) and isValidPosition(board, fallingPiece, adjX=-1): fallingPiece['x'] -= 1 movingLeft = True movingRight = False lastMoveSidewaysTime = time.time() if (event.key==K_RIGHT) and isValidPosition(board, fallingPiece, adjX=1): fallingPiece['x'] += 1 movingLeft = False movingRight = True lastMoveSidewaysTime = time.time() if (event.key==K_DOWN): movingDown = True if isValidPosition(board, fallingPiece, adjY=1): fallingPiece['y'] += 1 lastMoveDownTime = time.time() if (event.key==K_UP): fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) if not isValidPosition(board, fallingPiece): fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']]) if (event.key == K_3): fallingPiece['rotation'] = (fallingPiece['rotation'] -1) % len(PIECES[fallingPiece['shape']]) if not isValidPosition(board, fallingPiece): fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) if (event.key == K_4): movingDown = False movingLeft = False movingRight = False for i in range(1, BOARDHEIGHT): if not isValidPosition(board, fallingPiece, adjY=i): break score+=i #TODO: more digits on numbercounter, more scores fallingPiece['y'] += i - 1 if event.type == pygame.KEYUP: movingDown = False movingLeft = False movingRight = False if event.type == pygame.JOYBUTTONDOWN: # print("Joystick button pressed: {}".format(event.button)) if (event.button == JKEY_A): fallingPiece['rotation'] = (fallingPiece['rotation'] -1) % len(PIECES[fallingPiece['shape']]) if not isValidPosition(board, fallingPiece): fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']]) if (event.button == JKEY_Y): movingDown = False movingLeft = False movingRight = False for i in range(1, BOARDHEIGHT): if not isValidPosition(board, fallingPiece, adjY=i): break score+=i #TODO: more digits on numbercounter, more scores fallingPiece['y'] += i - 1 # return # handle moving the piece because of user input if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ: if movingLeft and isValidPosition(board, fallingPiece, adjX=-1): fallingPiece['x'] -= 1 elif movingRight and isValidPosition(board, fallingPiece, adjX=1): fallingPiece['x'] += 1 lastMoveSidewaysTime = time.time() if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1): fallingPiece['y'] += 1 lastMoveDownTime = time.time() # let the piece fall if it is time to fall if time.time() - lastFallTime > fallFreq: # see if the piece has landed if not isValidPosition(board, fallingPiece, adjY=1): # falling piece has landed, set it on the board addToBoard(board, fallingPiece) remLine = removeCompleteLines(board) # count lines for level calculation lines += remLine # more lines, more points per line score += SCORES[remLine]*level level, fallFreq = calculateLevelAndFallFreq(lines) fallingPiece = None else: # piece did not land, just move the piece down fallingPiece['y'] += 1 lastFallTime = time.time() # drawing everything on the screen clearScreen() drawBoard(board) #scoreText(score) if score>oldscore: scoreTetris(score,level,PIECES_ORDER.get(nextPiece['shape'])) oldscore = score if oldpiece!=PIECES_ORDER.get(nextPiece['shape']): scoreTetris(score,level,PIECES_ORDER.get(nextPiece['shape'])) oldpiece=PIECES_ORDER.get(nextPiece['shape']) #drawStatus(score, level) #drawNextPiece(nextPiece) if fallingPiece != None: drawPiece(fallingPiece) updateScreen() #FPSCLOCK.tick(FPS) time.sleep(.05) def drawClock(color): joystick_cnt=0 if PI: device.clear(); device.show(); hour = time.localtime().tm_hour minute= time.localtime().tm_min second= time.localtime().tm_sec while True: pygame.event.pump() for event in pygame.event.get(): # User did something # print("event detected {}".format(event)) # Possible joystick actions: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION if event.type == pygame.JOYBUTTONDOWN or event.type == KEYDOWN: if event.type == pygame.JOYBUTTONDOWN: myevent = event.button else: if event.key in mykeys: myevent = mykeys[event.key] else: myevent = -1 # print("Joystick button pressed: {}".format(event.button)) if (myevent==JKEY_X): # print("exiting clock") clearScreen() updateScreen() return if (myevent == JKEY_A): color = color + 1 if (color > (len(COLORS) - 1)): color = 0 if event.type == pygame.QUIT: # get all the QUIT events terminate() # terminate if any QUIT events are present #check if joystick is still connected if PI: if joystick_cnt==25: joystick_cnt=0 pygame.joystick.quit() pygame.joystick.init() try: joystick = pygame.joystick.Joystick(0) # create a joystick instance joystick.init() # init instance # print("Initialized joystick: {}".format(joystick.get_name())) #joystick_detected = True except pygame.error: print("no joystick found.") #joystick_detected = False else: joystick_cnt+=1 ltime = time.localtime() hour = ltime.tm_hour minute= ltime.tm_min second= ltime.tm_sec clearScreen() drawnumber(int(hour/10),2,1,color) drawnumber(int(hour%10),6,1,color) drawnumber(int(minute/10),2,8,color) drawnumber(int(minute%10),6,8,color) drawnumber(int(second/10),2,15,color) drawnumber(int(second%10),6,15,color) updateScreen() time.sleep(.2) def shutdownScreen(): if PI: device.clear(); device.show(); drawImage('/home/pi/shutdown.bmp') show_message(device,"Press Select to shutdown!",fill="white", font=proportional(CP437_FONT), scroll_delay=0.01) else: drawImage('shutdown.bmp') while True: pygame.event.pump() for event in pygame.event.get(): # User did something # print("event detected {}".format(event)) # Possible joystick actions: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION if event.type == pygame.JOYBUTTONDOWN or event.type == KEYDOWN: if event.type == pygame.JOYBUTTONDOWN: myevent = event.button else: if event.key in mykeys: myevent = mykeys[event.key] else: myevent = -1 # print("Joystick button pressed: {}".format(event.button)) if (myevent!=JKEY_SEL): # print("exiting clock") clearScreen() updateScreen() return else: if not PI: terminate() else: clearScreen() updateScreen() show_message(device,"Shutdown...",fill="white", font=proportional(CP437_FONT), scroll_delay=0.01) subprocess.Popen(['shutdown','-h','now']) #call("sudo nohup shutdown -h now", shell=True) terminate() if event.type == pygame.QUIT: # get all the QUIT events terminate() # terminate if any QUIT events are present updateScreen() time.sleep(.2) def drawImage(filename): im = Image.open(filename) for row in range(0,BOARDHEIGHT): for col in range(0,BOARDWIDTH): r,g,b = im.getpixel((col,row)) drawPixelRgb(col,row,r,g,b) updateScreen() def drawHalfImage(filename,offset): im = Image.open(filename) if offset>10: offset = 10 for row in range(0,10): for col in range(0,10): r,g,b = im.getpixel((col,row)) drawPixelRgb(col,row+offset,r,g,b) # drawing # def clearScreen(): if PI: pixels.fill((0,0,0)) else: DISPLAYSURF.fill(BGCOLOR) def updateScreen(): if PI: pixels.show() else: pygame.display.update() def drawPixel(x,y,color): if color == BLANK: return if PI: try: if (x>=0 and y>=0 and color >=0): if x%2==1: pixels[x*PIXEL_Y+y] = COLORS[color] else: pixels[x*PIXEL_Y+(PIXEL_Y-1-y)] = COLORS[color] except: print(str(x) + ' --- ' + str(y)) else: pygame.draw.rect(DISPLAYSURF, COLORS[color], (x*SIZE+1, y*SIZE+1, SIZE-2, SIZE-2)) def drawPixelRgb(x,y,r,g,b): if PI: if (x>=0 and y>=0): if x%2==1: pixels[x*PIXEL_Y+y] = (r,g,b) else: pixels[x*PIXEL_Y+(PIXEL_Y-1-y)] = (r,g,b) else: pygame.draw.rect(DISPLAYSURF, (r,g,b), (x*SIZE+1, y*SIZE+1, SIZE-2, SIZE-2)) def drawnumber(number,offsetx,offsety,color): for x in range(0,3): for y in range(0,5): if clock_font[3*number + x]&mask[y]: drawPixel(offsetx+x,offsety+y,color) def drawnumberMAX7219(number,offsetx,offsety,draw1): for x in range(0,3): for y in range(0,5): if clock_font[3*number+2- x]&mask[y]: drawScorePixel(offsetx+x,offsety+y,1,draw1) elif clock_font[3*number+2- x]&mask[y]: drawScorePixel(offsetx+x,offsety+y,0,draw1) def drawTetrisMAX7219(piece,offsetx,offsety,draw1): for x in range(0,4): for y in range(0,8): if theTetrisFont[4*piece + x]&mask[y]: drawScorePixel(offsetx+x,offsety+y,1,draw1) elif theTetrisFont[4*piece + x]&mask[y]: drawScorePixel(offsetx+x,offsety+y,0,draw1) def drawScorePixel(x,y,on,draw): if PI: draw.point((31-x,y), fill= "white") time.sleep(.01) else: pygame.draw.rect(DISPLAYSURF, COLORS[2], (64-2*x, 410+2*y,2,2)) def makeTextObjs(text, font, color): surf = font.render(text, True, color) return surf, surf.get_rect() def scrollText(text): if PI: show_message(device,text,fill="white", font=proportional(CP437_FONT)) else: titleSurf, titleRect = makeTextObjs(str(text), BASICFONT, TEXTCOLOR) titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3) DISPLAYSURF.blit(titleSurf, titleRect) def scoreText(score): _score=score if _score>999: _score = 999 if PI: with canvas(device) as draw: for i in range(0,3): text(draw, ((3-i)*8, 0), str(_score%10), fill="white") _score //=10 else: titleSurf, titleRect = makeTextObjs(str(_score), BASICFONT, TEXTCOLOR) titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3) DISPLAYSURF.blit(titleSurf, titleRect) def scoreTetris(score,level,nextpiece): #if PI: #device.clear() _score=score if _score>999999: _score = 999999 if PI: # one point per level with canvas(device) as draw1: for i in range(0,level): drawScorePixel(i*2,7,1,draw1) # score as 6 digit value for i in range(0,6): drawnumberMAX7219(_score%10,i*4,0,draw1) _score //=10 # draw next piece drawTetrisMAX7219(nextpiece,27,0,draw1) if PI: device.show() def twoscoreText(score1,score2): _score1=score1 _score2=score2 if _score1>9: _score1 = 9 if _score2>9: _score2 = 9 if PI: with canvas(device) as draw: text(draw, (0, 0), str(_score1), fill="white") text(draw, (8, 0), ":", fill="white") text(draw, (16, 0), str(_score2), fill="white") text(draw, (24, 0), " ", fill="white") else: titleSurf, titleRect = makeTextObjs(str(_score1)+':'+str(_score2), BASICFONT, TEXTCOLOR) titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3) DISPLAYSURF.blit(titleSurf, titleRect) # program flow # def terminate(): RUNNING = False pygame.quit() exit() def checkForQuit(): for event in pygame.event.get(QUIT): # get all the QUIT events terminate() # terminate if any QUIT events are present for event in pygame.event.get(KEYUP): # get all the KEYUP events if event.key == K_ESCAPE: terminate() # terminate if the KEYUP event was for the Esc key pygame.event.post(event) # put the other KEYUP event objects back # tetris subroutines # def calculateLevelAndFallFreq(lines): # Based on the score, return the level the player is on and # how many seconds pass until a falling piece falls one space. level = int(lines / 10) + 1 # limit level to 10 if level >10: level = 10 fallFreq = FALLING_SPEED - (level * 0.05) if fallFreq <= 0.05: fallFreq = 0.05 return level, fallFreq def getNewPiece(): # return a random new piece in a random rotation and color shape = random.choice(list(PIECES.keys())) newPiece = {'shape': shape, 'rotation': random.randint(0, len(PIECES[shape]) - 1), 'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2), 'y': -2, # start it above the board (i.e. less than 0) 'color': PIECES_ORDER.get(shape)} return newPiece def addToBoard(board, piece): # fill in the board based on piece's location, shape, and rotation for x in range(TEMPLATEWIDTH): for y in range(TEMPLATEHEIGHT): if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK: board[x + piece['x']][y + piece['y']] = piece['color'] def isOnBoard(x, y): return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT def isValidPosition(board, piece, adjX=0, adjY=0): # Return True if the piece is within the board and not colliding for x in range(TEMPLATEWIDTH): for y in range(TEMPLATEHEIGHT): isAboveBoard = y + piece['y'] + adjY < 0 if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK: continue if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY): return False if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK: return False return True def isCompleteLine(board, y): # Return True if the line filled with boxes with no gaps. for x in range(BOARDWIDTH): if board[x][y] == BLANK: return False return True def removeCompleteLines(board): # Remove any completed lines on the board, move everything above them down, and return the number of complete lines. numLinesRemoved = 0 y = BOARDHEIGHT - 1 # start y at the bottom of the board while y >= 0: if isCompleteLine(board, y): # Remove the line and pull boxes down by one line. for pullDownY in range(y, 0, -1): for x in range(BOARDWIDTH): board[x][pullDownY] = board[x][pullDownY-1] # Set very top line to blank. for x in range(BOARDWIDTH): board[x][0] = BLANK numLinesRemoved += 1 # Note on the next iteration of the loop, y is the same. # This is so that if the line that was pulled down is also # complete, it will be removed. else: y -= 1 # move on to check next row up return numLinesRemoved def drawBoard(matrix): for i in range(0,BOARDWIDTH): for j in range(0,BOARDHEIGHT): drawPixel(i,j,matrix[i][j]) def getBlankBoard(): # create and return a new blank board data structure board = [] for i in range(BOARDWIDTH): board.append([BLANK] * BOARDHEIGHT) return board def drawPiece(piece, pixelx=None, pixely=None): shapeToDraw = PIECES[piece['shape']][piece['rotation']] if pixelx == None and pixely == None: # if pixelx & pixely hasn't been specified, use the location stored in the piece data structure pixelx=piece['x'] pixely=piece['y'] # draw each of the boxes that make up the piece for x in range(TEMPLATEWIDTH): for y in range(TEMPLATEHEIGHT): if shapeToDraw[y][x] != BLANK: drawPixel( pixelx+ x , pixely+y,piece['color']) # snake subroutines # def getRandomLocation(wormCoords): while True: x = random.randint(0, BOARDWIDTH - 1) y = random.randint(0, BOARDHEIGHT - 1) if {'x': x, 'y': y} in wormCoords: print('no apples on worm') else: break return {'x': x, 'y': y} def drawWorm(wormCoords): for coord in wormCoords: x = coord['x'] y = coord['y'] drawPixel(x,y,1) def drawApple(coord): x = coord['x'] y = coord['y'] drawPixel(x,y,2) # pong subroutines # def drawBar(x,y): drawPixel(x-1,y,1) drawPixel(x,y,1) drawPixel(x+1,y,1) def drawBall(x,y): drawPixel(x,y,0) if __name__ == '__main__': main()