#include <AccelStepper.h>
#include <Servo.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
//TwoWire Wire(1);
//SPIClass SPI(0);
#define SCREEN_WIDTH 132 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 4
Adafruit_SH1106 display(OLED_RESET);
int obstacle_count = 0;
int obstacle_goal = 5;
// rat up/down side/side motion
int TRAIN_DIR_PIN = 2; // adjust pins as needed
int TRAIN_STEP_PIN = 3; // adjust pins as needed
int TRAIN_EN_PIN = 4; // adjust pins as needed
int SEWER_DIR_PIN = 5; // adjust pins as needed
int SEWER_STEP_PIN = 6; // adjust pins as needed
int SEWER_EN_PIN = 7; // adjust pins as needed
AccelStepper train_stepper(AccelStepper::DRIVER, TRAIN_STEP_PIN, TRAIN_DIR_PIN);
AccelStepper sewer_stepper(AccelStepper::DRIVER, SEWER_STEP_PIN, SEWER_DIR_PIN);
// spinner components
Servo myservo;
int spinner_button = 34; //
int choice;
bool spinnerButtonPressed = false; // Track if the button was pressed
unsigned long lastPressTime = 0; // Store the last time the button was pressed
const unsigned long debounceDelay = 200;
// speed game components
int ledPin = 28; //
int buttonPin = 30; //
int state = 1;
int score = 0;
long startTime;
long duration = 8000;
bool ledState = false;
long ledPreviousMillis = 0;
long ledInterval = 1000;
bool buttonPressed = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
// OLED screen
display.begin(SH1106_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128x64)
// init done
// Show image buffer on the display hardware.
// Since the buffer is intialized with an Adafruit splashscreen
// internally, this will display the splashscreen.
display.display();
delay(2000);
// Clear the buffer.
display.clearDisplay();
// draw a single pixel
display.drawPixel(10, 10, WHITE);
// Show the display buffer on the hardware.
// NOTE: You _must_ call display after making any drawing commands
// to make them visible on the display hardware!
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 10);
// Display static text
//display.println("Hello, world!");
display.display();
// Enable the stepper driver to move rat up and down
pinMode(TRAIN_EN_PIN, OUTPUT);
digitalWrite(TRAIN_EN_PIN, LOW);
train_stepper.setMaxSpeed(1000);
train_stepper.setAcceleration(500);
pinMode(SEWER_EN_PIN, OUTPUT);
digitalWrite(SEWER_EN_PIN, LOW);
sewer_stepper.setMaxSpeed(1000);
sewer_stepper.setAcceleration(500);
// servo motor picks obstacle
myservo.attach(36); //
//randomSeed(analogRead(A5));
//choice = random(1, 181);
pinMode(spinner_button, INPUT);
// button speed game pins
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT);
// pizza
// pinMode(44, INPUT);
// Serial.begin(9600);
// attachInterrupt(0, pulse, RISING); // Setup Interrupt
}
void loop() {
// put your main code here, to run repeatedly:
//int decision = spinner();
//Serial.println(decision);
int buttonState = digitalRead(spinner_button); // Read button state
// Check if the button is pressed and debounce time has passed
if (buttonState == HIGH && !spinnerButtonPressed && millis() - lastPressTime > debounceDelay) {
spinnerButtonPressed = true; // Register the button press
lastPressTime = millis(); // Update the press time
// Generate a new random position (between 0 and 180 degrees)
choice = random(0, 181);
myservo.write(choice); // Move the servo to the chosen position
Serial.println(choice); // Print the chosen value
delay(100);
//return choice;
}
if (choice > 120 && choice <= 180) {
sewer_obstacle();
Serial.println("sewer activated");
} else if (choice > 60 && choice <= 120) {
train_obstacle();
Serial.println("train activated");
} else if (choice > 0 && choice <= 60) {
button_speed_game();
Serial.println("speed activated");
}
// Reset button state when released
if (buttonState == LOW) {
spinnerButtonPressed = false; // Ready for the next press
}
return 0; // Return 0 if no new press detected
delay(500);
// if (obstacle_count >= obstacle_goal){
// Serial.println("you win");
// }
// else{
// Serial.println("you lose");
// }
//spinner();
//button_speed_game();
//train_obstacle();
//sewer_obstacle();
}
/*int spinner() {
int buttonState = digitalRead(spinner_button); // Read button state
// Check if the button is pressed and debounce time has passed
if (buttonState == HIGH && !spinnerButtonPressed && millis() - lastPressTime > debounceDelay) {
spinnerButtonPressed = true; // Register the button press
lastPressTime = millis(); // Update the press time
// Generate a new random position (between 0 and 180 degrees)
choice = random(0, 181);
myservo.write(choice); // Move the servo to the chosen position
Serial.println(choice); // Print the chosen value
return choice;
}
// Reset button state when released
if (buttonState == LOW) {
spinnerButtonPressed = false; // Ready for the next press
}
return 0; // Return 0 if no new press detected
}*/
void train_rat_pop_up() {
// rat pops up from obstacle
// materials required: 3D printed rotating link, stepper motor, rivets, cardboard
train_stepper.runToNewPosition(200);
delay(1000);
train_stepper.runToNewPosition(0);
delay(1000);
}
void sewer_rat_pop_up() {
// rat pops up from obstacle
// materials required: 3D printed rotating link, stepper motor, rivets, cardboard
sewer_stepper.runToNewPosition(200);
delay(1000);
sewer_stepper.runToNewPosition(0);
delay(1000);
}
// Helper function to update the score
void updateScoreDisplay(int score) {
// Clear only the area where the score is displayed
display.fillRect(0, 10, 128, 10, BLACK);
display.setCursor(0, 10);
display.print("Score: ");
display.println(score);
display.display();
}
// Countdown function: "Ready, Set, Go!"
void countdown() {
display.clearDisplay();
display.setCursor(0, 0);
// "Ready"
display.println("Ready...");
display.display();
Serial.println("Ready...");
delay(1000);
// "Set"
display.clearDisplay();
display.setCursor(0, 0);
display.println("Set...");
display.display();
Serial.println("Set...");
delay(1000);
// "Go!"
display.clearDisplay();
display.setCursor(0, 0);
display.println("Go!");
display.display();
Serial.println("Go!");
delay(1000);
display.clearDisplay(); // Clear for game start
updateScoreDisplay(0); // Show initial score
}
// button speed game states
void state1() {
if (digitalRead(buttonPin) == HIGH) {
display.println("Button speed game! Press as many times as possible in 10 seconds to win!");
display.display();
delay(5000);
countdown();
score = 0; // Reset score
updateScoreDisplay(score);
startTime = millis(); // save the starting time
state = 2; // transition to Main
}
}
void state2() {
if (millis() - startTime < duration) {
long ledCurrentMillis = millis();
if (ledCurrentMillis - ledPreviousMillis >= ledInterval) {
if (ledState == true) {
digitalWrite(ledPin, LOW);
ledState = false;
} else {
digitalWrite(ledPin, HIGH);
ledState = true;
ledInterval = random(100, 1500);
}
ledPreviousMillis = ledCurrentMillis;
}
if (digitalRead(buttonPin) == HIGH) {
if (ledState == true && buttonPressed == false) { // If LED is On , and the button was not pressed previously
score++; // add 1 point
updateScoreDisplay(score);
Serial.print("Score: ");
Serial.println(score);
buttonPressed = true; // update buttonPressed state
}
} else { //when the button is LOW
buttonPressed = false; // reset buttonPressed state
}
} else {
state = 3; //transition into “Outro”
}
}
// Outro
void state3() {
display.clearDisplay();
display.setCursor(0, 0);
display.print("Game Over! Total Score: ");
display.println(score);
display.display();
Serial.print("Game Over! Total Score: ");
Serial.println(score);
// Won or Lost
if (score > 35) {
display.println("You won!");
display.display();
Serial.println("You won!");
//obstacle_count++;
tone(33, 261, 300);
delay(300);
tone(33, 329, 300);
delay(300);
tone(33, 392, 300);
delay(1000);
} else {
display.println("You lost...");
display.display();
Serial.println("You lost...");
tone(33, 415, 500);
delay(500);
tone(33, 392, 500);
delay(500);
tone(33, 369, 500);
delay(500);
tone(33, 349, 500);
delay(1000);
}
display.println("Press the button to play again.");
display.display();
Serial.println("Press the restart button to play again.");
delay(1000); // wait 1 sec and then go back to intro again
state = 1; // transition to intro
}
void button_speed_game() { // good!
// button speed game: press the button as the light illuminates
// input: button
// output: LEDs
if (state == 1) {
state1(); // Before Game (Intro)
} else if (state == 2) {
state2(); // During Game (Main)
} else if (state == 3) {
state3(); // After Game (Outro)
}
}
void train_obstacle() { // good!
// train obstacle: kick(tap) the rat off the train tracks by getting the piezo read to 1000
// input: vibration sensor
// output: stepper motor
int vib_val = analogRead(A0);
if (vib_val > 70) {
train_rat_pop_up();
obstacle_count++;
}
Serial.println(vib_val);
delay(100);
}
void sewer_obstacle() { // good!
// sewer obstacle: push rat out of sewer
// input: pressure sensor
// output: stepper motor
int press_val = analogRead(A1);
if (press_val > 1000) {
sewer_rat_pop_up();
obstacle_count++;
}
Serial.println(press_val);
delay(100);
}