🎥 วิดีโอสอนสร้างเกม 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 ครบชุด