SenseHat でIMUを使ったゲーム


今度のsense hatゲームは、IMU(慣性測定ユニット)を試してみました。

本体を傾けると、赤いピクセルが動きます。これで緑のピクセルをすべて取るとクリア。最右列の青いピクセルは、時間制限です。

ただ今回苦労したのは、IMUではなく、同時に初めて使ったPythonのスレッドです。
IMUの方は、ジョイスティックと同様、結構簡単でした。

メインループと並行して時間制限をカウントするスレッドを動かしてみましたが、相互の制御(ゲームクリアならスレッドを停止し、タイムオーバーしたらメインループを停止)の方法が分かりませんでした。
threading.Event()による制御を知り、解決できました。


from sense_hat import SenseHat, ACTION_PRESSED, ACTION_HELD, ACTION_RELEASED
from time import sleep
from random import randint
from copy import copy
import threading

sense = SenseHat()
sense.clear()

red = (255, 0, 0)
blue = (0, 0, 255)
yellow=(255,255,0)
purple=(128,0,128)
green=(0,255,0)
indigg=(75,0,130)
orange=(255,128,0)
black=[0,0,0]

sense.set_rotation(0)

ncol = 8
nrow = 8
col_max = ncol - 2
row_max = nrow - 1

event = threading.Event()

def setdisturbs(num_disturbs, initpos):
    disturbs = list()
    for i in range(0,num_disturbs):
        while True:
            candi = (randint(0, col_max), randint(0, row_max))
            if candi == initpos:
                continue

            duplicated = False
            for j in disturbs:
                if candi == j:
                    duplicated = True
                    break
            if duplicated:
                continue
            disturbs.append(candi)
            break

    color_disturb = green
    for i in disturbs:
        sense.set_pixel(i[0], i[1], color_disturb)

def timecount(interval):
    col = ncol - 1
    for row in range(row_max):
        sense.set_pixel(col, row, blue)
        if event.wait(interval):
            break
    event.set()

speed = 0.2
num_disturbs = 10
interval = 3

ballpos = (ncol/2, nrow/2)
sense.set_pixel(ballpos[0], ballpos[1], red)
ballvec = (0, 0)

setdisturbs(num_disturbs, ballpos)

t1 = threading.Thread(target=timecount, args=(interval,))
t1.start()

success = False
while True:
    if event.is_set():
        break

    acceleration = sense.get_accelerometer_raw()
    x = acceleration['x']
    y = acceleration['y']
    z = acceleration['z']

    x=int(round(x, 0))
    y=int(round(y, 0))
    z=int(round(z, 0))

    #print("x={0}, y={1}, z={2}".format(x, y, z))

    ballvec = (x, y)
    # if x  == -1: #left
    #   ballvec = (-1, 0)
    # elif y == -1: #top
    #   ballvec = (0, -1)
    # elif x == 1: #right
    #   ballvec = (1, 0)
    # elif y == 1: #bottom
    #   ballvec = (0, 1)
    # else:
    #   ballvec = (0, 0)

    sense.set_pixel(ballpos[0], ballpos[1], black)
    ballpos = (max(min(ballpos[0] + ballvec[0], col_max), 0), max(min(ballpos[1] + ballvec[1], row_max), 0))
    sense.set_pixel(ballpos[0], ballpos[1], red)

    #print("col={0}, row={1}".format(ballpos[0], ballpos[1]))
    num_colorpx = 0
    cur_px = sense.get_pixels()
    for px in cur_px:
        if px == [0,252,0]: # green
            num_colorpx = num_colorpx + 1
    if num_colorpx == 0:
        event.set()
        success = True
        break

    sleep(speed)

if success:
    sense.show_letter("O")
else:
    sense.show_letter("X")

sleep(2)
sense.clear()