Quick Click Space Ship - a Unity / Arduino Arcade Game

by mardt in Circuits > Arduino

767 Views, 0 Favorites, 0 Comments

Quick Click Space Ship - a Unity / Arduino Arcade Game

expo.jpg
qcssprev copy.png
Quick Click Space Ship preview

I made an arcade game machine with Arduino, Unity & 10 buttons with LED lights, where you have to press the right button as quickly as you can, to fill your boost bar and boost!

You race to defeat your opponent.

Ever since visiting arcade centers in my country (the Netherlands) I wanted to create my own arcade machine.

Physical games in arcade centers have way more possibilities for types of inputs, types of displays and types of experiences that console or PC games could never have, which intrigues me.

I feel like there's huge potential for way more creative and interesting arcade games.

I have no experience with Arduino or making arcade games at all, so I doubt I will be able to rival current arcade games yet, but it'll be a first attempt and a fun challenge!

For this instructable I will summarize my process and leave out quite a lot of problems, struggles and little things I ran into to keep this from becoming too long. But I'll explain as much of the steps I took as I can!

Thanks for reading!

Supplies

  • Arduino Mega 2560 (or any Arduino with 20+ pins)
  • A 22 inch monitor you don't mind turning into an Arcade Machine (for a smaller or bigger monitor adjust the wood sizes accordingly)
  • Breadboard
  • A laptop or PC that can run your game
  • 2 big arcade buttons with LED's
  • 8 small arcade buttons with LED's
  • Various wires in different colors suitable for Arduino
  • Small heat shrink-wraps in different colors
  • Tie rips (small ones, preferably in different colors)
  • 10x 10kΩ resistors (for button inputs)
  • 10x 220Ω resistors (for button LED's)
  • 2 times 600mm x 600mm x 3mm MDF (4mm MDF is also fine)
  • 2 times 18mm x 600mm x 75mm wooden planks & 2 times 18mm x 40mm x 75mm wooden planks (or 1 big one you manually cut in 4 pieces)
  • Extra wood to reinforce the thing
  • As much little screws as you need to be confident it won't fall apart (I used 12 very small ones (they need to go in the 3mm MDF))
  • 8 long screws for the wooden planks
  • Wood glue

Software

  • Unity Game Engine
  • Arduino IDE

Tools

  • Drill
  • Soldering Iron & Tin
  • Heat gun
  • Wire stripper
  • Wood saw
  • File
  • Lasercutter (try to find a commercial place where you can use one if you're not a student with access to one at school) (or just manually cut through the MDF)

The Idea

ittconcept.png

Sorry the picture is in dutch, but it would be hard to read either way.

The point is, after going over different ideas I was very interested in making a top down arcade racing game.

Top down racing is a big genre but the screen you are playing it on is never actually top down.

So I'm going to make an actual top down racing game. I really like the idea of the table being the screen.

Since I have limited Arduino & coding experience I decided to go with buttons.

I brainstormed about different ways to use buttons as input for a racing game.

For example, pressing a single button as fast as possible, pressing in a certain rhythm, or pressing the button that lights up (what I ended up choosing).

I wanted it to be 4 players and a very big screen but I quickly learned that's outside of the scope and budget of this project (maybe another time).

I'm going to do 2 players and use an old 22 inch monitor I found in my parents attic.

I am going to use my laptop so I can use it's graphics card etc. because that's the easiest affordable option that's within the scope of this project.

Learning How to Use Button Inputs & Arduino to Unity Communication

image_2022-06-18_164749235.png

It would be great if I could immediately work on the final product, do it in 1 try and be done with it, but it would be quite a shame if I spent months on an arcade machine just to find out it doesn't work at all. That's why I took little baby steps at first.

This is actually my first ever Arduino project. When starting this I had just learned how to connect a single LED to an Arduino Uno and make it light up. I also have very limited coding knowledge and I was just about capable of creating a working if statement and maybe a for loop. So I first had to figure out how to connect a button and read the input.

I set up the most basic button connection (as seen in the picture) and tried to see if I was able to move a cube in Unity by just pressing it.

I ran into a ton of problems and errors before I got this to work but now that I've done it I'm going to pretend I know what I'm doing and explain it you properly.

The arduino code is as simple as this

void setup() {
  pinMode(2, INPUT_PULLUP); //set button pin
  Serial.begin(9600); //open serial communication 
}


void loop() {
  Serial.println(digitalRead(2)); //print 0 or 1 depending on whether the button is pressed to the serial


  delay(50); //fixes button debounce (for now)
}

Later I'm going to need to stop using delay because it stops the program and slows down the gameplay as well and ruin the experience when there is more than 1 player. (But I'll get into that later)

And in Unity all you need to do is read the Serial input and perform an action based on that.

A couple things that are important

  • The API compatibility level in Unity NEEDS to be set to Net Framework 4x. Otherwise it's just going to give you confusing errors.
  • Don't open the serial console from the Arduino IDE while testing in Unity (Unity will completely crash).

To use Serial communication in Unity you first need to add the library to our C# script.

using System.IO.Ports; 

After that you create a reference to the serial port your Arduino is in (can be found in your Arduino IDE). I simply called mine arduino.

And I found it convenient to create a string to store the data coming in from the Arduino. I called it arduinoOutput.

    SerialPort arduino = new SerialPort("COM4", 9600); //reference to the right serial port 
    string arduinoOutput = ""; 

Sadly, the serial can only be read as a string, but you can convert it to an int later if wanted with int.Parse.

Then in void start I open the serial.

    void Start()
    {
        arduino.Open();
    }

In update I use the ReadLine() function to read the incoming data and now it's just a matter of using that data however we like.

        if (arduino.BytesToRead > 0)
        {
            arduinoOutput = arduino.ReadLine();
            if (arduinoOutput == "1")
            {
                Debug.Log("oh my god it works");
            }
        }

It's important to always put the readline function inside an if statement that only activates when there is something to read. You never want Unity to try to read the serial when there is nothing to read because it will crash.

For this I used BytedToRead > 0.

Something I figured out later, (but I'll add it here) is how to send data the other way around, from Unity back to Arduino.

Arduino IDE:

  if (Serial.available() > 0) { //only read when there is something to read
    char serialRead = Serial.read(); //create variable to store incoming data
    if (serialRead == 'I'){
      Serial.println("it works guys");
    }

I used characters because they are quicker to read than strings with entire words.

In Unity all you need to do is:

arduino.Write("I");

The First Prototype

IMG_7042 copy.png
IMG_7305 copy.png

Now that I know how to connect an Arduino to Unity and use the button input, the sky is the limit really.

But before making a proper wooden case and setting it all up I started with a cardboard prototype.

I started with a cardboard prototype first so I can figure out if this idea is even fun at all or worth the effort.

I used a LED strip with this prototype because I made this during a seminar about Arduino & Light and I thought using the LED strip I got there would be a nice touch.

See it in action here: Cardboard prototype video

Short answer, yes it seems fun so far. It's a very simple little game that gets boring after 2 tries but people that played it were already competitive with this little prototype and tried to beat each others times.

I can see this being enjoyable when there's a whole top down race going on.

How I made it work:

I focused on making one player controller for now, with the main idea in place. 4 small buttons and a big button where you need to press the one that lights up as quickly as you can.

So I connected the five buttons each like I explained earlier. I bought buttons with LED lights and they all have 4 metal pins. + and - for the button inputs and + and - for the LEDs. I connected all the - to the ground and all the + individually through a resistor (220Ωf for the lights and 10kΩ for the button inputs).

The buttons have metal pins that don't fit in the breadboard or Arduino so I was forced to use a soldering iron for the first time. It was intimidating, but the buttons have little holes especially for soldering so it wasn't that hard in the end. I attached different colored cables to the right ends so I can remember which pin is which.

This time I couldn't get away with using delay because it was slowing down my game.

So I learned about using millis().

I also wanted it to count pushing the button and letting go as 1 press. Right now it only reads on or off when holding it down or not.

For the cardboard prototype I used a pretty bad hardcoded solution that kinda worked.

But I'll already share the way I ended up doing it in the final version here after a lot of struggling:

  BigButtoninput = digitalRead(BigButton);

   int buttonDebounce = 500;

    BigButtonState = BigButtonnput;
    if (BigButtonState != BigButtonLastState) {
      if (BigButtonState == 0) {
        float bigCurrentMillis = millis();
        if (bigCurrentMillis - startMillis > buttonDebounce) {
          Serial.println("BOOST");
          gameState = "Play";
          startMillis = bigCurrentMillis;
        }
      }
    }
    BigButtonLastState = BigButtonState;

I use multiple bool variables to check whether the pressed "state" is different from before to see if a button has been "pressed". I also incorporated the millis() function to fix the button debounce without using delay.

The code for the cardboard prototype is a big hardcoded mess since I was trying a lot of this for the first time, so I apologize in advance, but what it does is it pretty much randomly generates a number from 1-4 and using that it randomly turns on one of the 4 little LED lights and when you press the right button the next light goes on and so on.

Every correct click or wrong click it sends information to Unity which I use to play a sound.

Every 4 clicks the LED strip fills a little till its full and the blue button turns on.

Then you can press that to finish the game and check your time.

Unity starts a timer as soon as the game starts.

//Stuff to get led strip to work
#include <Adafruit_NeoPixel.h>

#define LED_PIN 4
#define LED_COUNT 7

Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);


//inputs & button lights
int bigButton = 7;
int bigButtonLight = 11;

int sButtonOne = 2;
int sButtonOneLight = 3;
int sButtonTwo = 13;
int sButtonTwoLight = 6;
int sButtonThree = 12;
int sButtonThreeLight = 5;
int sButtonFour = 8;
int sButtonFourLight = 10;


//other variables
int switchCount = 0;
int buttonPushCounter = 0; //hoeveel knop presses
int startButtonPushCounter = 0; //button presses aan begin
int currentButtonPushCounter = 0; //huidige presses
int bigButtonState = 0; //start knop status
int lastButtonState = 0; //huidige knop status

//Button states
int sButtonOneState = 0;
int sButtonOneLastState = 0;
int sButtonTwoState = 0;
int sButtonTwoLastState = 0;
int sButtonThreeState = 0;
int sButtonThreeLastState = 0;
int sButtonFourState = 0;
int sButtonFourLastState = 0;
boolean btn1pressed = 0;
boolean btn2pressed = 0;
boolean btn3pressed = 0;
boolean btn4pressed = 0;


int startMillis; //start tijd
int currentMillis; //huidige tijd
int pressPeriod = 0; //start periode
int waitPeriod = 2; //periode om de hoeveel seconden hij checkt


int speedScore = 0;


int randomLight = 1;
const int randomLightRangeOne[] = {1, 3, 4};
const int randomLightRangeTwo[] = {1, 2, 4};
int gameCounter = 24;
int scoreMillis; //score
int buttonChecker = 0;
int plingScore = 6;
int oldPlingScore = 6;


bool startGame = false;
int startCounter = 0;


int timerStart = 0;
int timerCurrent = 0;
int timerPeriod = 200;


void setup() {
  strip.begin();

  randomSeed(analogRead(A0)); //without this line for some reason using random isn't really random
  randomLight = random(1, 5);

  pinMode(bigButtonLight, OUTPUT);
  pinMode(bigButton, INPUT_PULLUP);

  pinMode(sButtonOneLight, OUTPUT);
  pinMode(sButtonOne, INPUT_PULLUP);

  pinMode(sButtonTwoLight, OUTPUT);
  pinMode(sButtonTwo, INPUT_PULLUP);

  pinMode(sButtonThreeLight, OUTPUT);
  pinMode(sButtonThree, INPUT_PULLUP);

  pinMode(sButtonFourLight, OUTPUT);
  pinMode(sButtonFour, INPUT_PULLUP);

  Serial.begin(9600);
  Serial.flush();

  startMillis = millis();
  startButtonPushCounter = buttonPushCounter;
}


void loop() {

  strip.show();

  //GAME OFF
  //////////////////////////

  if (digitalRead(7) == 0) {
    startCounter++;
  }


  if (startGame == false) {
    digitalWrite(bigButtonLight, HIGH);
    if (digitalRead(7) == 0) {
      startCounter++;
    }
    delay(50);
    digitalWrite(sButtonOneLight, HIGH);
    digitalWrite(sButtonTwoLight, LOW);
    digitalWrite(sButtonThreeLight, LOW);
    digitalWrite(sButtonFourLight, LOW);
    if (digitalRead(7) == 0) {
      startCounter++;
    }
    delay(50);
    digitalWrite(sButtonOneLight, LOW);
    digitalWrite(sButtonTwoLight, HIGH);
    digitalWrite(sButtonThreeLight, LOW);
    digitalWrite(sButtonFourLight, LOW);
    if (digitalRead(7) == 0) {
      startCounter++;
    }
    delay(50);
    digitalWrite(sButtonOneLight, LOW);
    digitalWrite(sButtonTwoLight, LOW);
    digitalWrite(sButtonThreeLight, HIGH);
    digitalWrite(sButtonFourLight, LOW);
    if (digitalRead(7) == 0) {
      startCounter++;
    }
    delay(50);
    digitalWrite(sButtonOneLight, LOW);
    digitalWrite(sButtonTwoLight, LOW);
    digitalWrite(sButtonThreeLight, LOW);
    digitalWrite(sButtonFourLight, HIGH);
    if (digitalRead(7) == 0) {
      startCounter++;
    }
    delay(50);
    if (digitalRead(7) == 0) {
      startCounter++;
    }
  }


  currentMillis = millis();


  if (startCounter >= 1) {
    startGame = true;
  }


  //GAME
  //////////////////////////////////////////////////////////
  if (startGame == true) {


    digitalWrite(bigButtonLight, LOW);


    sButtonOneState = digitalRead(sButtonOne);
    if (sButtonOneState != sButtonOneLastState) {
      if (sButtonOneState == 0) {
        buttonChecker = 1;
        btn1pressed = 1;
      }
    }
    sButtonOneLastState = sButtonOneState;


    //
    sButtonTwoState = digitalRead(sButtonTwo);
    if (sButtonTwoState != sButtonTwoLastState) {
      if (sButtonTwoState == 0) {
        buttonChecker = 2;
        btn2pressed = true;
      }
    }
    sButtonTwoLastState = sButtonTwoState;


    //
    sButtonThreeState = digitalRead(sButtonThree);
    if (sButtonThreeState != sButtonThreeLastState) {
      if (sButtonThreeState == 0) {
        buttonChecker = 3;
        btn3pressed = true;
      }
    }
    sButtonThreeLastState = sButtonThreeState;


    //
    sButtonFourState = digitalRead(sButtonFour);
    if (sButtonFourState != sButtonFourLastState) {
      if (sButtonFourState == 0) {
        buttonChecker = 4;
        btn4pressed = true;
      }
    }
    sButtonFourLastState = sButtonFourState;


    for (int y = gameCounter / 4; y < 7; y++) { //add to LED strip 
      strip.setPixelColor(y, 255, 115, 8);
    }

    if (oldPlingScore != plingScore) {
      Serial.println("point");
      oldPlingScore--;
    }
    oldPlingScore = plingScore;


    timerCurrent = millis();


    switch (randomLight) {
      case 1:
        digitalWrite(sButtonOneLight, HIGH);
        digitalWrite(sButtonTwoLight, LOW);
        digitalWrite(sButtonThreeLight, LOW);
        digitalWrite(sButtonFourLight, LOW);
        if ( btn2pressed || btn3pressed || btn4pressed) {
          Serial.println("wrong");
        } else  if (btn1pressed  ) {
          randomLight = random(2, 5);
          gameCounter--;
          plingScore = gameCounter / 4;
          Serial.println("pling");
        }
        delay(10);
        break;
      case 2:
        digitalWrite(sButtonOneLight, LOW);
        digitalWrite(sButtonTwoLight, HIGH);
        digitalWrite(sButtonThreeLight, LOW);
        digitalWrite(sButtonFourLight, LOW);
        if ( btn1pressed || btn3pressed || btn4pressed) {
          Serial.println("wrong");
        } else  if (btn2pressed  ) {
          randomLight = randomLightRangeOne[random(0, 3)];
          gameCounter--;
          plingScore = gameCounter / 4;
          Serial.println("pling");
        }
        delay(10);
        break;
      case 3:
        digitalWrite(sButtonOneLight, LOW);
        digitalWrite(sButtonTwoLight, LOW);
        digitalWrite(sButtonThreeLight, HIGH);
        digitalWrite(sButtonFourLight, LOW);
        if ( btn1pressed || btn2pressed || btn4pressed) {
          Serial.println("wrong");
        } else  if (btn3pressed  ) {
          randomLight = randomLightRangeTwo[random(0, 3)];
          gameCounter--;
          plingScore = gameCounter / 4;
          Serial.println("pling");
        }
        delay(10);
        break;
      case 4:
        digitalWrite(sButtonOneLight, LOW);
        digitalWrite(sButtonTwoLight, LOW);
        digitalWrite(sButtonThreeLight, LOW);
        digitalWrite(sButtonFourLight, HIGH);
        if ( btn1pressed || btn2pressed || btn3pressed) {
          Serial.println("wrong");
        } else  if (btn4pressed  ) {
          randomLight = random(1, 4);
          gameCounter--;
          plingScore = gameCounter / 4;
          Serial.println("pling");
        }
        delay(10);
        break;
    }
    btn1pressed = false;
    btn2pressed = false;
    btn3pressed = false;
    btn4pressed = false;


    if (gameCounter <= 0) {
      digitalWrite(bigButtonLight, HIGH);
      Serial.println("finished");
      delay(5);
    }
    else {
      digitalWrite(bigButtonLight, LOW);
      Serial.println("startgame");
      delay(20);
    }
  }
}

Making the Actual Game

qcssprev copy.png
qcssprev cop23y.png
qcssprev co2323py.png
spaceshipthumbnails.png
spaceshipconceptsV2.png

So this cardboard game made with a shoebox is cool and all, but now it's time to make the actual game.

One thing I decided to drop is the led strip. Even though it was pretty cool, getting another one is expensive and it's very unreliable hardware. If you connect it to power before connecting it to ground the first LED breaks. It's always a guess that that's the reason why your strip isn't working. I broke a LED in my led strip 2 times and both times it took hours before I realized that was the reason why my code wasn't working.

Also soldering and connecting it was really annoying so I just decided to drop it. I was excited about creating a animated boost bar UI on the screen anyway so the LED strip isn't necessary.

I won't go into much detail about the Unity game itself. I'd recommend if you want to try making something similar; think about all infinite awesome possibilities you have with custom button inputs and whatever game idea you can think of and try something out.

I used some of the art & sound design experience I have as a first year game artist for the look and feel. I brainstormed, thumbnailed and sketched ideas and modeled everything in Blender. I used EpidemicSound & Splice as sound libraries and edited and layered the sounds to fit my needs with FL Studio.

To make it work I went on a big journey through youtube's big library of Unity C# tutorials and google to:

  • Get the space ships to follow a custom path
  • Create a working smooth boost (speed increase)
  • Have them switch paths based on who's first
  • Check who's won...
  • A menu structure and space ship select screen

After weeks of coding I learned so much I was able to add most of the things by myself. I slowly became more confident with coding and I became a lot faster at it and more efficient!

There were points where I thought I wasn't able to do it and I almost gave up (especially when figuring out path following and switching paths), but after months of hard work it slowly became easier and easier to code till at some point it actually became fun...

I did a lot of visual and audio things for the first time aswell. This is the first time I used pitch in Unity to create the satisfying sound that feels like its going up when playing. This is the first time I properly used the VFX graph in Unity to create Fire VFX when boosting. I added a camera shake, I made animated UI elements and much more.

Creating a UI for 2 opposite sides of the screen flipped was also a fun challenge.

It's the first time I did all of this and I'm so excited about all the Unity things I learned during this project.

(I still have much more to learn of course)

To have Unity properly communicate with Arduino I wanted to write a better code than the hardcoded mess from before. I thought about how I could use arrays to improve the code and incorporate millis() better (because I secretly still used delay sometimes in the cardboard prototype).

But the most important thing I decided to do was create a "mode" system.

With the cardboard prototype I had the annoying problem that every time someone was done playing the buttons would be stuck where they ended and to replay you had to manually replug the USB cable into the laptop.

I thought a lot about rebooting the Arduino through code, which seems to be possible in a way, but it still needs to completely reboot every time if I want to reset the Arduino and rebooting takes quite a bit time, especially with the amount of code I'm about to show you in a bit.

So I created a couple "modes". An idle mode, a menu mode and a game mode. The game mode has several states as well (wait, play and boost). All I need to do then is send characters from Unity to the Arduino when a specific mode is needed and the Arduino switches to the desired mode. This way you can smoothly transition from menu, to space ship select, to game and restart without having to reboot at all. And I used it to create a short waiting period when you press the wrong button and a boost mode where the game allows you to press the boost button.

So I connected the 4 other buttons and made the 2 player version.

I still had trouble with doing everything in the most optimized way using for loops and arrays and the deadline was closing in, so I still hardcoded a lot of parts.

But I'm confident I can do much better next project.

(I'm also just really happy it works)

//GameController / logic
String GameMode = "Idle";
String gameState = "Wait";
String gameState2 = "Wait";
bool boostState1 = false;
bool boostState2 = false;
int randomLight = 1;
int randomLight2 = 1;
const int randomLightRangeOne[] = {1, 3, 4};
const int randomLightRangeTwo[] = {1, 2, 4};
const int randomLightRangeOne2[] = {1, 3, 4};
const int randomLightRangeTwo2[] = {1, 2, 4};


//Player 1 ---------------
//Lights
int Light11 = 8;
int Light12 = 9;
int Light13 = 3;
int Light14 = 7;
int BigLight1 = 10;
int buttonLights1[] = {Light11, Light12, Light13, Light14};

//Buttons
int Button11 = 30;
int Button12 = 22;
int Button13 = 34;
int Button14 = 32;
int BigButton1 = 49;

int button11Pressed = 0;
int button12Pressed = 0;
int button13Pressed = 0;
int button14Pressed = 0;

int buttonPressed1[] = {button11Pressed, button12Pressed, button13Pressed, button14Pressed};
bool bigButton1Pressed = false;

int buttons1[] = {Button11, Button12, Button13, Button14};

int buttonInput1[] = {1, 1, 1, 1};
int BigButton1input = 1;

int BigButton1State = 0;
int BigButton1LastState = 0;
int Button11State = 0;
int Button11LastState = 0;
int Button12State = 0;
int Button12LastState = 0;
int Button13State = 0;
int Button13LastState = 0;
int Button14State = 0;
int Button14LastState = 0;

int Button1States[] = {Button11State, Button12State, Button13State, Button14State};
int Button1LastStates[] = {Button11LastState, Button12LastState, Button13LastState, Button14LastState};

//Player 2 ----------------
//Lights
int Light21 = 2;
int Light22 = 5;
int Light23 = 4;
int Light24 = 6;
int BigLight2 = 12;

int buttonLights2[] = {Light11, Light12, Light13, Light14};

//Buttons
int Button21 = 26;
int Button22 = 36;
int Button23 = 28;
int Button24 = 24;
int BigButton2 = 44;

int button21Pressed = 0;
int button22Pressed = 0;
int button23Pressed = 0;
int button24Pressed = 0;

int buttonPressed2[] = {button21Pressed, button22Pressed, button23Pressed, button24Pressed};
bool bigButton2Pressed = false;

int buttons2[] = {Button21, Button22, Button23, Button24};

int buttonInput2[] = {1, 1, 1, 1};
int BigButton2input = 1;

int BigButton2State = 0;
int BigButton2LastState = 0;
int Button21State = 0;
int Button21LastState = 0;
int Button22State = 0;
int Button22LastState = 0;
int Button23State = 0;
int Button23LastState = 0;
int Button24State = 0;
int Button24LastState = 0;

int Button2States[] = {Button21State, Button22State, Button23State, Button24State};
int Button2LastStates[] = {Button21LastState, Button22LastState, Button23LastState, Button24LastState};

//Millis variables
float startMillisIdle = 0;
float startMillisMenu = 0;
float startMillisMenu2 = 0;
float startMillisGame = 0;
float startMillisGame2 = 0;
float startMillisGameSwitch = 0;
float startMillisGameSwitch2 = 0;
int ledCounter = 0;

void setup() {
  Serial.begin(9600);
  Serial.flush();
  Serial.setTimeout(10);

  randomSeed(analogRead(A0));
  randomLight = random(1, 5);
  randomLight2 = random(1, 5);

  //Player 1 pinmode setup
  pinMode(Light11, OUTPUT);
  pinMode(Light12, OUTPUT);
  pinMode(Light13, OUTPUT);
  pinMode(Light14, OUTPUT);
  pinMode(BigLight1, OUTPUT);

  pinMode(Button11, INPUT_PULLUP);
  pinMode(Button12, INPUT_PULLUP);
  pinMode(Button13, INPUT_PULLUP);
  pinMode(Button14, INPUT_PULLUP);
  pinMode(BigButton1, INPUT_PULLUP);

  //Player 2 pinmode setup
  pinMode(Light21, OUTPUT);
  pinMode(Light22, OUTPUT);
  pinMode(Light23, OUTPUT);
  pinMode(Light24, OUTPUT);
  pinMode(BigLight2, OUTPUT);

  pinMode(Button21, INPUT_PULLUP);
  pinMode(Button22, INPUT_PULLUP);
  pinMode(Button23, INPUT_PULLUP);
  pinMode(Button24, INPUT_PULLUP);
  pinMode(BigButton2, INPUT_PULLUP);
}

void loop() {

  //Mode switching
  if (GameMode == "Idle") {
    IdleScreen(250);
  }
   if (GameMode == "EndScreen") {
    EndScreen(500);
  }
  if (GameMode == "Menu") {
    MenuScreen();
  }

  if (Serial.available() > 0) {
    char serialRead = Serial.read();
    if (serialRead == 'C'){
      GameMode = "EndScreen";
    }
    if (serialRead == 'I'){
      GameMode = "Idle";
    }
    if (serialRead == 'S') {
      GameMode = "Game";
      gameState = "Wait";
      gameState2 = "Wait";
    }
    if (serialRead == 'M'){
      GameMode = "Menu";
    }
    if (serialRead == 'B') {
      gameState = "Play";
    }
    if (serialRead == 'N') {
      gameState2 = "Play";
    }
    if (serialRead == 'W') {
      gameState = "Wait";
    }
    if (serialRead == 'E') {
      gameState2 = "Wait";
    }
    if (serialRead == 'O') {
      gameState = "Boost";
    }
    if (serialRead == 'P') {
      gameState2 = "Boost";
    }
  }

  if (GameMode == "Game") {
    Game();
  }

  //Player 1 input checker
  BigButton1input = digitalRead(BigButton1);
  for (int i = 0; i < 4; i++) {
    buttonInput1[i] = digitalRead(buttons1[i]);
  }

  //Player 2 input checker
  BigButton2input = digitalRead(BigButton2);
  for (int i = 0; i < 4; i++) {
    buttonInput2[i] = digitalRead(buttons2[i]);
  }
}

void Game() {

  //Short period before game starts
  if (gameState == "Wait") {
    digitalWrite(Light11, HIGH);
    digitalWrite(Light12, HIGH);
    digitalWrite(Light13, HIGH);
    digitalWrite(Light14, HIGH);
    digitalWrite(BigLight1, LOW);
  }
  if (gameState2 == "Wait") {
    digitalWrite(Light21, HIGH);
    digitalWrite(Light22, HIGH);
    digitalWrite(Light23, HIGH);
    digitalWrite(Light24, HIGH);
    digitalWrite(BigLight2, LOW);
  }

  if (gameState == "Boost") {
    digitalWrite(Light11, HIGH);
    digitalWrite(Light12, HIGH);
    digitalWrite(Light13, HIGH);
    digitalWrite(Light14, HIGH);
    digitalWrite(BigLight1, HIGH);

    int buttonDebounce = 500;
    BigButton1State = BigButton1input;
    if (BigButton1State != BigButton1LastState) {
      if (BigButton1State == 0) {
        float bigCurrentMillis1 = millis();
        if (bigCurrentMillis1 - startMillisMenu > buttonDebounce) {
          Serial.println("BOOST");
          gameState = "Play";
          startMillisMenu = bigCurrentMillis1;
        }
      }
    }
    BigButton1LastState = BigButton1State;
  }

  if (gameState2 == "Boost") {
    digitalWrite(Light21, HIGH);
    digitalWrite(Light22, HIGH);
    digitalWrite(Light23, HIGH);
    digitalWrite(Light24, HIGH);
    digitalWrite(BigLight2, HIGH);
    int buttonDebounce = 500;
    BigButton2State = BigButton2input;
    if (BigButton2State != BigButton2LastState) {
      if (BigButton2State == 0) {
        float bigCurrentMillis2 = millis();
        if (bigCurrentMillis2 - startMillisMenu2 > buttonDebounce) {
          Serial.println("BOOST2");
          gameState2 = "Play";
          startMillisMenu2 = bigCurrentMillis2;
        }
      }
    }
    BigButton2LastState = BigButton2State;
  }

  if (gameState == "Play") {
    digitalWrite(BigLight1, LOW);
    //Player 1
    int buttonDebounce = 25;
    for (int i = 0; i < 4; i++) {
      Button1States[i] = buttonInput1[i];
      float currentGameMillis = millis();
      if (currentGameMillis - startMillisGame > buttonDebounce) {
        if (Button1States[i] != Button1LastStates[i]) {
          if (Button1States[i] == 0) {
            buttonPressed1[i] = 1;
            startMillisGame = currentGameMillis;
          }
        }
        Button1LastStates[i] = Button1States[i];
      }
    }
    float lightSwitchDebounce = 250;

    switch (randomLight) {
      case 1:
        //Serial.println("lightNumber1" + String(randomLight));
        digitalWrite(Light11, HIGH);
        digitalWrite(Light12, LOW);
        digitalWrite(Light13, LOW);
        digitalWrite(Light14, LOW);

        if (buttonPressed1[1] == 1 || buttonPressed1[2] == 1 || buttonPressed1[3] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch > lightSwitchDebounce) {
            Serial.println("P1Wrong");
            startMillisGameSwitch = switchMillis;
          }
          //randomLight = random(2, 5);
        }
        else if (buttonPressed1[0] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch > lightSwitchDebounce) {
            randomLight = random(2, 5);
            Serial.println("P1Check");
            startMillisGameSwitch = switchMillis;
          }
        }
        break;
      case 2:
        //Serial.println("lightNumber1" + String(randomLight));
        digitalWrite(Light11, LOW);
        digitalWrite(Light12, HIGH);
        digitalWrite(Light13, LOW);
        digitalWrite(Light14, LOW);
        if (buttonPressed1[0] == 1 || buttonPressed1[2] == 1 || buttonPressed1[3] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch > lightSwitchDebounce) {
            Serial.println("P1Wrong");
            startMillisGameSwitch = switchMillis;
          }
          //randomLight = randomLightRangeOne[random(0, 3)];
        }
        else if (buttonPressed1[1] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch > lightSwitchDebounce) {
            randomLight = randomLightRangeOne[random(0, 3)];
            Serial.println("P1Check");
            startMillisGameSwitch = switchMillis;
          }
        }
        break;
      case 3:
        //Serial.println("lightNumber1" + String(randomLight));
        digitalWrite(Light11, LOW);
        digitalWrite(Light12, LOW);
        digitalWrite(Light13, HIGH);
        digitalWrite(Light14, LOW);
        if (buttonPressed1[0] == 1 || buttonPressed1[1] == 1 || buttonPressed1[3] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch > lightSwitchDebounce) {
            Serial.println("P1Wrong");
            startMillisGameSwitch = switchMillis;
          }
          //randomLight = randomLightRangeTwo[random(0, 3)];
        }
        else if (buttonPressed1[2] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch > lightSwitchDebounce) {
            Serial.println("P1Check");
            randomLight = randomLightRangeTwo[random(0, 3)];
            startMillisGameSwitch = switchMillis;
          }
        }
        break;
      case 4:
        //Serial.println("lightNumber1" + String(randomLight));
        digitalWrite(Light11, LOW);
        digitalWrite(Light12, LOW);
        digitalWrite(Light13, LOW);
        digitalWrite(Light14, HIGH);
        if (buttonPressed1[0] == 1 || buttonPressed1[1] == 1 || buttonPressed1[2] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch > lightSwitchDebounce) {
            Serial.println("P1Wrong");
            startMillisGameSwitch = switchMillis;
          }
          //randomLight = random(1, 4);
        }
        else if (buttonPressed1[3] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch > lightSwitchDebounce) {
            Serial.println("P1Check");
            randomLight = random(1, 4);
            startMillisGameSwitch = switchMillis;
          }
        }
        break;
    }
    for (int i = 0; i < 4; i++) {
      buttonPressed1[i] = 0;
    }
  }

  if (gameState2 == "Play") {
    digitalWrite(BigLight2, LOW);

    //Player 2
    int buttonDebounce = 25;
    for (int i = 0; i < 4; i++) {
      Button2States[i] = buttonInput2[i];
      float currentGameMillis = millis();
      if (currentGameMillis - startMillisGame2 > buttonDebounce) {
        if (Button2States[i] != Button2LastStates[i]) {
          if (Button2States[i] == 0) {
            buttonPressed2[i] = 1;
            startMillisGame2 = currentGameMillis;
          }
        }
        Button2LastStates[i] = Button2States[i];
      }
    }

    float lightSwitchDebounce = 250;

    switch (randomLight2) {
      case 1:
        //Serial.println("lightNumber1" + String(randomLight));
        digitalWrite(Light21, LOW);
        digitalWrite(Light22, LOW);
        digitalWrite(Light23, LOW);
        digitalWrite(Light24, HIGH);

        if (buttonPressed2[1] == 1 || buttonPressed2[2] == 1 || buttonPressed2[3] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch2 > lightSwitchDebounce) {
            Serial.println("P2Wrong");
            startMillisGameSwitch2 = switchMillis;
          }
          //randomLight = random(2, 5);
        }
        else if (buttonPressed2[0] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch2 > lightSwitchDebounce) {
            randomLight2 = random(2, 5);
            Serial.println("P2Check");
            startMillisGameSwitch2 = switchMillis;
          }
        }
        break;
      case 2:
        //Serial.println("lightNumber1" + String(randomLight));
        digitalWrite(Light21, LOW);
        digitalWrite(Light22, LOW);
        digitalWrite(Light23, HIGH);
        digitalWrite(Light24, LOW);

        if (buttonPressed2[0] == 1 || buttonPressed2[2] == 1 || buttonPressed2[3] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch2 > lightSwitchDebounce) {
            Serial.println("P2Wrong");
            startMillisGameSwitch2 = switchMillis;
          }
          //randomLight = randomLightRangeOne[random(0, 3)];
        }
        else if (buttonPressed2[1] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch2 > lightSwitchDebounce) {
            randomLight2 = randomLightRangeOne2[random(0, 3)];
            Serial.println("P2Check");
            startMillisGameSwitch2 = switchMillis;
          }
        }
        break;
      case 3:
        //Serial.println("lightNumber1" + String(randomLight));
        digitalWrite(Light21, LOW);
        digitalWrite(Light22, HIGH);
        digitalWrite(Light23, LOW);
        digitalWrite(Light24, LOW);

        if (buttonPressed2[0] == 1 || buttonPressed2[1] == 1 || buttonPressed2[3] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch2 > lightSwitchDebounce) {
            Serial.println("P2Wrong");
            startMillisGameSwitch2 = switchMillis;
          }
          //randomLight = randomLightRangeTwo[random(0, 3)];
        }
        else if (buttonPressed2[2] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch2 > lightSwitchDebounce) {
            Serial.println("P2Check");
            randomLight2 = randomLightRangeTwo2[random(0, 3)];
            startMillisGameSwitch2 = switchMillis;
          }
        }
        break;
      case 4:
        //Serial.println("lightNumber1" + String(randomLight));
        digitalWrite(Light21, HIGH);
        digitalWrite(Light22, LOW);
        digitalWrite(Light23, LOW);
        digitalWrite(Light24, LOW);

        if (buttonPressed2[0] == 1 || buttonPressed2[1] == 1 || buttonPressed2[2] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch2 > lightSwitchDebounce) {
            Serial.println("P2Wrong");
            startMillisGameSwitch2 = switchMillis;
          }
          //randomLight = random(1, 4);
        }
        else if (buttonPressed2[3] == 1) {
          float switchMillis = millis();
          if (switchMillis - startMillisGameSwitch2 > lightSwitchDebounce) {
            Serial.println("P2Check");
            randomLight2 = random(1, 4);
            startMillisGameSwitch2 = switchMillis;
          }
        }
        break;
    }
    for (int i = 0; i < 4; i++) {
      buttonPressed2[i] = 0;
    }
  }
}

