2026寒假练 - 基于树莓派RP2040游戏机实现重力迷宫滚球小游戏
该项目使用了树莓派RP2040游戏机,实现了重力迷宫滚球小游戏的设计,它的主要功能为:玩家通过倾斜游戏机来控制小球在迷宫中移动,目标是在规定时间内到达终点,同时避开墙壁以获得更高分数。项目集成了姿态传感器、LCD显示、按键输入和蜂鸣器输出等功能,提供了完整的游戏体验。
标签
Arduino
游戏机
SPI
蜂鸣器
树莓派RP2040
寒假练
LCD屏幕
重力迷宫
鲜de芒果
更新2026-03-24
35

一、项目介绍

本项目基于树莓派RP2040开发板,实现了一款重力感应控制的迷宫滚球小游戏。玩家通过倾斜游戏机来控制小球在迷宫中移动,目标是在规定时间内到达终点,同时避开墙壁以获得更高分数。项目集成了姿态传感器、LCD显示、按键输入和蜂鸣器输出等功能,提供了完整的游戏体验。


1.1 硬件介绍

本项目使用的硬件组件包括:

组件名称

型号/规格

功能描述

主控芯片

树莓派RP2040

负责游戏逻辑处理和硬件控制

显示屏幕

240x240 LCD

显示游戏界面、迷宫、小球和游戏信息

姿态传感器

MMA7660

检测设备倾斜角度,控制小球移动

按键

4个物理按键

实现开始、暂停、重开与关卡切换功能

蜂鸣器

压电蜂鸣器

提供碰撞和通关的声音提示

存储

板载Flash

存储迷宫地图数据

硬件连接关系:

  • LCD屏幕通过SPI接口连接到RP2040
  • MMA7660姿态传感器通过I2C接口连接
  • 按键直接连接到RP2040的GPIO引脚
  • 蜂鸣器连接到RP2040的PWM输出引脚
    • USB Type C连接器用于供电、程序下载


1.2 功能概览

本项目实现了以下功能:

  1. 重力感应控制:使用MMA7660姿态传感器检测设备倾斜角度,控制小球在迷宫中移动
  2. 多关卡迷宫:设计了5个不同难度的固定迷宫,每个迷宫有独立的起点和终点
  3. 游戏状态管理:包含启动界面、游戏菜单、游戏中、暂停、关卡完成和游戏结束等状态
  4. 计时与得分系统:每关限时60秒,根据完成时间和碰撞次数计算得分
  5. 碰撞检测:检测小球与墙壁的碰撞,增加惩罚时间并播放碰撞音效
  6. 声音提示:碰撞和通关时播放不同的音效
  7. 迷宫数据存储:支持将迷宫数据保存到Flash和从Flash加载
  8. 按键控制:通过按键实现开始、暂停、重开、关卡切换等操作


1.3 设计思路

  1. 模块化设计:将游戏功能分解为多个独立模块,如硬件初始化、迷宫绘制、小球控制、碰撞检测、输入处理等
  2. 状态机管理:使用状态机模式管理游戏流程,清晰地处理不同游戏状态之间的转换
  3. 数据结构设计:使用结构体存储关卡信息,包括起点、终点和迷宫地图
  4. 传感器数据处理:对MMA7660传感器数据进行校准和处理,实现平滑的小球控制
  5. 碰撞检测算法:基于网格的碰撞检测,准确判断小球是否与墙壁碰撞
  6. 得分计算逻辑:根据完成时间和碰撞惩罚计算关卡得分,并累加总分


二、功能实现

2.1 软件流程图


2.2 实现过程

1. 硬件初始化

