ATtiny85 迷你街机:贪吃蛇 — 打造掌上 OLED 游戏机
组件与物料
| Microchip ATtiny85 | ×1 |
| 128×64 图形 OLED 屏 (I2C) | ×1 |
| SparkFun microB USB 电源板 | ×1 |
| Arduino Nano R3 (用于烧录 ATtiny85) | ×1 |
必需工具
- 电烙铁(通用)
- 3D 打印机(通用)
应用与在线服务
- Autodesk Fusion 360 (外壳设计)
- Arduino IDE
项目简介
灵感与前作
2017 年底我曾制作过基于 Arduino Nano 与 OLED 的手持 Pong 游戏机,但体积笨重。近期重制旧项目,目标是做一个极致小巧的贪吃蛇掌机。
核心元件选型
为实现微型化,放弃 Arduino 开发板,改用 ATtiny85 裸片。它提供足够 I/O:两路 ADC、一路 I2C、一路 GPIO。输入采用简易 2 轴摇杆/按键模块,仅需 3 根信号线。显示选用 DFRobot 128×64 OLED,尺寸小巧分辨率足够。
焊接系统
将 ATtiny85 焊接在 SOP-8 转 DIP-8 转接板上,再焊到千孔板。焊接两排排针:一排用于编程烧录,一排连 OLED。接着接摇杆信号线,最后接 micro USB 电源板供电。
外壳设计
使用 Fusion 360 建模:先建立实物元件模型并布局,再包裹设计外壳。造型致敬 80 年代街机,同时保持极小体积。
游戏编程
贪吃蛇逻辑简明:蛇身最大长度限 30 节(节省 RAM),吃满 29 个食物即胜利。用二维数组存储各节段坐标。蛇头移动时,前序坐标依次后移。吃食后在随机位置生成新食物。碰撞检测遍历所有节段坐标与蛇头比较,撞墙或撞身均判负。
游戏体验
上电等待画面初始化蛇头与食物,拨动摇杆控制移动吞食。游戏节奏紧凑,极适合碎片时间消遣,包装在指尖大小的复古街机盒中。
代码
ATtiny85 代码 (C/C++)
需先安装 U8g2lib
//#include <TinyWireM.h>
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g(U8G2_R0, /* clock=*/ 2, /* data=*/ 0, /* reset=*/ U8X8_PIN_NONE);
#define MAX_LENGTH 30
#define X 0
#define Y 1
#define JOYSTICK_X 2
#define JOYSTICK_Y 3
#define DIR_THRESH 300
uint8_t segmentPositions[MAX_LENGTH][2];
uint8_t headPosition[2] = {63, 31};
uint8_t foodPosition[2];
uint8_t tempPosition0[2], tempPosition1[2];
int segmentLength = 1;
void gameUpdate();
enum DIRECTIONS { RIGHT, DOWN, LEFT, UP } currentDirection;
void setup() {
//TinyWireM.begin();
u8g.begin();
u8g.setPowerSave(0);
pinMode(JOYSTICK_X, INPUT);
pinMode(JOYSTICK_Y, INPUT);
randomSeed(analogRead(0));
beginGame();
}
void loop() {
u8g.firstPage();
do { gameUpdate(); u8g.setColorIndex(1); } while(u8g.nextPage());
}
void beginGame(){
currentDirection = RIGHT;
spawnFood();
delay(1000);
}
bool checkCollisions(){
for(int i=1; i<segmentLength; i++){
if(segmentPositions[i][X] == headPosition[X] && segmentPositions[i][Y] == headPosition[Y]) return 1;
}
if(headPosition[X] <= 0 || headPosition[X] >= 128) return 1;
if(headPosition[Y] <= 0 || headPosition[Y] >= 64) return 1;
return false;
}
void spawnFood(){
foodPosition[X] = random(5, 123);
foodPosition[Y] = random(5, 60);
}
void checkFoodEaten(){
if(headPosition[X] == foodPosition[X] || headPosition[Y] == foodPosition[Y]){
segmentLength += 1;
spawnFood();
}
}
void updateDirection(){
int joy_x_val = analogRead(JOYSTICK_X);
int joy_y_val = analogRead(JOYSTICK_Y);
if(joy_x_val <= DIR_THRESH) currentDirection = LEFT;
else if(joy_x_val >= 1023-DIR_THRESH) currentDirection = RIGHT;
else if(joy_y_val <= DIR_THRESH) currentDirection = UP;
else if(joy_y_val >= 1023-DIR_THRESH) currentDirection = DOWN;
}
void displaySegments(){
for(int s=0; s<segmentLength; s++) u8g.drawPixel(segmentPositions[s][X], segmentPositions[s][Y]);
u8g.drawPixel(foodPosition[X], foodPosition[Y]);
}
void gameUpdate(){
updateDirection();
tempPosition0[X] = headPosition[X]; tempPosition0[Y] = headPosition[Y];
switch(currentDirection){
case UP: headPosition[Y] -= 1; break;
case DOWN: headPosition[Y] += 1; break;
case LEFT: headPosition[X] -= 1; break;
case RIGHT: headPosition[X] += 1; break;
}
for(int seg=1; seg<segmentLength; seg+=2){
tempPosition1[X] = segmentPositions[seg][X]; tempPosition1[Y] = segmentPositions[seg][Y];
segmentPositions[seg][X] = tempPosition0[X]; segmentPositions[seg][Y] = tempPosition0[Y];
tempPosition0[X] = segmentPositions[seg+1][X]; tempPosition0[Y] = segmentPositions[seg+1][Y];
segmentPositions[seg+1][X] = tempPosition1[X]; segmentPositions[seg+1][Y] = tempPosition1[Y];
}
displaySegments();
checkFoodEaten();
if(checkCollisions()) endGame();
if(segmentLength >= MAX_LENGTH) endGame();
delay(50);
}
void endGame(){
segmentLength = 1;
headPosition[0] = 63; headPosition[1] = 31;
beginGame();
}
自定义零件与外壳
(STL 文件见项目页面)
原理图

制造工艺
- 基于 Edge Impulse 的 TinyML 语言检测器:Arduino Nano 33 BLE Sense 实战
- Arduino Nano 与 MPU-6050 构建实时陀螺仪游戏
- Arduino 数字骰子:LCD 显示随机点数的电子骰子
- 用 Arduino Nano 自制 37 灯珠轮盘赌游戏机
- 便携测距仪 DIY 套件:Arduino Nano + HC-SR04 + 18650 电池 + 3D 打印外壳
- 声控氛围灯:Arduino Nano + 麦克风模块 + WS2812B 灯珠
- 铜电镀智能系统:基于 Arduino UNO 的可控电解装置
- Arduino Nano 驱动 NeoPixel 矩阵:自制霓虹乒乓游戏
- 使用 Arduino 移位寄存器创建绚丽灯光序列
- 智能插座:基于 Arduino 与 RTC 的 120V 定时开关插座
- Arduino 智能安防系统:超声波测距 + 舵机扫描 + 声光报警
- 用蜂鸣器和摇杆制作经典 Arduino LCD 街机游戏