組員:411214224 蔡宇鎮
摘要 :許多人對 80、90 年代的街機或掌上遊戲機充滿了回憶。這些簡單但耐 玩的遊戲雖然畫面樸素,卻讓人沉迷,這啟發了設計簡單、便攜的遊戲設備來 重現這種經典感。
所需材料:
Arduino Uno
OLED 顯示模組(SSD1306)
按鍵模組
杜邦線
面包板
USB 傳輸線
原理:
1. 蛇的資料儲存結構
蛇的每一節位置以陣列儲存
2. 食物邏輯
食物位置 X Y隨機生成在格線上
撞牆:蛇頭超出畫面邊界 → Game Over
撞自己:蛇頭與身體任一節重疊 → Game Over
4. 畫面更新
每回合清畫面 → 依序繪出蛇身、食物
顯示圖像
分數顯示在左上角
5. 重啟機制
按下 A 鍵重設陣列、分數與狀態
程式碼:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// 按鍵定義
#define UP 2
#define DOWN 3
#define LEFT 4
#define RIGHT 5
#define START 6
#define GRID_SIZE 4
#define MAX_LENGTH 64
int snakeX[MAX_LENGTH];
int snakeY[MAX_LENGTH];
int snakeLength = 3;
int dir = 3; // 0:上, 1:下, 2:左, 3:右
int foodX, foodY;
int score = 0;
bool gameOver = false;
void setup() {
pinMode(UP, INPUT_PULLUP);
pinMode(DOWN, INPUT_PULLUP);
pinMode(LEFT, INPUT_PULLUP);
pinMode(RIGHT, INPUT_PULLUP);
pinMode(START, INPUT_PULLUP);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.display();
resetGame();
}
void resetGame() {
snakeLength = 3;
score = 0;
for (int i = 0; i < snakeLength; i++) {
snakeX[i] = 32 - i * GRID_SIZE;
snakeY[i] = 32;
}
dir = 3;
spawnFood();
gameOver = false;
}
void spawnFood() {
foodX = (random(0, SCREEN_WIDTH / GRID_SIZE)) * GRID_SIZE;
foodY = (random(0, SCREEN_HEIGHT / GRID_SIZE)) * GRID_SIZE;
}
void loop() {
if (digitalRead(START) == LOW && gameOver) {
resetGame();
}
if (!gameOver) {
if (digitalRead(UP) == LOW && dir != 1) dir = 0;
if (digitalRead(DOWN) == LOW && dir != 0) dir = 1;
if (digitalRead(LEFT) == LOW && dir != 3) dir = 2;
if (digitalRead(RIGHT) == LOW && dir != 2) dir = 3;
for (int i = snakeLength - 1; i > 0; i--) {
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
if (dir == 0) snakeY[0] -= GRID_SIZE;
if (dir == 1) snakeY[0] += GRID_SIZE;
if (dir == 2) snakeX[0] -= GRID_SIZE;
if (dir == 3) snakeX[0] += GRID_SIZE;
// 撞牆或撞到自己判定
if (snakeX[0] < 0 || snakeX[0] >= SCREEN_WIDTH ||
snakeY[0] < 0 || snakeY[0] >= SCREEN_HEIGHT) {
gameOver = true;
}
for (int i = 1; i < snakeLength; i++) {
if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
gameOver = true;
}
}
// 吃到食物
if (snakeX[0] == foodX && snakeY[0] == foodY) {
if (snakeLength < MAX_LENGTH) snakeLength++;
score++;
spawnFood();
}
// 畫面更新
display.clearDisplay();
for (int i = 0; i < snakeLength; i++) {
display.fillRect(snakeX[i], snakeY[i], GRID_SIZE, GRID_SIZE, SSD1306_WHITE);
}
display.fillRect(foodX, foodY, GRID_SIZE, GRID_SIZE, SSD1306_WHITE);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Score: ");
display.print(score);
display.display();
} else {
// Game Over 畫面
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(30, 28);
display.println("Game Over!");
display.setCursor(20, 40);
display.println("Press A to restart");
display.display();
}
delay(100);
}
心得:
在這次專題實作中,我學會了如何操作 Arduino、進行接線佈局、讀取按鍵輸入,並透過程式控制 OLED 螢幕顯示圖形。過程中曾遇到像是按鍵無效、蛇的行為異常與重啟失敗等問題,但我逐步查找資料、測試並修正錯誤,最終順利完成一款功能完整的迷你貪食蛇遊戲。
這段經驗讓我對軟硬體整合流程有更深入的認識,也增進了動手實作與除錯的能力。未來若有機會,我希望能設計出專屬 3D 外殼,讓作品不僅可玩,還具有美觀與攜帶性,成為真正的小型遊戲裝置。