void initializeHardware() {
// 初始化串口
Serial.begin(115200);

// 初始化I2C总线(用于MMA7660)
i2c.begin();

// 初始化MMA7660
accelemeter.begin();
accelemeter.setMode(MMA7660::MODE_ACTIVE);

// 初始化LCD
tft.init();
tft.setRotation(LCD_ROTATION);
tft.fillScreen(TFT_BLACK);

// 初始化按键引脚
pinMode(BUTTON_A, INPUT_PULLUP);
pinMode(BUTTON_B, INPUT_PULLUP);
pinMode(BUTTON_START, INPUT_PULLUP);
pinMode(BUTTON_MENU, INPUT_PULLUP);

// 初始化蜂鸣器引脚
pinMode(BUZZER_PIN, OUTPUT);

// 初始化摇杆引脚
pinMode(JOYSTICK_X, INPUT);
pinMode(JOYSTICK_Y, INPUT);
}


2. 迷宫数据结构

typedef struct {
uint8_t startX;
uint8_t startY;
uint8_t goalX;
uint8_t goalY;
uint8_t maze[MAZE_SIZE][MAZE_SIZE];
} LevelInfo;

LevelInfo levels[MAX_LEVELS] = {
{
.startX = 1,
.startY = 1,
.goalX = 18,
.goalY = 17,
.maze = {
// 迷宫数据...
}
},
// 更多关卡...
};


3. 小球控制与碰撞检测

void updateBallPosition() {
float accelX = 0, accelY = 0;

// 读取IMU数据
if (imuEnabled) {
float x, y, z;
accelemeter.getAcceleration(&x, &y, &z);

// 对调X和Y轴数据,并将X轴反向
accelX = y;
accelY = -x;

// 应用校准偏移值
accelX -= accelXOffset;
accelY -= accelYOffset;

// 加速度阈值和档位设置
// ...

// 计算速度增益
// ...

// 方向优先级逻辑
// ...

// 更新速度
ballSpeedX += accelX * gainX;
ballSpeedY += accelY * gainY;
}

// 速度限制
// ...

// 摩擦力
ballSpeedX *= 0.95;
ballSpeedY *= 0.95;

// 更新位置
ballX += ballSpeedX;
ballY += ballSpeedY;

// 边界检查
// ...

// 清除旧球位置并绘制新位置
// ...
}

void checkCollision() {
// 计算迷宫参数
// ...

int cellX = (ballX - mazeStartX) / cellSize;
int cellY = (ballY - mazeStartY) / cellSize;

// 检查墙壁碰撞
if (levels[currentLevel].maze[cellY][cellX] == 1) {
// 增加惩罚时间
penaltyTime += PENALTY_TIME * 1000;

// 播放碰撞音效
playCollisionSound();
}

// 检查终点
if (cellX == levels[currentLevel].goalX && cellY == levels[currentLevel].goalY) {
gameState = STATE_LEVEL_COMPLETE;
}
}


4. 得分系统

void nextLevel() {
// 计算得分
unsigned long totalTime = millis() - startTime + penaltyTime;
levelScore = 1000 - (int)(totalTime / 100);
if (levelScore < 0) levelScore = 0;
totalScore += levelScore;

// 播放胜利音效
playVictorySound();

// 检查是否通关所有关卡
if (currentLevel < MAX_LEVELS - 1) {
// 进入下一关
loadMaze(currentLevel + 1);
gameState = STATE_PLAYING;
} else {
// 游戏结束
gameState = STATE_GAME_OVER;
}
}


5. 游戏状态管理

void loop() {
switch (gameState) {
case STATE_INIT:
// 启动界面
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(2);
tft.setCursor(60, 70);
tft.println("Gravity Maze");
tft.setTextSize(1);
tft.setCursor(70, 120);
tft.println("Press A to start");
tft.setCursor(65, 140);
tft.println("Press Menu to set");

// 检测按键
bool aState = digitalRead(BUTTON_A) == LOW;
bool menuState = digitalRead(BUTTON_MENU) == LOW;
delay(BUTTON_DEBOUNCE);

if (aState || menuState) {
gameState = STATE_MENU;
}
break;

case STATE_MENU:
drawMenu();
handleMenuInput();
break;

case STATE_PLAYING:
updateBallPosition();
checkCollision();
handleInput();
updateDisplay();
break;

case STATE_PAUSED:
tft.setCursor(80, 110);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(2);
tft.print("Paused");
handleInput();
break;

case STATE_LEVEL_COMPLETE:
nextLevel();
break;

case STATE_GAME_OVER:
gameOver();
break;
}
}


