一、项目目标
打造一款基于 M5CoreS3 的便携式体感游戏机,玩家通过倾斜、摇晃、挥动设备等方式控制游戏,无需额外手柄。
二、核心硬件组成
1. 主控:M5CoreS3
ESP32-S3 双核处理器(主频高达 240MHz)内置 6 轴 IMU(ICM-42688-P 或类似):提供加速度和角速度数据2.0 英寸 320×240 IPS LCD 屏幕内置扬声器 + 麦克风(可用于音效或语音反馈)USB-C 供电 & 编程。



三、软件架构
开发环境
Arduino IDE + M5Unified 库

四、重力小球
游戏规则
屏幕上有一个小球,受“重力”影响会向设备倾斜方向滚动。玩家需通过倾斜设备,引导小球避开障碍物,收集星星。若撞到障碍物,游戏结束。
/*
* 使用 M5CoreS3 的 6 轴 IMU 控制小球收集星星,避开障碍物
*/
#include <M5Unified.h>
// 小球参数
int ballX = 160, ballY = 120;
float ballVX = 0, ballVY = 0;
// 星星(目标)
struct Star {
int x, y;
bool collected;
} stars[5];
// 障碍物
struct Obstacle {
int x, y;
int size = 20;
} obstacles[3];
// 游戏状态
int score = 0;
bool gameRunning = true;
unsigned long lastStarTime = 0;
const unsigned long starInterval = 8000; // 每8秒生成新星星(实际是重置未收集的)
// 滤波系数(用于平滑 IMU 数据)
const float alpha = 0.2;
float filteredAx = 0, filteredAy = 0;
// 初始化星星和障碍物
void initGame() {
score = 0;
ballX = 160; ballY = 120;
ballVX = ballVY = 0;
// 初始化星星(随机位置)
for (int i = 0; i < 5; i++) {
stars[i].x = random(20, 300);
stars[i].y = random(20, 220);
stars[i].collected = false;
}
// 初始化障碍物(固定位置,避免太难)
obstacles[0] = {80, 60};
obstacles[1] = {240, 180};
obstacles[2] = {160, 120};
gameRunning = true;
lastStarTime = millis();
}
// 检测点是否在矩形内
bool pointInRect(int px, int py, int rx, int ry, int size) {
return (px > rx && px < rx + size && py > ry && py < ry + size);
}
// 检测点是否在圆内(小球半径=8)
bool pointInBall(int px, int py, int bx, int by) {
int dx = px - bx;
int dy = py - by;
return (dx * dx + dy * dy) < (8 * 8);
}
void setup() {
auto cfg = M5.config();
cfg.clear_display = true;
M5.begin(cfg);
// 初始化 IMU
if (!M5.IMU.Init()) {
M5.Lcd.println("IMU Init Failed!");
while (1) delay(100);
}
M5.Speaker.setVolume(3);
randomSeed(analogRead(0));
initGame();
}
void loop() {
M5.update();
if (!gameRunning) {
// Game Over 画面
M5.Lcd.fillScreen(TFT_RED);
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextSize(3);
M5.Lcd.setCursor(40, 80);
M5.Lcd.println("GAME OVER");
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(90, 130);
M5.Lcd.printf("Score: %d", score);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(60, 180);
M5.Lcd.println("Press Btn A to Restart");
if (M5.BtnA.wasPressed()) {
initGame();
}
delay(50);
return;
}
// === 读取并滤波 IMU 数据 ===
float ax, ay, az;
M5.IMU.getAccelData(&ax, &ay, &az);
// 低通滤波(减少抖动)
filteredAx = alpha * ax + (1 - alpha) * filteredAx;
filteredAy = alpha * ay + (1 - alpha) * filteredAy;
// === 更新小球速度与位置 ===
ballVX = -filteredAx * 80; // X 轴反向:右倾 → 小球左移
ballVY = filteredAy * 80; // Y 轴:前倾 → 小球下移(符合直觉)
ballX += ballVX * 0.02;
ballY += ballVY * 0.02;
// 边界限制(留出小球半径)
ballX = constrain(ballX, 8, 312);
ballY = constrain(ballY, 8, 232);
// === 碰撞检测:障碍物 ===
for (int i = 0; i < 3; i++) {
if (pointInRect(ballX, ballY, obstacles[i].x, obstacles[i].y, obstacles[i].size)) {
// 播放爆炸音效(简单 beep)
M5.Speaker.tone(200, 200);
gameRunning = false;
break;
}
}
// === 收集星星 ===
for (int i = 0; i < 5; i++) {
if (!stars[i].collected && pointInBall(stars[i].x, stars[i].y, ballX, ballY)) {
stars[i].collected = true;
score += 10;
M5.Speaker.tone(1000, 100); // 收集音效
}
}
// === 自动刷新未收集的星星(每8秒)===
if (millis() - lastStarTime > starInterval) {
for (int i = 0; i < 5; i++) {
if (!stars[i].collected) {
stars[i].x = random(20, 300);
stars[i].y = random(20, 220);
}
}
lastStarTime = millis();
}
// === 绘制画面 ===
M5.Lcd.fillScreen(TFT_BLACK);
// 绘制障碍物(红色方块)
for (int i = 0; i < 3; i++) {
M5.Lcd.fillRect(obstacles[i].x, obstacles[i].y, obstacles[i].size, obstacles[i].size, TFT_RED);
}
// 绘制星星(黄色 ★ 符号,用小三角模拟)
for (int i = 0; i < 5; i++) {
if (!stars[i].collected) {
int x = stars[i].x, y = stars[i].y;
M5.Lcd.fillCircle(x, y, 3, TFT_YELLOW);
// 简单星形(可选)
M5.Lcd.drawPixel(x, y - 4, TFT_YELLOW);
M5.Lcd.drawPixel(x, y + 4, TFT_YELLOW);
M5.Lcd.drawPixel(x - 4, y, TFT_YELLOW);
M5.Lcd.drawPixel(x + 4, y, TFT_YELLOW);
}
}
// 绘制小球(白色)
M5.Lcd.fillCircle(ballX, ballY, 8, TFT_WHITE);
// 显示分数
M5.Lcd.setTextColor(TFT_GREEN);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(10, 10);
M5.Lcd.printf("Score: %d", score);
delay(20); // ~50 FPS
}
玩法说明
控制方式:倾斜 M5CoreS3 控制白色小球移动。目标:收集黄色星星(★),每个 +10 分。失败条件:碰到红色方块即 Game Over。重启:Game Over 后按 按钮 A 重新开始。
烧录步骤
在 Arduino IDE 中选择开发板:
选择端口(插入 USB-C 后自动识别)点击 上传(Upload)。

