I want to share my first stable version of Snake for Arduino with the internet. As I said in an earlier post, this version of Snake does not need an Extra shield for your Arduino, it only needs a video plug, and 2 resistors (like the schematic below).
For testing purposes, controls are via a processing sketch, so every enthusiast is able to control the snake, without hacking a game pad first… I will present the code for both the game and the processing sketch below, in a format that is (hopefully) readable and understandable.
Schematic
The schematic is made by the same people who made it possible to do TVout on the arduino:
Instructions
Install the TVOut Library
Create a new Arduino sketch with the code below
Create a new Processing sketch with the code below (do not forget to change the comport)
And one last thing; In the PollSerial.cpp library file (libraries/pollserial), change line 30 from
#define BUFFER_SIZE 64
into
#define BUFFER_SIZE 8
Arduino couldn’t handle this big buffer altogether with the video stuff, and with this smaller buffer it is responding really good 🙂
Arduino sketch
\*
Snake for Arduino Snake Game with output via a video plug using the TVOut library. A Processing sketch is used to send key commands to let the snake move, but this can easily be replaced by physical buttons in next versions The circuit: \* Video Plug Connected to Pin 7,9 and GND created 2011 by Pepijn Fens V0.9: First stable version \*/
#include <TVout.h>
#include <fontALL.h>
#include <pollserial.h>
#define memory 25 TVout TV;
pollserial pserial;
byte vres = 120;
byte hres = 104;
byte x = vres/2;
byte y = hres/2;
byte xfield,yfield,wfield,hfield;
byte dx,dy,dir;
byte tailx,taily,taildx,taildy;
byte taildir;
byte bend_x[memory];
byte bend_y[memory];
byte bend_dir[memory];
byte i,j;
//bend index from the head and tail
int score; int foodx,foody;
void setup(){
TV.begin(PAL,hres,vres);
TV.select_font(font4x6);
TV.set_hbi_hook(pserial.begin(57600));
TV.print(5,2,"score ");
initialize(); } void loop() {
char buf = 0;
if (pserial.available()) {
buf = (char) pserial.read();
pserial.flush();
}
switch(buf){
case 'U': if (dir != 'D') {dx=0; dy=-1; dir='U'; addBend(dir);} break;
case 'D': if (dir != 'U') {dx=0; dy=1; dir='D';
addBend(dir);
} break;
case 'R': if (dir != 'L') {dx=1; dy=0; dir='R';
addBend(dir); } break;
case 'L': if (dir != 'R') {dx=-1; dy=0; dir='L';
addBend(dir); } break;
}
if (dir!=0){
if (tailx == bend_x[j] && taily == bend_y[j]) {
taildir = bend_dir[j];
j++;
if (j >= memory) { j=0; } //go searching for the next bend in the snake, and so on
}
switch(taildir) {
case 'U': taildx=0; taildy=-1; break;
case 'D': taildx=0; taildy=1; break;
case 'R': taildx=1; taildy=0; break;
case 'L': taildx=-1; taildy=0; break;
case 'O': taildx=0; taildy=0; break;
}
moveTail();
moveHead();
} }
void moveHead(){
x += dx;
y += dy;
boolean border = false;
if (x > xfield+wfield-1 ) { x = xfield+1; border=true;}
if (x < xfield+1 ) { x =xfield+wfield-1; border=true;}
if (y > yfield+hfield-2) {y = yfield+1; border=true;}
if (y < yfield+1 ) {y =yfield+hfield-1; border=true;}
if (x == foodx && y == foody) {grow(); border=true;}
if (TV.get_pixel(x,y) == 1 && border==false ){
gameover();
}
TV.set_pixel(x,y,1);
delay(1000/30); //FPS } void moveTail(){
tailx += taildx;
taily += taildy;
if (tailx > xfield+wfield-1 ) { tailx = xfield+1;}
if (tailx < xfield+1 ) { tailx =xfield+wfield-1;}
if (taily > yfield+hfield-2) {taily = yfield+1;}
if (taily < yfield+1 ) {taily =yfield+hfield-1;}
TV.set_pixel(tailx,taily,0); } void addBend(char direction) { bend_dir[i]=direction; bend_x[i] = x; bend_y[i] = y; i++; if (i >= memory) { i = 0; } } void grow() {
score += 10;
drawscore();
newfood();
moveHead();
moveHead(); } void newfood() {
foodx = random(xfield+5,xfield+wfield-5);
foody = random(yfield+5,yfield+hfield-5);
TV.set_pixel(foodx,foody,1); } void drawscore() {
TV.print(30,2,score,10); } void gameover() {
dx=0;
dy=0;
taildir='O';
TV.print(50,50,"GAME OVER");
delay(5000); //if Game Over, wait 5 seconds....
initialize(); } void initialize() {
drawscore();
xfield=5; //where the field is on the screen
yfield=10;
wfield=hres-(xfield\*2); //defining dimensions
hfield=vres-15;
TV.draw_rect(xfield,yfield,wfield,hfield,1,0);
TV.set_pixel(x,y,1); //Set middle pixel to white=start
TV.set_pixel(x-1,y,1);
TV.set_pixel(x-2,y,1);
taildir = 'R'; //start with tail to the right
tailx = x-3;
taily = y;
newfood(); //setup first food
dir = 0;
dx = 0;
dy = 0;
i = 0;
j= 0;
score=0;
for (int k=0; k<memory; k++) {
bend_x[k] = 200;
bend_y[k] = 200;
bend_dir[k] = 0;
} }
Processing Sketch
import processing.serial.*; Serial myPort;
// Create object from Serial class int val;
// Data received from the serial port
char tempKey;
void setup() {
tempKey=0;
size(200, 200);
myPort = new Serial(this, "COM19", 57600); //Change COM19 to whatever comport you are using } void draw() {
background(255);
}
void keyPressed() {
println(key);
switch(key){
case 'w': myPort.write('U'); break;//up
case 'a': myPort.write('L'); break; //left
case 's': myPort.write('D'); break; //down
case 'd': myPort.write('R'); break; //right
}
}