void MenuScreen() {
  digitalWrite(Light11, HIGH);
  digitalWrite(Light12, LOW);
  digitalWrite(Light13, LOW);
  digitalWrite(Light14, HIGH);
  digitalWrite(Light21, HIGH);
  digitalWrite(Light22, LOW);
  digitalWrite(Light23, LOW);
  digitalWrite(Light24, HIGH);
  digitalWrite(BigLight1, HIGH);
  digitalWrite(BigLight2, HIGH);

  int buttonDebounce = 20;
  //Player 1 input check
  BigButton1State = BigButton1input;
  if (BigButton1State != BigButton1LastState) {
    if (BigButton1State == 0) {
      float bigCurrentMillis1 = millis();
      if (bigCurrentMillis1 - startMillisMenu > buttonDebounce) {
        Serial.println("ok1");
        Serial.println("StartGame");
        startMillisMenu = bigCurrentMillis1;
      }
    }
  }
  BigButton1LastState = BigButton1State;

  for (int i = 0; i < 4; i++) {
    Button1States[i] = buttonInput1[i];
    if (Button1States[i] != Button1LastStates[i]) {
      if (Button1States[i] == 0) {
        float currentMillis = millis();
        if (currentMillis - startMillisMenu > buttonDebounce) {
          Serial.println("button1" + String(i + 1));
          startMillisMenu = currentMillis;
        }
      }
    }
    Button1LastStates[i] = Button1States[i];
  }

  //Player 2 input check
  BigButton2State = BigButton2input;
  if (BigButton2State != BigButton2LastState) {
    if (BigButton2State == 0) {
      float bigCurrentMillis2 = millis();
      if (bigCurrentMillis2 - startMillisMenu > buttonDebounce) {
        Serial.println("ok2");
        startMillisMenu = bigCurrentMillis2;
      }
    }
  }
  BigButton2LastState = BigButton2State;

  for (int i = 0; i < 4; i++) {
    Button2States[i] = buttonInput2[i];
    if (Button2States[i] != Button2LastStates[i]) {
      if (Button2States[i] == 0) {
        float currentMillis2 = millis();
        if (currentMillis2 - startMillisMenu > buttonDebounce) {
          Serial.println("button2" + String(i + 1));
          startMillisMenu = currentMillis2;
        }
      }
    }
    Button2LastStates[i] = Button2States[i];
  }
}


