Skip to content

SnakeOut v0.9

Published: at 11:13 PM

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:

  Video Plug schematic. SYNC, VIDEO and GND are respectively 9,7 and GND on the arduino UNO

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
  }
 }

Previous Post
Simple streamgraph Code sample
Next Post
Rainmeter Skin: Daily Quote