#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSans9pt7b.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
enum MoleState{
IDLE,
POP,
HIT,
MISS
};
struct Mole{
int LED;
int Switch;
MoleState state;
int lastFlick;
int laststage;
unsigned long stateTimer;
unsigned long waitDuration;
unsigned long lastDebounceTime;
};
struct button{
int pin, stage, laststage;
};
Mole Molestatus[5] = {{13, 14, IDLE, HIGH, HIGH, 0, 0, 0},
{26, 27, IDLE, HIGH, HIGH, 0, 0, 0},
{32, 33, IDLE, HIGH, HIGH, 0, 0, 0},
{16, 17, IDLE, HIGH, HIGH, 0, 0, 0},
{18, 19, IDLE, HIGH, HIGH, 0, 0, 0}};
button BUTTON[3] = {{4, HIGH, HIGH},
{5, HIGH, HIGH},
{23, HIGH, HIGH}};
int year_select=1, name_select=0, score=0, StartTime=0;
String Names[9] = {"Ong1", "Ong2", "Ong3", "Ong4", "Ong5", "Ong6", "Ong7", "Ong8", "Ong9"};
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
display.begin(SSD1306_SWITCHCAPVCC, 0x3c); //initialize I2C addr 0x3c
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setRotation(2);
//pinMode W type
for (int i=0; i<3; i++) {
pinMode(BUTTON[i].pin, INPUT_PULLUP);
}
for (int i=0; i<5; i++) {
pinMode(Molestatus[i].Switch, INPUT_PULLUP);
pinMode(Molestatus[i].LED, OUTPUT);
Molestatus[i].waitDuration = random(1000, 6000);
}
//Select
SELECTPLAYER(Names[name_select], year_select);
while(BUTTON[2].stage != LOW){
BUTTON[0].stage = digitalRead(BUTTON[0].pin);
BUTTON[1].stage = digitalRead(BUTTON[1].pin);
BUTTON[2].stage = digitalRead(BUTTON[2].pin);
if(BUTTON[0].laststage == HIGH && BUTTON[0].stage == LOW){
year_select++;
if(year_select>4){year_select = 1;}
SELECTPLAYER(Names[name_select], year_select);
delay(250);
}
else if(BUTTON[1].laststage == HIGH && BUTTON[1].stage == LOW){
name_select++;
if(name_select>=9){name_select = 0;}
SELECTPLAYER(Names[name_select], year_select);
delay(250);
}
BUTTON[0].laststage = BUTTON[0].stage;
BUTTON[1].laststage = BUTTON[1].stage;
}
display.setFont(&FreeSans9pt7b);
DISPLAYS("!!START!!");
delay(2000);
for(int i=5; i>=1; i--){
DISPLAYS(String(i).c_str());
delay(1000);
}
StartTime = millis();
}
void loop() {
unsigned long currentMillis = millis();
for (int i=0; i<5; i++){
bool ispress = updateButtonDebounce(Molestatus[i], currentMillis);
switch (Molestatus[i].state) {
case IDLE:
digitalWrite(Molestatus[i].LED, LOW);
if (currentMillis-Molestatus[i].stateTimer >= Molestatus[i].waitDuration){
Molestatus[i].state = POP;
Molestatus[i].stateTimer = currentMillis;
Serial.printf("mole %d POP \n", i+1);
}
break;
case POP:
digitalWrite(Molestatus[i].LED, HIGH);
if(ispress){
Molestatus[i].state = HIT;
Molestatus[i].stateTimer = currentMillis;
score++;
Serial.printf("mole %d HIT \n", i+1);
}
if (currentMillis-Molestatus[i].stateTimer >= 1000){
Molestatus[i].state = MISS;
Molestatus[i].stateTimer = currentMillis;
Serial.printf("mole %d MISS \n", i+1);
}
break;
case HIT:
digitalWrite(Molestatus[i].LED, HIGH);
if (currentMillis-Molestatus[i].stateTimer >= 4000){
Molestatus[i].state = IDLE;
Molestatus[i].stateTimer = currentMillis;
Molestatus[i].waitDuration = random(2000, 7000);
Serial.printf("mole %d IDLE \n", i+1);
}
break;
case MISS:
digitalWrite(Molestatus[i].LED, LOW);
if (currentMillis-Molestatus[i].stateTimer >= 2000){
Molestatus[i].state = IDLE;
Molestatus[i].stateTimer = currentMillis;
Molestatus[i].waitDuration = random(2000, 7000);
Serial.printf("mole %d IDLE \n", i+1);
}
break;
}
}
if (millis()-StartTime >= 60000){
ESP.restart();
}
display.clearDisplay();
display.setCursor(0, 12);
display.print(F("Score: "));
display.println(score);
display.print(F("Time :"));
display.print((60000-(millis()-StartTime))/1000);
display.println(F("S"));
display.display();
}
void DISPLAYS(String text){
display.clearDisplay();
display.setCursor(0, 12);
display.print(text);
display.display();
}
void SELECTPLAYER(String Names, int8_t year_select){
display.clearDisplay();
display.setCursor(0, 12);
display.setFont(&FreeSans9pt7b);
display.print(F("Name:"));
display.println(Names);
display.print("Year:");
display.println(year_select);
display.setCursor(0, 55);
display.setFont();
display.print(F("Press Butt to select"));
display.display();
}
// ฟังก์ชันอ่านค่าปุ่มพร้อม Debounce 25 ms
bool updateButtonDebounce(Mole &mole, unsigned long now) {
bool reading = digitalRead(mole.Switch);
if (reading != mole.lastFlick) {
mole.lastFlick = reading;
mole.lastDebounceTime = now;
}
bool pressedEvent = false;
if ((now - mole.lastDebounceTime) > 25 && reading != mole.laststage) { //กรอง Debounce และ ถ้าสถานะเปลี่ยน
mole.laststage = reading;
if (reading == LOW) pressedEvent = true;
}
return pressedEvent;
}