2026寒假练 - 用RP2040游戏机设计重力迷宫滚球小游戏
该项目使用了RP2040游戏机,实现了重力迷宫滚球小游戏的设计,它的主要功能为:使用姿态传感器(IMU)俯仰和横滚控制小球在迷宫中移动。
标签
嵌入式系统
显示
符煜晨
更新2026-03-27
北京理工大学
21

一、项目介绍

本项目基于树莓派RP2040的嵌入式系统学习平台,用MicroPython编程开发完成的重力迷宫滚球游戏。项目将硬件传感器与屏幕显示相结合,玩家通过在物理空间中倾斜开发板,利用重力感应来控制屏幕内小球的移动,最终走出迷宫。游戏有3关固定迷宫,按键实现开始、暂停与关卡切换,使用姿态传感器俯仰和横滚控制小球在迷宫中移动,蜂鸣器提示碰壁与通关,LCD屏幕实时显示计时与得分。

二、硬件介绍

1.RP2040微控制器

核心控制器,负责读取传感器数据、控制显示屏幕及实现游戏逻辑。主频最高可达133MHz,采用双核Arm Cortex M0+内核,内置264KB SRAM,具备丰富的GPIO接口,支持高性能的可编程IO(PIO),满足高速数字接口需求。提供12位精度的高采样率ADC,支持4路外部模拟信号采集,支持MicroPython、C、C++ 等多种编程环境。

2.240×240彩色IPS LCD 显示屏(ST7789 控制器)

采用SPI通信接口,驱动芯片为ST7789。支持完整的240×240分辨率,IPS屏带来较广的可视角度和明亮显示效果。实现多色彩图形绘制,为游戏界面提供直观、人性化的交互体验。

3.三轴姿态传感器MMA7660FC

小巧的运动检测传感器,采用I2C总线与主控连接,实时监测三轴加速度,捕获设备姿态倾斜和震动信息,用于游戏中物理倾斜控制,实现基于重力感应的交互体验。

4. 四向摇杆(FJ08K-N)及轻触按键

输入设备采集玩家的手动控制指令,辅助重力传感器实现多维度交互。四向模拟电位计摇杆,提供多轴模拟输入信号,2个轻触按键用于菜单选择或功能控制。

5. 外扩存储器

2MB 容量 SPI Flash 闪存(型号:P25Q16H-SSH-IT),存储程序固件及数据,支持MicroPython运行时环境。

三、方案框图和项目设计思路

1.方案框图

image.png

2.项目设计思路

1)数据采集与硬件驱动

姿态感知:通过I2C总线调用mma7660.py驱动,实时读取MMA7660三轴加速度计的X轴和Y轴原始数据。

数据映射:将读取到的倾斜角度(加速度值)转化为屏幕中小球在X/Y轴上的移动速度和方向。

2)游戏物理引擎与状态管理

运动学模拟:根据传感器传来的速度变量,实时更新小球在屏幕坐标系中的(x, y)位置。

碰撞检测:在小球坐标更新前,程序会判断下一步即将到达的位置是否与迷宫墙壁重合。如果碰到墙壁,则将该方向的速度归零,阻止小球穿墙。

游戏状态机:管理游戏的各个阶段,包括初始化生成迷宫,游戏进行计时计分,到达终点,重新开始。

3)图形渲染与刷新

屏幕驱动:通过SPI总线调用st7789.py驱动,控制TFT彩屏。

UI与字体:调用vga2.py提供的高效点阵字体,在屏幕边缘显示游戏时间、得分等HUD信息。

局部刷新优化:为了保证游戏画面的流畅度,不采用每次全屏清空重绘的方式,而是采用局部刷新,只用背景色覆盖小球上一帧的位置,然后在新的位置画出小球,避免屏幕闪烁。

四、软件流程图和关键代码介绍

1.软件流程图