void IdleScreen(float idleSpeed) {

  if (BigButton1input == 0 || BigButton2input == 0) {
    //GameMode = "Menu";
    Serial.println("MenuOpen");
  }

  float currentMillis = millis();
  if (currentMillis - startMillisIdle > idleSpeed) {
    ledCounter = ledCounter + 1;
    if (ledCounter > 4) {
      ledCounter = 1;
    }
    startMillisIdle = currentMillis;
  }
  switch (ledCounter) {
    case 1:
      digitalWrite(Light11, HIGH);
      digitalWrite(Light12, LOW);
      digitalWrite(Light13, LOW);
      digitalWrite(Light14, LOW);
      digitalWrite(Light21, LOW);
      digitalWrite(Light22, LOW);
      digitalWrite(Light23, LOW);
      digitalWrite(Light24, HIGH);
      digitalWrite(BigLight1, HIGH);
      digitalWrite(BigLight2, LOW);
      break;
    case 2:
      digitalWrite(Light11, LOW);
      digitalWrite(Light12, HIGH);
      digitalWrite(Light13, LOW);
      digitalWrite(Light14, LOW);
      digitalWrite(Light21, LOW);
      digitalWrite(Light22, LOW);
      digitalWrite(Light23, HIGH);
      digitalWrite(Light24, LOW);
      digitalWrite(BigLight1, HIGH);
      digitalWrite(BigLight2, LOW);
      break;
    case 3:
      digitalWrite(Light11, LOW);
      digitalWrite(Light12, LOW);
      digitalWrite(Light13, HIGH);
      digitalWrite(Light14, LOW);
      digitalWrite(Light21, LOW);
      digitalWrite(Light22, HIGH);
      digitalWrite(Light23, LOW);
      digitalWrite(Light24, LOW);
      digitalWrite(BigLight1, LOW);
      digitalWrite(BigLight2, HIGH);
      break;
    case 4:
      digitalWrite(Light11, LOW);
      digitalWrite(Light12, LOW);
      digitalWrite(Light13, LOW);
      digitalWrite(Light14, HIGH);
      digitalWrite(Light21, HIGH);
      digitalWrite(Light22, LOW);
      digitalWrite(Light23, LOW);
      digitalWrite(Light24, LOW);
      digitalWrite(BigLight1, LOW);
      digitalWrite(BigLight2, HIGH);
      break;
  }
}


  void EndScreen(float idleSpeed) {


  if (BigButton1input == 0 || BigButton2input == 0) {
    GameMode = "Idle";
    Serial.println("Restart");
  }


  float currentMillis = millis();
  if (currentMillis - startMillisIdle > idleSpeed) {
    ledCounter = ledCounter + 1;
    if (ledCounter > 4) {
      ledCounter = 1;
    }
    startMillisIdle = currentMillis;
  }
  switch (ledCounter) {
    case 1:
      digitalWrite(Light11, HIGH);
      digitalWrite(Light12, LOW);
      digitalWrite(Light13, LOW);
      digitalWrite(Light14, LOW);
      digitalWrite(Light21, LOW);
      digitalWrite(Light22, LOW);
      digitalWrite(Light23, LOW);
      digitalWrite(Light24, HIGH);
      digitalWrite(BigLight1, HIGH);
      digitalWrite(BigLight2, LOW);
      break;
    case 2:
      digitalWrite(Light11, LOW);
      digitalWrite(Light12, HIGH);
      digitalWrite(Light13, LOW);
      digitalWrite(Light14, LOW);
      digitalWrite(Light21, LOW);
      digitalWrite(Light22, LOW);
      digitalWrite(Light23, HIGH);
      digitalWrite(Light24, LOW);
      digitalWrite(BigLight1, HIGH);
      digitalWrite(BigLight2, LOW);
      break;
    case 3:
      digitalWrite(Light11, LOW);
      digitalWrite(Light12, LOW);
      digitalWrite(Light13, HIGH);
      digitalWrite(Light14, LOW);
      digitalWrite(Light21, LOW);
      digitalWrite(Light22, HIGH);
      digitalWrite(Light23, LOW);
      digitalWrite(Light24, LOW);
      digitalWrite(BigLight1, LOW);
      digitalWrite(BigLight2, HIGH);
      break;
    case 4:
      digitalWrite(Light11, LOW);
      digitalWrite(Light12, LOW);
      digitalWrite(Light13, LOW);
      digitalWrite(Light14, HIGH);
      digitalWrite(Light21, HIGH);
      digitalWrite(Light22, LOW);
      digitalWrite(Light23, LOW);
      digitalWrite(Light24, LOW);
      digitalWrite(BigLight1, LOW);
      digitalWrite(BigLight2, HIGH);
      break;
  }

}

