——– Interactive Project ——–
For my project I wanted to prototype a game on the Arduino and make something interactive for people to enjoy. At first, I was going to do an installation where two people would play a game, but I wanted to do something a little different than a game on display. After looking at examples of wearables I decided to do something along the lines of a game on a shirt or a sweater. At that time the idea for the prototype was just to get the game working and trying to find a suitable piece of clothing where the screen and wires could be attached to. I settled for a 16×16 LED Matrix and a safety vest as my choice of materials.
Material list for Prototype
- Safety Vest
- LED Matrix
- Arduino Uno
- Alligator Clips
- Breadboard
- Solderless Jumper Cables
- 2 Axis Joystick
Original Snake game code source – https://create.arduino.cc/projecthub/vasiljevalentin/snake-led-16×16-matrix-game-27ba6d
I found the snake game code and spent the majority of this first part of prototyping making sure that the both the LED Matrix and joystick worked as intended. The game had a few bugs that got sorted out such as the snake game not resetting properly, and the controls being reversed. The last thing I tried to do at this stage was to adjust the code, so it worked on the playground express but for whatever reason it didn’t work properly (See video 1). Overall, all the components at this stage fit on the vest and I was ready to incorporate more into the project.
Video 1
——– Final Project ——–
For my final project I wanted to take my prototype and make it into a more complete piece by adding components that would make the wearable interactive for both the person wearing the vest and the person playing the game. This would create a dynamic where the player wearing the vest and trying to escape being eaten would play the part of “prey” and the other would be the “predator” or snake trying to eat the food in game.
Remaining Materials Needed
- Fake plant foliage
- Fake moss
- Bark textured paper
- Push button switch
- Potentiometer
- Protoboard
- Electrical wire
- Cable cutter
- Cable stripper
- Electrical tape
- Portable battery
- Soldering iron + solder
- Velcro
- Hot glue
Step 1 – extra code
Reconfigure parts of the snake game code in order to work with the potentiometer and button in order to add input.
For the button to work as input to move the food, an “if” statement that runs the food spawn code if the button state is high is needed to be put into the loop function.
For the potentiometer to increase and decrease the snakes speed, mapping the analog pin voltage reading to the snake speed will give a reading appropriate to the voltage reading the potentiometer gives.
Step 2 – setup
Wire the components on a breadboard to test and make sure that the components all work as intended. In order to be efficient with space, the wires should be set up in a parallel circuit for power to accommodate for space. The analog/digital wires should also be wired through the breadboard for the same reason.
Step 3 – soldering
Once everything works, start soldering each component on the protoboard with a short cable first so that attaching to the vest with Velcro can be easier. Fit the protoboard and Uno in the middle of the vest with velcro.
Step 4 – cable management
Begin wiring each component to the protoboard depending on the desired length of where the physical input is going to be on the vest.
Step 5 – screen
Attach the LED Matrix to the back and hot glue a cover around the matrix in order to weld it in place, connect and solder the pins to the protoboard.
Step 6 – decoration/start
Decorate the exterior with the fake tree bark and foliage and then connect the board to the portable battery to initialize the game.
Video demonstration
Code
#include <FastLED.h> // Include outside libraries
//Extra Inputs
const int buttonPin = 7;
int buttonState = 0;
//matrix settings
#define NUM_LEDS 256 // number of led present in your strip
#define DATA_PIN 3 // digital pin of your arduino
#define BRIGHTNESS 8
//joystick settings
#define pinX A4 // Joystick X axis
#define pinY A3 // Joystick Y axis
#define swPin 2 // Joystick button
int snake[256]; // array of snake elements
int snakeSize = 4; // real snake size
int motorPin = A0;
//int snakeSpeed = 500; // speed
int row; // row number
int col; // column number
int lastDirection = 135; // start direction
int i, newDirection, OlddX = 1, OlddY, f;
int red, green, blue, fred, fgreen, fblue; // colors
CRGB leds[NUM_LEDS];
///////////////////////////////////
void setup() {
pinMode(buttonPin, INPUT);
red = random(0, 255);
green = random(0, 255);
blue = random(0, 255);
fred = random(127, 255);
fgreen = random(127, 255);
fblue = random(127, 255);
Serial.begin(9600);
pinMode(pinX, INPUT); // configures pin to behave as input or output
pinMode(pinY, INPUT);
pinMode(swPin, INPUT);
digitalWrite(swPin, HIGH);
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS); // matrix brightness
for ( i = 0; i <= 255; i++ ) {
snake[i] = 0;
}
for ( i = 0; i <= snakeSize; i++ ) {
snake[i] = lastDirection + i;
}
f = random(0, 255); // food location spawn function // original code
FastLED.show();
}
///////////////////////////////////////
int Snakedirection(int last, float dX, float dY ) {
//int Snakedirection(int last, int dX, int dY ) { // movement
dX = map(dX, 0, 1000, -1, 1);
dY = map(dY, 0, 1000, -1, 1);
//No input, direction unchanged.
if (dX == 0 && dY == 0 && OlddX != dX) {
dX = OlddX;
}
if (dY == 0 && dX == 0 && OlddY != dY) {
dY = OlddY;
}
int newDirection = last;
// Left/right input (1/-1)
if ( dX != 0 ) { // moving in X direction
if ( row & 1 ) { // Odd row
if ( col == 0 && dX == 1) {
newDirection = last – 15;
}
else if ( col == 15 && dX == -1) {
newDirection = last + 15;
}
else newDirection = last + dX; // Even Row
} else {
if ( col == 0 && dX == 1) {
newDirection = last + 15;
}
else if ( col == 15 && dX == -1 ) {
newDirection = last – 15;
}
else newDirection = last – dX; // Not even
}
}
// Up/down input (1/-1)
if ( dY < 0) { // moving in Y DOWN direction
if (row == 15 && dY == -1) {
newDirection = col;
}
else if ( row & 1 ) {
newDirection = last + (col * 2) + 1; // Even
} else {
newDirection = last + (16 – col – 1) + (16 – col); // Not even
}
}
if ( dY > 0) { // moving in Y UP direction
if ( row == 0 && dY == 1) {
newDirection = 255 – col;
}
else if ( row & 1 ) {
newDirection = last – (last – 16 * row) – (16 – col); // Even
} else {
newDirection = last – (col * 2) – 1; // Not even
}
}
OlddX = dX;
OlddY = dY;
return newDirection;
}
////////////////////////////////////
int snakeMove(int snakeDirection) {
for ( i = 0; i <= 255; i++ ) {
if ( snake[i] == snakeDirection ) { // if snake touches snake it dies
death();
}
}
FastLED.clear();
for (i = snakeSize; i >= 1; i–) { // reset snake size back to two
snake[i] = snake[i – 1];
}
snake[0] = snakeDirection;
for ( i = 0; i <= 255; i++ ) {
if ( snake[i] ) {
leds[snake[i]].setRGB(red, green, blue);
}
}
FastLED.show();
row = (int)(snakeDirection / 16); // row number
if ( row & 1 ) {
col = (row + 1) * 16 – snakeDirection – 1;
} else {
col = snakeDirection – row * 16;
}
return snakeDirection;
}
//////////////////////////////////////
void food( int eaten ) { // eat food, gain one pixel size and increase speed
if ( eaten == f ) {
snakeSize++; // snake gets bigger
f = random(0, 255); // new food spawn
red = fred;
green = fgreen;
blue = fblue;
fred = random(0, 255);
fgreen = random(0, 255);
fblue = random(0, 255);
//snakeSpeed = snakeSpeed / 1.1; // speed increase
} else {
leds[f].setRGB(fred, fgreen, fblue);
FastLED.show();
}
}
////////////////////////////////////////////
void death() { // death funtion after snake dies, resets game automatically
for ( i = 0; i <= 255; i++ ) {
snake[i] = 0;
}
snakeSize = 4;
//snakeSpeed = 500;
red = 255;
green = 0;
blue = 0;
}
/////////////////////////////////////////////////
void color(boolean sw) { // clicking joystick changes snake color
if (!sw) {
red = random(0, 255);
green = random(0, 255);
blue = random(0, 255);
}
}
//////////////////////////////////
void loop() { // snake movement based on joystick input?
buttonState = digitalRead(buttonPin);
int sensorValue = analogRead(A5);
// float voltage = sensorValue * (5.0 / 1023.0);
float voltage = sensorValue;
//voltage = map(voltage,0,5,0,500);
voltage = map(voltage, 0, 1023, 0, 500);
int snakeSpeed = voltage; // speed on dial
color( digitalRead(swPin) );
newDirection = Snakedirection(lastDirection, analogRead(pinX), analogRead(pinY));
lastDirection = snakeMove(newDirection);
food(newDirection);
if (buttonState == HIGH) {
f = random(0, 255);
}
Serial.println(voltage);
delay(snakeSpeed);
}