本项目采用MicroPython作为主要编程语言,语法简洁,开发效率高,调试环境采用Thonny IDE,调试和测试嵌入式程序,提高开发效率,减少调试难度。

image.png

2.关键代码介绍

1)主程序游戏核心逻辑(p05_maze_game.py)

p05_maze_game.py文件是重力迷宫游戏的主程序,负责初始化硬件(LCD、IMU、按键、蜂鸣器),运行三关迷宫IMU倾斜控制小球移动碰墙提示、通关提示显示时间、得分、状态。

a.传感器数据采集与处理

此函数负责通过I2C接口从MMA7660加速度传感器获取三轴原始数据,转换为带符号的加速度值,最终将设备的物理倾斜角映射为游戏内的左右、上下速度增量,供后续物理计算使用。

def read_tilt(self):
# Read accel raw, convert to signed -32..31
self.acc.getSample(self.acc_buf)
ax = twos_compliment_6bit(self.acc_buf[0])
ay = twos_compliment_6bit(self.acc_buf[1])
az = twos_compliment_6bit(self.acc_buf[2])

# Final mapping (after your feedback):
# left/right from ay, up/down from ax
gx = ay / 16.0
gy = -ax / 16.0
return gx, gy, az

b.游戏物理逻辑与碰撞检测

本函数实现根据传感器输入调整球速,更新球的新位置,结合游戏地图进行碰撞检测,碰壁时反弹减速,撞击声音提示;同时检测是否到达目标点完成游戏。

def collide_and_move(self):
if not self.running or self.win:
return

gx, gy, _ = self.read_tilt()

# Integrate (faster)
self.vx = clamp(self.vx + gx * ACC_SCALE, -MAX_V, MAX_V)
self.vy = clamp(self.vy + gy * ACC_SCALE, -MAX_V, MAX_V)
self.vx *= FRICTION
self.vy *= FRICTION

nx = self.ball_x + self.vx
ny = self.ball_y + self.vy

nx = clamp(nx, BALL_R, W - BALL_R)
ny = clamp(ny, BALL_R, H - BALL_R)

bumped = False

# X axis collision
if self.hit_wall(nx, self.ball_y):
self.vx = -self.vx * 0.30
nx = self.ball_x
bumped = True

# Y axis collision
if self.hit_wall(self.ball_x, ny):
self.vy = -self.vy * 0.30
ny = self.ball_y
bumped = True

if bumped:
self.bump_count += 1
self.oops_until = time.ticks_add(time.ticks_ms(), OOPS_MS)
beep(self.buzz, 2000, 35)

self.ball_x = nx
self.ball_y = ny

# Goal check
cx, cy = self.cell_at(self.ball_x, self.ball_y)
if self.is_goal_cell(cx, cy):
self.win = True
self.running = False
beep(self.buzz, 1200, 80)
time.sleep_ms(40)
beep(self.buzz, 1600, 120)

c.字体定义和显示

font文件库定义8x8点阵字体数据,用二进制(字节列表)存储所有字符的点阵图形,游戏中通过该字库渲染文字信息(时间、分数、提示文字)至LCD屏幕,简约、高效。

def draw_hud(self):
self.tft.fill_rect(0, 0, W, HUD_H, C_HUD_BG)
self.update_time_score()

sec = self.elapsed_ms // 1000
mm = sec // 60
ss = sec % 60

tstr = "%02d:%02d" % (mm, ss)
lstr = "L%d" % (self.level_idx + 1)
sstr = "S%05d" % self.score
state = "RUN" if self.running else ("WIN" if self.win else "PAUSE")

self.tft.text(font, lstr, 2, 8, C_TEXT, C_HUD_BG)
self.tft.text(font, state, 38, 8, (C_GOAL if self.win else C_TEXT), C_HUD_BG)
self.tft.text(font, tstr, 98, 8, st7789.WHITE, C_HUD_BG)
self.tft.text(font, sstr, 160, 8, st7789.YELLOW, C_HUD_BG)