Soldering & Making the Wooden Case

IMG_7466.jpg
IMG_7536 cop4545y.png
sketch_bb.png
IMG_7525 copy.png
buitenkant afmetingen.png
binnenkantV3.png
controller afmetingen.png
BCA382AB-B71B-4E49-81E5-3DEF19FE5F38.jpg

This is the first time I'm ever doing something like this and I honestly have no idea where to start.

Luckily my teachers at school pointed me in the right direction and taught me about laser cutting.

I never knew what a laser cutter even did before this and if I was ever going to be capable enough to even touch one, but apparently I totally can. It isn't even that hard. You load in a file with Vector lines and it cuts or engraves the exact lines perfectly.

I cut out the exact proportions and holes needed for the buttons with the laser cutter using the 3MM MDF, I also cut the bottom square and engraved the logo while I was at it.

I used a DXF file I made in illustrator with the exact size in MM and the laser cutter software automatically loaded it in in the right size.

For the sides I bought the cheapest wooden planks I could find at the nearest store that were the right size.

I couldn't find planks exactly in the right size of course so I had to manually cut them in 4 pieces with a wood saw. Luckily my dad has all the equipment I needed for this.

Before putting it together I soldered all the cables and resistors to make it more definitive.

I couldn't risk putting a breadboard in the wooden case, because a cable can easily go loose while travelling.

