Game controller with Arduino
Hi guys!, In my previous post I described how to build a volume controller with Arduino, using the termios API for serial communication in GNU/Linux, well, in this post I use the same concepts to build a simple game controller for the classical game Snake.
Let’s get started
We need to build the following circuit:
We need the following code in wiring to receive instructions from the board.
const int DOWN = 8;
const int LEFT = 6;
const int UP = 10;
const int RIGHT = 12;
const int CONTINUE = 0;
void setup()
{9600);
Serial.begin(
pinMode(DOWN, INPUT);
pinMode(LEFT, INPUT);
pinMode(UP, INPUT);
pinMode(RIGHT, INPUT);
// Pullups(pulldowns?)
digitalWrite(DOWN, HIGH);
digitalWrite(LEFT, HIGH);
digitalWrite(UP, HIGH);
digitalWrite(RIGHT, HIGH);
13, OUTPUT);
pinMode(
}
void loop()
{if (Serial.available() > 0) {
// Light the LED when the game ends
13, HIGH);
digitalWrite(3000);
delay(13, LOW);
digitalWrite(
Serial.read();else {
} if (digitalRead(DOWN) == LOW)
Serial.println(DOWN);else if (digitalRead(LEFT) == LOW)
Serial.println(LEFT);else if (digitalRead(UP) == LOW)
Serial.println(UP);else if (digitalRead(RIGHT) == LOW)
Serial.println(RIGHT);else
Serial.println(CONTINUE);40);
delay(
} }
The previous code reads the button presses and write the appropriate values to the serial channel, we’ll read this values from our game. I have implemented a limited version of the game Snake for our purpose, here is the code:
// Compile with: g++ -Wall -o snake snake.cpp -lcurses
#include <ncurses.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <vector>
using namespace std;
const int MAX_WIDTH = 80;
const int MAX_HEIGHT = 40;
const int DOWN = 8;
const int LEFT = 6;
const int UP = 10;
const int RIGHT = 12;
const int CONTINUE = 0;
const int DELAY = 500 * 1000; // microseconds
int, int> > snake;
vector< pair<bool M[MAX_HEIGHT+5][MAX_WIDTH+5];
int current_direction;
void move(int command)
{int i, size = snake.size();
for (i = size - 1; i > 0; i--) {
1].first;
snake[i].first = snake[i-1].second;
snake[i].second = snake[i-
}
if (command == CONTINUE) {
switch (current_direction) {
case UP:
0].first--;
snake[break;
case RIGHT:
0].second++;
snake[break;
case DOWN:
0].first++;
snake[break;
case LEFT:
0].second--;
snake[break;
};
else {
} switch (current_direction) {
case UP:
if (command == LEFT) {
0].second--;
snake[
current_direction = LEFT;else if (command == RIGHT) {
} 0].second++;
snake[
current_direction = RIGHT;
}break;
case RIGHT:
if (command == UP) {
0].first--;
snake[
current_direction = UP;else if (command == DOWN) {
} 0].first++;
snake[
current_direction = DOWN;
}break;
case DOWN:
if (command == LEFT) {
0].second--;
snake[
current_direction = LEFT;else if (command == RIGHT) {
} 0].second++;
snake[
current_direction = RIGHT;
}break;
case LEFT:
if (command == UP) {
0].first--;
snake[
current_direction = UP;else if (command == DOWN) {
} 0].first++;
snake[
current_direction = DOWN;
}break;
};
}
}
bool contains(const pair<int, int> &point)
{for (int i = 0; i < int(snake.size()); i++)
if (point.first == snake[i].first && point.second == snake[i].second)
return true;
return false;
}
int main(int argc, char** argv)
{struct termios tio;
int tty_fd, command, i, last_r, last_c, star_r, star_c;
char v, ch;
char *device = "/dev/ttyUSB0"; // Your serial device
0));
srand(time(
0,sizeof(tio));
memset(&tio,0;
tio.c_iflag = 0;
tio.c_oflag =
tio.c_cflag = CS8|CREAD|CLOCAL;0;
tio.c_lflag = 1;
tio.c_cc[VMIN] = 5;
tio.c_cc[VTIME] =
tty_fd = open(device, O_RDWR | O_NONBLOCK);
cfsetospeed(&tio,B9600);
cfsetispeed(&tio,B9600);
tcsetattr(tty_fd,TCSANOW,&tio);
command = CONTINUE;
current_direction = RIGHT;2, 1));
snake.push_back(make_pair(MAX_HEIGHT/1;
star_r = rand()%MAX_HEIGHT + 1;
star_c = rand()%MAX_WIDTH + true;
M[star_r][star_c] =
initscr();while (true) {
int size = snake.size();
1].first;
last_r = snake[size-1].second;
last_c = snake[size-
for (i = 0; i < 50; i++) {
0;
command = while (read(tty_fd, &v, 1) > 0) {
if (v == '\n') break;
if (v >= '0' && v <= '9')
10 + v - '0';
command = command *
}if (command != CONTINUE)
break;
}
move(command);
int r = snake[0].first;
int c = snake[0].second;
if (r < 1 || r > MAX_HEIGHT || c < 1 || c > MAX_WIDTH) {
2, MAX_WIDTH/2 - 5);
move(MAX_HEIGHT/
char signal = '1';
1);
write(tty_fd, &signal,
"GAME OVER");
printw(
refresh();
getch();
break;
else {
}
clear();if (M[r][c]) {
false;
M[r][c] =
snake.push_back(make_pair(last_r, last_c));int, int> point(rand()%MAX_HEIGHT + 1, rand()%MAX_WIDTH + 1);
pair<while (contains(point))
1, rand()%MAX_WIDTH + 1);
point = make_pair(rand()%MAX_HEIGHT +
true;
M[point.first][point.second] =
star_r = point.first;
star_c = point.second;
}
for (i = 0; i <= MAX_WIDTH + 1; i++) {
0, i);
move(".");
printw(1, i);
move(MAX_HEIGHT + ".");
printw(
}
for (i = 0; i <= MAX_HEIGHT + 1; i++) {
0);
move(i, ".");
printw(1);
move(i, MAX_WIDTH + ".");
printw(
}
move(star_r, star_c);"*");
printw(
for (i = 0; i < size; i++) {
move(snake[i].first, snake[i].second);"#");
printw(
}
refresh();
}
0;
command = 130000);
usleep(
}
endwin();
close(tty_fd);
return EXIT_SUCCESS;
}
Connect the Arduino to the PC and execute the previous program. Here is a screenshot of the game in action.
Game Over! Until next time.
References
The schematic and the electronic diagram were designed using fritzing.