IT_Study/Personal Project

Raspberry Pi와 SenseHat을 활용한 자이로스코프 게임 만들기

__Vivacé__ 2023. 4. 19. 17:40

Raspberry Pi 위에 SenseHat을 연결하여, 8x8 maze game을 생성

초기 화면 구성

 

기능

0. 게임 시작 시, 디스플레이 초기화를 통해 초기 화면 구성을 보여줌

1. 자이로스코프 계산을 통해, 기울일 때마다 기울이는 방향으로 S가 이동

2. 조이스틱을 클릭할 때마다, S지점부터 E지점까지 도착하는 경로 출력
    - 처음 최단경로를 노란색으로 표시, 연속해서 누를 시 다음 최단경로를 나타냄
    - 모든 경로를 표시했을 때 클릭하면, 처음 최단경로를 나타냄

3. E 지점에 도착 시, 게임이 종료되며 "WINNER" 메세지 출력 후 디스플레이 OFF

 

 


라이브러리 및 변수 선언

from sense_hat import SenseHat
from time import sleep
from collections import deque
from copy import deepcopy
import sys

dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]

sense = SenseHat() # 디스플레이 객체 가져오기

S = [0, 255, 0] # 시작 지점은 Green
E = [0, 0, 255] # 도착 지점은 Blue
RC = [100, 100, 0] # 경로는 Yellow
X = [255, 255, 255] # 벽은 White
O = [0, 0, 0]

R = 8 # Row 크기
C = 8 # Column 크기

flag = -1 # DFS 시작 및 최단경로 저장 idx

cur_x, cur_y = 0, 0 # 현재 지점 표시 - 나중에 초기화
s_y, s_x = 0, 2 # 시작 지점
e_y, e_x = 6, 7 # 도착 지점

visit = [] # BFS 방문 경로
route = [] # BFS 탐색 시 경로 저장
result = [] # 최단 거리를 저장할 경로

maze = [
O, X, O, O, O, O, O, O,
O, X, X, X, X, O, X, O,
O, O, O, O, O, O, O, O,
O, X, X, X, X, O, X, O,
O, O, X, O, O, O, X, O,
O, O, X, O, X, X, X, O,
O, X, X, O, O, O, O, O,
O, O, O, O, X, X, X, X
] # 8x8 LED 초기화

 

초기화 함수

def init():
    global cur_x, cur_y
   
    # 현재 지점을 시작 지점으로 초기화
    cur_x = s_x
    cur_y = s_y
   
    # 8x8 LED판 초기화
    sense.clear()
    sleep(1)
    
    # maze 정보대로 LED 판을 초기화
    for y in range(R):
        for x in range(C):
            sense.set_pixel(x, y, maze[R*y+x])
    
    # 시작 지점과 도착 지점 표시
    maze[R*s_y + s_x] = S
    maze[R*e_y + e_x] = E
    sense.set_pixel(s_x, s_y, S)
    sense.set_pixel(e_x, e_y, E)

 

자이로스코프 값에 따른 움직임 기능 구현

# 자이로스코프 값에 따라, 어느 좌표로 움직일 지 결정
def move(num):
    if num == 1:
        t_x = cur_x - 1
        t_y = cur_y
        check(t_x, t_y)
   
    elif num == 2:
        t_x = cur_x + 1
        t_y = cur_y
        check(t_x, t_y)

    elif num == 3:
        t_x = cur_x
        t_y = cur_y + 1
        check(t_x, t_y)
   
    elif num == 4:
        t_x = cur_x
        t_y = cur_y - 1
        check(t_x, t_y)

# 해당 좌표로 움직여도 되는 지를 판단 및 움직임 구현
def check(j, i):
    global cur_x, cur_y, flag
   
    if maze[i*R + j] == E: # 도착 지점 도달 시
        sense.clear()
        sleep(1)
        sense.show_message("WINNER") # 이겼을 시, 메세지 출력
        sys.exit()
        return
    elif (maze[i*R + j] == X) or (0 > i or 0 > j or C <= i or R <= j): # 가면 안 되는 곳
        print('Cannot move to there.')
    else: # 일반적인 움직임
        sense.set_pixel(cur_x, cur_y, O)
        sense.set_pixel(j, i, S)
        cur_x = j
        cur_y = i
        flag = -1

 

조이스틱 클릭 시 경로 탐색 및 디스플레이 표현

# 경로 탐색 알고리즘
def go_BFS(x, y):
    if x == e_y and y == e_x:
       
        temp = deepcopy(route)
        result.append((len(temp), temp))
        return
   
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
       
        if (nx < 0 or ny < 0 or nx >= R or ny >= C): continue
        if maze[nx*R + ny] == X: continue
        if visit[nx][ny] == 1: continue
       
       
        visit[nx][ny] = 1
        route.append([nx, ny])
        go_BFS(nx, ny)
        route.pop()
        visit[nx][ny] = 0
        
# 선택된 경로를 LED 판에 나타냄
def light():
    global flag
   
    target = result[flag][1]
   
    for i in range(len(target)-1):
        y, x = target[i]
        sense.set_pixel(x, y, RC)
       
    sleep(1)

    for i in range(len(target)-1):
        y, x = target[i]
        sense.set_pixel(x, y, O)
   
    flag = (flag + 1) % len(result)
   
    return;

 

이벤트 대기 구현

# Polling 방식을 활용한 구현
while True:
    for event in sense.stick.get_events(): # 이벤트 발생 시 체크
        if (event.action == 'pressed' and event.direction == 'middle'):
            if flag == -1: # 현재 위치가 업데이트가 되었을 경우, 경로 탐색
                flag = 0
                result = []
                visit = [[0 for i in range(R)] for j in range(C)]
                visit[cur_y][cur_x] = 1
                route = []
                go_BFS(cur_y, cur_x)
                result.sort()
                light()
            else: # 현재 위치 비 업데이트 시, 최단 거리 순 경로 표시
                light()
           
    ori = sense.get_orientation_degrees() # SenseHat 자이로스코프 측정 값 가져오기
    if 20 < ori["pitch"] < 100:
        move(1)
    elif 260 < ori["pitch"] < 340:
        move(2)
    elif 20 < ori["roll"] < 100:
        move(3)
    elif 260 < ori["roll"] < 340:
        move(4)
       
    sleep(0.3)

 

시연 영상