6. 迷宫数据存储

void saveMazesToFlash() {
// 准备数据
MazeData data;
data.version = FLASH_VERSION;
memcpy(data.levels, levels, sizeof(levels));

// 擦除Flash
flashIap.erase(FLASH_MAZE_START, 4096);

// 写入数据
flashIap.program((const uint8_t*)&data, FLASH_MAZE_START, sizeof(data));
}

void loadMazesFromFlash() {
// 从Flash读取数据
MazeData data;
flashIap.read((uint8_t*)&data, FLASH_MAZE_START, sizeof(data));

// 检查版本
if (data.version == FLASH_VERSION) {
memcpy(levels, data.levels, sizeof(levels));
}
}


三、功能展示

启动界面

游戏启动后显示启动界面,包含游戏标题"Gravity Maze"和操作提示"Press A to start"、"Press Menu to set"。


游戏界面

游戏界面显示当前关卡、迷宫地图、小球位置、剩余时间等信息。迷宫使用蓝色线条绘制墙壁,红色标记起点,黄色标记终点。


游戏操作

  • A键:开始游戏/暂停游戏
  • B键:返回启动界面
  • Start键:同A键功能,长按切换IMU状态
  • Menu键:打开/关闭菜单
  • A+B长按:重开本关
  • Start+Menu长按:软重启


游戏流程

  1. 启动游戏,进入启动界面
  2. 按A键进入菜单,选择关卡
  3. 进入游戏,通过倾斜设备控制小球移动
  4. 避开墙壁,尽快到达终点
  5. 完成当前关卡后,自动进入下一关
  6. 完成所有关卡后,显示总分并返回启动界面


四、总结

遇到的问题

  1. 传感器噪声:初期姿态数据抖动明显,通过互补滤波和适当降低灵敏度得以改善。
  2. 使用的是 TFT_eSPI 绘制的地图,导致小球在移动过程中会擦除一点路径的墙壁。暂时没有什么好的解决方案。


心得体会

本项目成功实现了基于树莓派RP2040的重力迷宫滚球小游戏,具有以下特点:

  1. 完整的游戏体验:实现了从启动到通关的完整游戏流程,包括多个关卡、计时、得分、音效等功能
  2. 良好的控制体验:使用MMA7660姿态传感器实现了流畅的重力感应控制,支持方向优先级逻辑
  3. 模块化设计:代码结构清晰,模块化程度高,便于维护和扩展
  4. 数据持久化:支持将迷宫地图数据保存到Flash,实现数据持久化
  5. 硬件资源利用:充分利用了RP2040的硬件资源,包括I2C、SPI、GPIO等


项目还存在一些可以改进的地方:

  1. 迷宫编辑器:可以开发一个迷宫编辑器,允许用户自定义迷宫
  2. 难度调整:可以增加难度设置,调整迷宫大小、时间限制等参数
  3. 更多游戏模式:可以添加时间挑战、无尽模式等游戏模式
  4. 视觉效果:可以增加小球移动的动画效果,提升游戏视觉体验
  5. 电源管理:可以优化电源管理,延长电池续航时间


总体而言,本项目成功实现了一个功能完整、体验良好的重力迷宫滚球小游戏,展示了树莓派RP2040的强大功能和应用潜力。

最后感谢电子森林推出的 《寒假练》 系列活动,对于我来说是个很好的学习机会,理论结合实践。我们下期活动再见!


五、参考资料

附件下载
源码.zip
PlatformIO 工程源码
团队介绍
业余电子爱好者
团队成员
鲜de芒果
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号