# Oops message
if time.ticks_diff(self.oops_until, time.ticks_ms()) > 0:
self.tft.text(font, "Oops!", 106, 0, st7789.RED, C_HUD_BG)

if self.win:
self.tft.text(font, "A:Next", 2, HUD_H - 8, st7789.GREEN, C_HUD_BG)
self.tft.text(font, "B:Restart", 70, HUD_H - 8, st7789.GREEN, C_HUD_BG)

d.屏幕绘制与画面刷新

通过“擦除上一位置的球体像素”和“重绘新位置的球体”,实现局部刷新,避免全屏刷新带来的闪烁与性能开销,提高屏幕绘制效率和游戏流畅度。

def draw_ball(self):
x0 = int(self.ball_x)
y0 = int(self.ball_y)
r = BALL_R
for dy in range(-r, r + 1):
y = y0 + dy
if y < 0 or y >= H:
continue
dx_max = int((r * r - dy * dy) ** 0.5)
x1 = clamp(x0 - dx_max, 0, W - 1)
x2 = clamp(x0 + dx_max, 0, W - 1)
self.tft.fill_rect(x1, y, x2 - x1 + 1, 1, C_BALL)

def erase_ball(self, prev_x, prev_y):
r = BALL_R + 1
x1 = clamp(int(prev_x) - r, 0, W - 1)
y1 = clamp(int(prev_y) - r, 0, H - 1)
x2 = clamp(int(prev_x) + r, 0, W - 1)
y2 = clamp(int(prev_y) + r, 0, H - 1)

for py in range(y1, y2 + 1):
cy = py // CELL
row = self.map[cy]
for px in range(x1, x2 + 1):
cx = px // CELL
ch = row[cx]
color = C_BG
if ch == "#":
color = C_WALL
elif ch == "G":
color = C_GOAL
self.tft.pixel(px, py, color)

e.游戏状态管理与主循环

游戏主循环持续读取按键输入,更新球的物理状态及位置,重新绘制球体,并定期刷新状态HUD。通过控制循环休眠,实现合适的帧率和响应速度,保证游戏交互流畅。

def step(self):
self.handle_buttons()

prev_x, prev_y = self.ball_x, self.ball_y
self.collide_and_move()

self.erase_ball(prev_x, prev_y)
self.draw_ball()
def main():
g = Game()
last_hud = time.ticks_ms()

while True:
g.step()

now = time.ticks_ms()
if time.ticks_diff(now, last_hud) > 150:
g.draw_hud()
last_hud = now

time.sleep_ms(20)

main()

2三轴加速度传感器驱动(mma7660.py)

a.实现MMA7660三轴加速度传感器的初始化与读数操作,驱动初始化里的I2C扫描及寄存器配置过程,保证传感器可用,通过I2C协议读取X、Y、Z三个轴的加速度原始数据。

def __init__(self, i2c):
self.i2c = i2c
devices = self.i2c.scan() # get devices on I2C bus

self.address = None
for dev in devices:
print("Found Device(s):" + str(dev))
if dev == 0x4c:
self.address = dev

if self.address == None:
raise RuntimeError("No MMA7660 accelerometer found on I2C bus 1")

self.buf = bytearray(1) # 1-byte buffer for I2C communications
self.on(False) # Put it in standby mode

b.传感器从寄存器获得原始数据,并进行位掩码处理。提供开关机模式切换,便于节能和配置寄存器。是游戏中获取实时倾斜角度的底层数据保障。

def getSample(self, data):
self.i2c.readfrom_mem_into(self.address, MMA7660.X_REG, data) # read sample
for i in range(3):
data[i] &= 0x3F

3) st7789.py(LCD驱动)

