🎥 วิดีโอสอนสร้างเกม Simon Says ด้วย Arduino Uno R4 WiFi แบบละเอียด
🎯 สิ่งที่คุณจะได้เรียนรู้
- การใช้งาน Arduino Uno R4 WiFi และ LED Matrix
- การเขียนโปรแกรมเกมและ Game Logic
- การสร้างเสียงและ Visual Effects
- การจัดการ Memory และ Performance
- การออกแบบ User Interface สำหรับเกม
ภาพรวมของโปรเจค
เกม Simon Says เป็นเกมฝึกความจำคลาสสิกที่ผู้เล่นต้องจำลำดับของสีและเสียงที่เกมแสดงให้ดู จากนั้นทำซ้ำตามลำดับที่ถูกต้อง ในโปรเจคนี้เราจะใช้ Arduino Uno R4 WiFi ที่มา LED Matrix ในตัว เพื่อสร้างเกมที่สวยงามและสนุก
จุดเด่นของ Arduino Uno R4 WiFi คือมี LED Matrix 12x8 ในตัว ทำให้เราสามารถแสดงกราฟิกและแอนิเมชันได้โดยไม่ต้องใช้อุปกรณ์เพิ่มเติม นอกจากนี้ยังมี DAC (Digital-to-Analog Converter) ที่สามารถสร้างเสียงได้
📊 แผนผังโดยรวมของระบบ
แผนผังแสดงการเชื่อมต่อและการทำงานของระบบโดยรวม
อุปกรณ์ที่ต้องใช้
🤖 Arduino และ Components หลัก
- Arduino Uno R4 WiFi - 1,290฿ (มี LED Matrix 12x8 ในตัว)
- Breadboard Half Size - 120฿ (สำหรับต่อวงจร)
- Jumper Wires Male-Male - 80฿ (สายจั๊มเปอร์)
- USB Cable Type-C - 150฿ (สำหรับเชื่อมต่อและจ่ายไฟ)
🔘 Input Controls
- Push Button Switch (4 ตัว) - 25฿/ตัว (ปุ่มสำหรับเล่นเกม)
- Resistor 10kΩ (4 ตัว) - 5฿/ตัว (Pull-up resistor)
- Resistor 220Ω (4 ตัว) - 5฿/ตัว (Current limiting)
💡 Visual Feedback (Optional)
- LED 5mm สี (4 สี) - 15฿/ตัว (แดง, เขียว, น้ำเงิน, เหลือง)
- Buzzer Active 5V - 45฿ (สำหรับเสียงเกม)
🔊 Audio Output (Optional)
- Speaker 8Ω 0.5W - 80฿ (ลำโพงเล็ก)
- Audio Amplifier Module - 120฿ (ขยายเสียง)
💰 ราคารวมประมาณ
- แบบพื้นฐาน: 1,800-2,200฿ (ใช้ LED Matrix เท่านั้น)
- แบบเต็มรูปแบบ: 2,500-3,000฿ (มี LED และเสียง)
- ประหยัด: ใช้ Arduino Uno R3 + LED Matrix Shield (1,500฿)
การต่อวงจร
การต่อวงจรของเกม Simon Says ค่อนข้างง่าย เนื่องจาก Arduino Uno R4 WiFi มี LED Matrix ในตัวแล้ว เราจึงต้องต่อเพียงปุ่มกดและอุปกรณ์เสริมเท่านั้น
🔌 แผนผังการต่อวงจรแบบละเอียด
แผนผังการต่อวงจรแบบละเอียด พร้อมค่าอุปกรณ์และการเชื่อมต่อ
การต่อปุ่มกด (Push Buttons)
- Button 1 (Red): Pin 2 → Button → GND (with 10kΩ pull-up)
- Button 2 (Green): Pin 3 → Button → GND (with 10kΩ pull-up)
- Button 3 (Blue): Pin 4 → Button → GND (with 10kΩ pull-up)
- Button 4 (Yellow): Pin 5 → Button → GND (with 10kΩ pull-up)
การต่อ LED เสริม (Optional)
- Red LED: Pin 6 → 220Ω → LED → GND
- Green LED: Pin 7 → 220Ω → LED → GND
- Blue LED: Pin 8 → 220Ω → LED → GND
- Yellow LED: Pin 9 → 220Ω → LED → GND
การต่อเสียง
- Buzzer: Pin 10 → Buzzer → GND
- Speaker (DAC): DAC Pin → Amplifier → Speaker
⚠️ ข้อควรระวัง
Arduino Uno R4 WiFi ใช้แรงดัน 5V แต่ MCU ภายในทำงานที่ 3.3V ตรวจสอบให้แน่ใจว่าอุปกรณ์ที่เชื่อมต่อรองรับแรงดันที่ถูกต้อง และใช้ Current Limiting Resistor กับ LED เสมอ
การเขียนโปรแกรม
โปรแกรมเกม Simon Says ประกอบด้วยส่วนหลัก 5 ส่วน คือ การแสดงผลบน LED Matrix, การรับ Input จากปุ่ม, การสร้างเสียง, Game Logic และการจัดการ Score
Setup และ Library
#include "Arduino_LED_Matrix.h"
// Initialize LED Matrix
ArduinoLEDMatrix matrix;
// Pin definitions
const int buttonPins[4] = {2, 3, 4, 5};
const int ledPins[4] = {6, 7, 8, 9};
const int buzzerPin = 10;
// Game variables
int gameSequence[100];
int playerSequence[100];
int gameLevel = 1;
int sequenceLength = 1;
bool gameActive = false;
bool playerTurn = false;
int playerIndex = 0;
// Timing variables
unsigned long lastButtonPress = 0;
unsigned long sequenceStartTime = 0;
const unsigned long buttonDebounce = 200;
const unsigned long playerTimeout = 3000;
// LED Matrix patterns for each color
const uint32_t redPattern[3] = {
0x3C3C3C3C,
0x3C3C3C3C,
0x3C3C3C3C
};
const uint32_t greenPattern[3] = {
0xC3C3C3C3,
0xC3C3C3C3,
0xC3C3C3C3
};
const uint32_t bluePattern[3] = {
0x0F0F0F0F,
0x0F0F0F0F,
0x0F0F0F0F
};
const uint32_t yellowPattern[3] = {
0xF0F0F0F0,
0xF0F0F0F0,
0xF0F0F0F0
};
void setup() {
Serial.begin(9600);
// Initialize LED Matrix
matrix.begin();
// Initialize buttons as inputs with pull-up
for (int i = 0; i < 4; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
pinMode(ledPins[i], OUTPUT);
digitalWrite(ledPins[i], LOW);
}
// Initialize buzzer
pinMode(buzzerPin, OUTPUT);
// Seed random number generator
randomSeed(analogRead(A0));
// Show welcome screen
showWelcomeScreen();
delay(2000);
// Start first game
startNewGame();
}
void loop() {
if (gameActive) {
if (!playerTurn) {
// Show sequence to player
showSequence();
playerTurn = true;
playerIndex = 0;
sequenceStartTime = millis();
} else {
// Wait for player input
checkPlayerInput();
// Check for timeout
if (millis() - sequenceStartTime > playerTimeout * sequenceLength) {
gameOver();
}
}
} else {
// Wait for button press to start new game
for (int i = 0; i < 4; i++) {
if (digitalRead(buttonPins[i]) == LOW) {
delay(buttonDebounce);
if (digitalRead(buttonPins[i]) == LOW) {
startNewGame();
break;
}
}
}
}
}
Game Logic Functions
void startNewGame() {
gameLevel = 1;
sequenceLength = 1;
gameActive = true;
playerTurn = false;
// Generate first sequence
for (int i = 0; i < sequenceLength; i++) {
gameSequence[i] = random(0, 4);
}
showLevel();
delay(1000);
}
void showSequence() {
for (int i = 0; i < sequenceLength; i++) {
// Show color on LED Matrix
showColor(gameSequence[i]);
playTone(gameSequence[i]);
delay(600);
// Clear display
matrix.clear();
delay(200);
}
}
void showColor(int colorIndex) {
// Turn on corresponding LED
digitalWrite(ledPins[colorIndex], HIGH);
// Show pattern on LED Matrix
switch (colorIndex) {
case 0: // Red
matrix.loadFrame(redPattern);
break;
case 1: // Green
matrix.loadFrame(greenPattern);
break;
case 2: // Blue
matrix.loadFrame(bluePattern);
break;
case 3: // Yellow
matrix.loadFrame(yellowPattern);
break;
}
delay(400);
digitalWrite(ledPins[colorIndex], LOW);
}
void playTone(int colorIndex) {
int frequencies[4] = {262, 330, 392, 523}; // C, E, G, C
tone(buzzerPin, frequencies[colorIndex], 400);
}
void checkPlayerInput() {
for (int i = 0; i < 4; i++) {
if (digitalRead(buttonPins[i]) == LOW &&
millis() - lastButtonPress > buttonDebounce) {
lastButtonPress = millis();
// Show player's choice
showColor(i);
// Check if correct
if (i == gameSequence[playerIndex]) {
playerIndex++;
// Check if sequence complete
if (playerIndex >= sequenceLength) {
// Level complete!
levelComplete();
}
} else {
// Wrong button - game over
gameOver();
}
break;
}
}
}
void levelComplete() {
// Show success animation
showSuccessAnimation();
// Increase difficulty
gameLevel++;
sequenceLength++;
// Add new color to sequence
gameSequence[sequenceLength - 1] = random(0, 4);
// Reset for next level
playerTurn = false;
playerIndex = 0;
showLevel();
delay(1500);
}
void gameOver() {
gameActive = false;
// Show game over animation
showGameOverAnimation();
// Play game over sound
for (int i = 0; i < 3; i++) {
tone(buzzerPin, 200, 200);
delay(300);
}
// Show final score
showScore();
delay(3000);
// Show restart message
showRestartMessage();
}
LED Matrix Display Functions
void showWelcomeScreen() {
const uint32_t welcomeFrame[3] = {
0x19297A5E,
0x297A5E19,
0x7A5E1929
};
matrix.loadFrame(welcomeFrame);
}
void showLevel() {
// Create level display pattern
uint32_t levelFrame[3] = {0, 0, 0};
// Simple level indicator (dots)
for (int i = 0; i < min(gameLevel, 12); i++) {
int row = i / 4;
int col = i % 4;
levelFrame[row] |= (1UL << (31 - col * 8));
}
matrix.loadFrame(levelFrame);
}
void showSuccessAnimation() {
// Animated success pattern
const uint32_t successFrames[4][3] = {
{0x00000000, 0x00180000, 0x00000000},
{0x00000000, 0x003C0000, 0x00000000},
{0x00180000, 0x007E0000, 0x00180000},
{0x003C0000, 0x00FF0000, 0x003C0000}
};
for (int frame = 0; frame < 4; frame++) {
matrix.loadFrame(successFrames[frame]);
tone(buzzerPin, 523 + frame * 100, 150);
delay(200);
}
delay(500);
matrix.clear();
}
void showGameOverAnimation() {
// Game over X pattern
const uint32_t gameOverFrame[3] = {
0x81424281,
0x42244224,
0x81424281
};
for (int i = 0; i < 5; i++) {
matrix.loadFrame(gameOverFrame);
delay(200);
matrix.clear();
delay(200);
}
}
void showScore() {
// Display final score
Serial.print("Game Over! Final Level: ");
Serial.println(gameLevel - 1);
// Simple score display on matrix
uint32_t scoreFrame[3] = {0, 0, 0};
// Show score as binary pattern
int score = gameLevel - 1;
for (int i = 0; i < 8 && i < score; i++) {
scoreFrame[0] |= (1UL << (31 - i * 4));
}
matrix.loadFrame(scoreFrame);
}
void showRestartMessage() {
// Blinking pattern to indicate restart
const uint32_t restartFrame[3] = {
0xFFFFFFFF,
0x00000000,
0xFFFFFFFF
};
for (int i = 0; i < 6; i++) {
matrix.loadFrame(restartFrame);
delay(300);
matrix.clear();
delay(300);
}
}
การปรับแต่งและเพิ่มฟีเจอร์
🎵 ระบบเสียงขั้นสูง
เราสามารถใช้ DAC ของ Arduino Uno R4 เพื่อสร้างเสียงที่ซับซ้อนมากขึ้น
// Advanced audio using DAC
void playMelody(int colorIndex) {
int melodies[4][4] = {
{262, 294, 330, 349}, // Red - C major scale
{330, 370, 415, 466}, // Green - E major scale
{392, 440, 494, 523}, // Blue - G major scale
{523, 587, 659, 698} // Yellow - High C major scale
};
for (int i = 0; i < 4; i++) {
analogWrite(DAC, map(sin(millis() * melodies[colorIndex][i] / 1000.0) * 127 + 127, 0, 255, 0, 255));
delay(100);
}
}
🏆 ระบบคะแนนและ High Score
// High score system using EEPROM
#include
int highScore = 0;
const int EEPROM_ADDRESS = 0;
void loadHighScore() {
highScore = EEPROM.read(EEPROM_ADDRESS);
if (highScore == 255) highScore = 0; // First time
}
void saveHighScore() {
if (gameLevel - 1 > highScore) {
highScore = gameLevel - 1;
EEPROM.write(EEPROM_ADDRESS, highScore);
showNewRecord();
}
}
void showNewRecord() {
// Special animation for new record
for (int i = 0; i < 10; i++) {
matrix.loadFrame(successFrames[i % 4]);
tone(buzzerPin, 800 + i * 50, 100);
delay(150);
}
}
🎮 โหมดเกมเพิ่มเติม
- Speed Mode: เวลาในการแสดงลำดับลดลงทุกเลเวล
- Reverse Mode: ผู้เล่นต้องกดปุ่มในลำดับย้อนกลับ
- Memory Mode: แสดงลำดับทั้งหมดพร้อมกัน แล้วให้ผู้เล่นจำ
- Multiplayer Mode: ผู้เล่น 2 คนผลัดกันเล่น
✅ ฟีเจอร์ที่สามารถเพิ่มได้
- WiFi Connectivity สำหรับ Online Leaderboard
- Mobile App Control ผ่าน Bluetooth
- Voice Commands ด้วย Speech Recognition
- RGB LED Strip สำหรับ Ambient Lighting
- Accelerometer สำหรับ Motion Control
การแก้ไขปัญหาที่พบบ่อย
🔧 ปัญหาทางเทคนิค
❌ ปัญหาที่พบบ่อย
- LED Matrix ไม่แสดงผล: ตรวจสอบการเรียก matrix.begin() และ loadFrame()
- ปุ่มกดไม่ตอบสนอง: ตรวจสอบ Pull-up Resistor และ Debounce
- เสียงไม่ออก: ตรวจสอบการต่อ Buzzer และ Ground
- เกมค้าง: เพิ่ม Timeout และ Error Handling
- Memory เต็ม: ลด Array Size หรือใช้ PROGMEM
🎯 เทคนิคการปรับปรุง
- Optimize Memory: ใช้ PROGMEM สำหรับ Pattern ที่ไม่เปลี่ยนแปลง
- Smooth Animation: ใช้ millis() แทน delay() สำหรับ Non-blocking Code
- Better UX: เพิ่ม Visual และ Audio Feedback
- Code Organization: แยก Functions ให้ชัดเจน
การขยายโปรเจค
🌐 เชื่อมต่อ WiFi
#include
#include
const char* ssid = "YourWiFi";
const char* password = "YourPassword";
void setupWiFi() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("WiFi connected!");
}
void uploadScore(int score) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin("http://yourserver.com/api/scores");
http.addHeader("Content-Type", "application/json");
String payload = "{\"score\":" + String(score) + "}";
int httpResponseCode = http.POST(payload);
if (httpResponseCode > 0) {
Serial.println("Score uploaded successfully!");
}
http.end();
}
}
📱 Mobile App Integration
สามารถสร้าง Mobile App ด้วย Flutter หรือ React Native เพื่อ:
- ควบคุมเกมผ่าน Bluetooth
- แสดง Leaderboard และสถิติ
- ปรับแต่งการตั้งค่าเกม
- บันทึกและแชร์ผลคะแนน
สรุป
เกม Simon Says ด้วย Arduino Uno R4 เป็นโปรเจคที่เหมาะสำหรับผู้เริ่มต้นเรียนรู้การเขียนโปรแกรม Arduino และการสร้างเกม ไม่เพียงแต่สนุกในการเล่น แต่ยังช่วยฝึกทักษะการเขียนโค้ด การจัดการ Input/Output และการออกแบบ User Experience
จุดเด่นของ Arduino Uno R4 WiFi คือมี LED Matrix ในตัวที่ทำให้เราสามารถสร้างเกมที่มี Visual Effects ที่สวยงามได้โดยไม่ต้องใช้อุปกรณ์เพิ่มเติมมาก นอกจากนี้ยังสามารถขยายฟีเจอร์ได้อีกมากมาย เช่น การเชื่อมต่อ WiFi, Mobile App Integration และระบบ Multiplayer
🛒 สั่งซื้ออุปกรณ์
อุปกรณ์ทั้งหมดในบทความนี้สามารถสั่งซื้อได้ที่ Global Byte Shop พร้อมคู่มือและ Source Code ครบชุด