I made a schematic using the software Fritzing and it quickly became impossible to make a clear organized picture but I tried.

I used PCB and spend two whole days soldering all of it because there are so many cables in different colors and I couldn't mess any of them up or it wouldn't work.

I ended up soldering all the - cables together because they all need to go to the ground anyway and put a shrinkwrap around it I made stick with a heat gun.

Pretty often I soldered a cable to the wrong place and I found an easy way to fix it was just cutting through the cables and soldering them to the end of the right cable instead and making it stick with a shrinkwrap and the heat gun.

After finishing and being really proud of myself I heard I literally didn't need the big PCB and I could have just soldered the cables for the small buttons directly to the needed resistor and that'd be it.

I wasted a lot of time soldering it on a PCB but hey I became better at soldering because of it.

Before going any further I tested it if still works. Because it's very easy to mess up soldering.

Every button worked except for one which apparently was soldered wrong so I fixed that and after that it worked!

I also ran into the problem that I connected one of the big buttons to pin number 52 on the Arduino Mega which is apparently a special pin because it just doesn't work on pin number 52.

On pin number 47 it works fine. So that's something to keep in mind if you can't figure out why it's not working.

When everything was properly soldered I put the buttons in and tied up all the cables using tie rips. I put tape over the Arduino because I didn't want to do any soldering on the Arduino, since it's an expensive thing and I want to use it for different projects in the future. Everything else is soldered tight.