实现ST7789驱动芯片的SPI数据通讯与命令控制。提供基础的图形绘制接口,如填充矩形、绘制圆形,小球及迷宫墙壁绘制都调用这些方法。负责屏幕的初始化与显示区域设置。通过SPI高速与LCD通信,保证游戏流畅画面显示。

 def __init__(self, spi, width, height, reset, dc, cs=None, backlight=None,
xstart=-1, ystart=-1, rotation=0):
"""
Initialize display.
"""
if (width, height) != (240, 240) and (width, height) != (135, 240):
raise ValueError(
"Unsupported display. Only 240x240 and 135x240 are supported."
)

self._display_width = self.width = width
self._display_height = self.height = height
self.spi = spi
self.reset = reset
self.dc = dc
self.cs = cs
self.backlight = backlight
self._rotation = rotation % 4
        self.set_window(x, y, x + width - 1, y + height - 1)
chunks, rest = divmod(width * height, _BUFFER_SIZE)
pixel = _encode_pixel(color)
self.dc.on()
if chunks:
data = pixel * _BUFFER_SIZE
for _ in range(chunks):
self.write(None, data)
if rest:
self.write(None, pixel * rest)

五、功能展示图及说明

1:第一关迷宫。

image.png

2:游戏进行中,文字栏状态由PAUSE变为RUN,实时计时和计分。

image.png

3:碰壁提醒,蜂鸣器提示,文字栏显示红色“Oops!”字样。

image.png

4:第二关迷宫。

image.png

5:第三关迷宫。

image.png

6:第三关通关,文字栏状态变为WIN,显示最终通关用时和得分,出现“A:Next B:Restart”字样,指示玩家重新游戏或进入下一关。

image.png

六、遇到的难题及解决方法

1.加速度传感器数据解读的准确性问题:初期从MMA7660姿态传感器读取的加速度数据频繁出现波动和噪声,导致游戏中的小球运动不流畅甚至跳跃过大,影响用户体验。

解决方法:引入了6位二进制补码转换函数,正确解析传感器输出的有符号数值,避免误解读数据。通过调节加速度系数ACC_SCALE和摩擦系数FRICTION,减少抖动,提升控制手感。调试确定合适的速度最大值MAX_V和碰撞检测半径COLLIDE_R,避免频繁误触碰撞。

2.碰撞检测算法实现复杂:起初使用简单点位检测导致球体穿墙或判定过于严格,影响游戏体验。

解决方法:采用多点临近检测法,在球体方位周围四个点进行墙壁检测,结合合适的缩小碰撞半径,使碰撞逻辑更宽松合理。对碰撞后速度进行了反弹与衰减处理,确保球不会卡死或反复弹跳。

3.局部刷新与绘图效率问题:LCD屏幕刷新时如果使用全屏擦除,画面闪烁严重且更新延迟造成输入响应滞后。

解决方法:实现局部绘制策略,仅擦除并重绘小球周围区域,避免不必要的全屏刷新。优化绘制函数,合理利用填充矩形与像素绘制,保证屏幕更新效率,提升视觉平滑度和响应速度。

七、项目心得与体会

通过这次项目,我学习了RP2040开发板及相关传感器和显示设备的驱动方法,了解了编写嵌入式实时游戏应用的方法。本次项目涉及传感器数据采集、图形驱动与显示、用户输入处理、多任务调度等环节,让我对嵌入式系统的整体架构与工作流程有了更加系统和全面的认识。

项目过程中遇到的问题,如加速度传感器数据的稳定性和映射、碰撞检测的准确实现及高效刷新技术,在不断的尝试和调试中得到解决,锻炼了我的问题分析与解决能力,增强了我的动手实践能力。

希望未来能继续深入学习更复杂的嵌入式系统设计与优化技巧,打造更加丰富和人性化的智能应用。

附件下载
mma7660.py
姿态传感器控制代码文件
st7789.py
显示屏控制代码文件
fonts.zip
字体代码文件
p05_maze_game.py
主程序代码文件
团队介绍
符煜晨,电子信息工程专业在校生
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号