I used very tiny screws to screw the Arduino on as well as the PCB and I used small pieces of old MDF with a little hole in it to wrap the tie rips through. (If that makes sense) so the cables wouldn't move around and I would have enough space on the outside and inside for the wooden planks.

This was my dad's idea because he saw me struggling with the messy cables that went all over the place (thanks dad).

So I put the pieces together and it all fit pretty much perfectly! I(f you don't look too hard at the edges and corners)

A hard part was screwing in the monitor. I used a small part of a wooden plank I had left to screw onto the back side of the monitor. Luckily enough (I didn't even realize how lucky this is) the monitor has 4 screw openings for a mount on the back which I could perfectly use to screw it onto the wood.

I measured it precisely and screwed in the screws, glewed the thing inside the case and I successfully put a monitor in the case.

I also made a hole in one of the sides with a big drill for the cables to go out. The monitor has of course a power cable, a HDMI cable going out and the Arduino has a USB cable going out.

To reinforce the case I put in screws on the sides and on top with a drill and to get the screws to fit perfectly inside without sticking out. For that I used something called a countersink. At least that's what I think it's called in English.

It creates a smooth hole for the screw head.

There were a lot more little challenges I ran into during this process, like how long I needed to strip the wires and at some point I bought new cables because the old ones would break way too easily. I realized way too late the big buttons have extra little plastic pins that require extra little holes in the MDF before I can put them in so I had to make those holes manually and I used a marker on the plastic pins to get the exact location where I needed to make holes (literally by just pressing the buttons on the MDF, which leaves little dots because of the marker).

But I won't go into all of the little problems I ran into because this post is already way too long.

Making the case was really hard and looking at the end result being literally just a square wooden thing with a monitor makes me laugh.

The result really doesn't show how hard it is to make this simple looking wooden box.

But it's sturdy and it works!

Final Result

expo.jpg

So I finally finished everything and I forgot one major thing.

The whole thing is really heavy.

I had an extremely hard time walking with it to the train station and bringing it to school but I managed and people played it and really enjoyed it!

I noticed different people figured out different play styles and got really competitive and had a great time.

Reflection

I'm really proud of the end result and I have learned a huge amount of stuff about soldering, wood, Arduino, Unity and a lot of little things that help me in so many ways.

I feel like the door of custom controllers and custom input for my own games has now been opened and I'm excited to create cooler projects in the future.

The biggest problems in the end were some of the design decisions.

Something almost everyone who played it told me was that you never look at the actual game, because you are too busy looking at the buttons that light up.

This is a really obvious thing I should have realized earlier because this makes the game a lot less fun, since you can't actually see if you are winning or not and see any of the cool effects I made cause you don't want to lose seconds looking a away from your buttons.

I should have added lights on the screen as well so you can look at the screen and looking at the buttons isn't necessary. The only downside to that is that the button LED's become pointless.

So all in all, big oversight on my part. I spent so much time working on making the game work and finishing the whole thing and the wooden case that game design became less of a priority.

Next project I'm going to focus more on important design decisions and run more tests before continuing. Making a cardboard prototype was smart, but the cardboard version didn't have a race game accompanying it so looking at the buttons didn't matter. I was so busy finishing the final version I forgot to do proper tests and evaluate the game design again with the actual race game and monitor attached.

I also got feedback about my UI (the end screen still wasn't optimized for 2 players looking from 2 sides).

But in the end I get goosebumps thinking about all the people that played it and enjoyed it. This is the first time I ever made something as complete as this and a game people actually could pick up and play.

I'm confident my next project will be even better!

Thanks for reading!!