Go Down

Topic: Snake on a 8x8 led matrix (Read 13041 times) previous topic - next topic

Blammers

Feb 08, 2010, 11:28 pm Last Edit: Feb 08, 2010, 11:38 pm by Blammers Reason: 1
Hey all!

After purchasing a Roboduino Duemilanove from Mike at Earthshine Design, I wanted to dig straight in!

So I did, and with the help of a breadboard, a bundle of wires, and some loose parts, I quickly found out that my electronics knowledge was buried under a big pile of dust :P
All in all, even before I ordered it, I knew what I wanted to make.

Snake on a dotmatrix :D

And to my own surprise, I did!

[media]http://www.youtube.com/watch?v=q0Wz8jydeAo[/media]
The colors are really bad with the current lighting, together with my MacBook camera, but perhaps I can post a better video when daylight returns :)

The snake is red, the head is orange (so you know which way is front) and the goal is to catch the green apple.

Everyone probably knows the game, but just to be sure:
If you hit yourself, you lose. If you eat the apple, you get 1 bodypart longer, and a new apple appears randomly. When hitting a wall, you appear on the other side (some versions, hitting the wall kills you, found that boring :P)

Any feedback is welcome!
Will try to post up my code as well, even though it's not that high-tech.

Oh and before I forget, the partslist:
- Roboduino Duemilanove
- 8x8 red/green led matrix
- 3x 74hc595 shift register
- 100nF capacitors on the vcc of the registers
- 2x uln2803 darlington array (current sinks for the cathodes)
- 8x pn2907 pnp transistors on the anodes
- bunch of resistors (220 and 470 Ohm)
- 2 small switches
- breadboard and jumperwires

Blammers

#1
Feb 08, 2010, 11:29 pm Last Edit: Feb 08, 2010, 11:30 pm by Blammers Reason: 1
Code: [Select]

#include <Bounce.h>
#include <TimerOne.h>

// Snake on a plane.. ehm.. dotmatrix

int latchPin = 12;
int clockPin = 10;
int dataPin = 9;
int button1 = 2;
int button2 = 3;
int numrow = 8;
int numcol = 8;
int mask8 = B11111111;
int row = 0;
int col = 0;
int pixel = 0;
int pointer = 0;
long rowoutput;
long coloutput;
long redoutput;
long greenoutput;
long redoutputrow;
long greenoutputrow;

/*
Colours:
 0 = none
 1 = red
 2 = green
 3 = orange
*/
int empty = 0;
int red = 1;
int green = 2;
int orange = 3;

/*
Directions
 0 = up
 1 = right
 2 = down
 3 = left
*/
int direction = 1;

byte matrix[64];
int snake[64];
int newsnake[64];
int startingpoint = 24; // row 4 col 0
int snakehead = 0;
int oldsnakehead = 0;
int snaketail = 0;
int applecaught = 0;

int apple = 0;

int moveSpeed = 200;

unsigned long lastMillis = 0;

Bounce bouncer1 = Bounce(button1, 10);
Bounce bouncer2 = Bounce(button2, 10);
int button1value = HIGH;
int button2value = HIGH;

void setup() {
 
 randomSeed(analogRead(5));
 
 // set pins to output
 pinMode(latchPin, OUTPUT);
 pinMode(clockPin, OUTPUT);
 pinMode(dataPin, OUTPUT);
 // buttons to input
 pinMode(button1, INPUT);
 pinMode(button2, INPUT);
 
 // Enable internal pullup resistors
 digitalWrite(button1, HIGH);
 digitalWrite(button2, HIGH);
 
 Serial.begin(9600);
 
 resetSnake();
 
 Timer1.initialize(2000);
 Timer1.attachInterrupt(outputDisplay);
 
}

void loop() {
 bouncer1.update();
 bouncer2.update();
 if (bouncer1.read() == LOW) {
   if (button1value == HIGH) {
     prevDirection();
   }
 }
 button1value = bouncer1.read();
 
 if (bouncer2.read() == LOW) {
   if (button2value == HIGH) {
     nextDirection();
   }
 }
 button2value = bouncer2.read();
 
 moveSnake();
}

void resetSnake() {
 // Create empty snake
 for (int i=0; i<64; i++)  {
   snake[i] = -1;
   newsnake[i] = -1;
 }
   
 clearMatrix();
 
 // Add starting dot
 matrix[startingpoint] = orange;
 snakehead = startingpoint;
 snake[0] = snakehead;
 
 generateApple();
 matrix[apple] = green;
 
 direction = 1;
}

void clearMatrix() {
 // Clear matrix
 for (int i=0; i<64; i++)  {
   matrix[i] = 0;
 }
}

void outputDisplay() {
 greenoutputrow = 0;
 redoutputrow = 0;
 
 for (int c = 0; c < numcol; c++) {
   pointer = (row * numcol) + c;
   pixel = matrix[pointer];

   switch(pixel) {
     case 1:
      redoutput = 1 << c;
      greenoutput = 0;
      break;
     case 2:
      redoutput = 0;
      greenoutput = 1 << c;
      break;
     case 3:
      redoutput = 1 << c;
      greenoutput = 1 << c;
      break;
     default:
      redoutput = 0;
      greenoutput = 0;
      break;
   }
   redoutputrow += redoutput;
   greenoutputrow += greenoutput;  
 }
 
 rowoutput = (1 << row) ^ mask8; // 0 = enable row, 1 = disable row, so invert it.
 
 digitalWrite(latchPin, LOW);
 
 shiftOut(dataPin, clockPin, MSBFIRST, greenoutputrow);
 shiftOut(dataPin, clockPin, MSBFIRST, redoutputrow);
 shiftOut(dataPin, clockPin, MSBFIRST, rowoutput);

 digitalWrite(latchPin, HIGH);
   
 nextRow();
}

void moveSnake() {
 
 if (millis() - lastMillis >= moveSpeed) {
   oldsnakehead = snakehead;
   switch(direction) {
     case 0:
      // up
      if ((snakehead - numcol) < 0) {
        snakehead += ((numrow - 1) * numcol);
      }
      else {
        snakehead -= numcol;
      }
      break;
     case 1:
      // right
      if ((snakehead - (snakehead % numcol)) == (((snakehead+1) - (snakehead+1) % numcol))) {
        snakehead += 1;
      }
      else {
        snakehead = snakehead - (numcol - 1); // to start of row
      }
      break;
     case 2:
      // down
      if ((snakehead + numcol) > ((numrow * numcol - 1))) {
        snakehead = snakehead % numcol;
      }
      else {
        snakehead += numcol;
      }
      break;
     case 3:
      // left
      if (snakehead == 0) {
        // exception for topleft, pixel 0
        snakehead += (numcol - 1);
      }
      else if ((snakehead - (snakehead % numcol)) == (((snakehead-1) - (snakehead-1) % numcol))) {
        snakehead -= 1;
      }
      else {
        snakehead += (numcol - 1); // end of row
      }
      break;
     default:
      // wtf?
      break;
   }
   
   // Check if we have the apple
   if (snakehead == apple) {
     // Got it!
     generateApple();
     applecaught = 1;
   }
   
   for (int i = 1; i < 64; i++) {
     if (snake[i] == snakehead) {
       endGame();
     }
   }
   
   newsnake[0] = snakehead;
   for(int n = 0; n < 63; n++) {
     if (snake[n] == -1) {
       snaketail = snake[n-1];
       if (applecaught == 0) {
         newsnake[n] = -1; // undo last, we are moving on
       }
       break;
     }
     newsnake[n+1] = snake[n];
   }
   for(int m = 0; m < 64; m++) {
     snake[m] = newsnake[m];
   }
   
   if (applecaught == 1) {
     generateApple();
     applecaught = 0;
   }
   
   updateMatrix();
   
   lastMillis = millis();
 }
}

void updateMatrix() {
 clearMatrix();
 for (int i = 1; i < 64; i++) {
   if (snake[i] == -1) {
     break;
   }
   matrix[snake[i]] = red;
 }
 matrix[snakehead] = orange;
 matrix[apple] = green;
}

void generateApple() {
 apple = random(64);
 for (int n = 1; n < 64; n++) {
   if (snake[n] == apple) {
     generateApple();
   }
 }
}

void nextRow() {
row++;
if (row >= numrow) {
  row = 0;
}
}

void nextDirection() {
 direction++;
 if (direction > 3) {
   direction = 0;
 }
}

void prevDirection() {
 direction--;
 if (direction < 0) {
   direction = 3;
 }
}

void endGame() {
 for (int i = 0; i < numrow; i++) {
   for (int n = 0; n < numcol; n++) {
     matrix[n + (i * numcol)] = green;
   }
   delay(200);
 }
 delay(4000);
 resetSnake();
}

sciguy

Cool!  I ordered some dotmatrices (?)  from sparkfun, i'm still waiting for something in the order to come in stock.
I got two dotmatrices and the electronics to drive them, and I found a convenient box at staples that can perfectly fit these in the lid, along with a little space for buttons, etc.
Soundcloud page: http://soundcloud.com/beefinator-2
Youtube channel: http://www.youtube.com/user/beefinator14
Old soundcloud page (ran out o

bill2009

#3
Feb 09, 2010, 02:54 am Last Edit: Feb 09, 2010, 03:01 am by bill2009 Reason: 1
hey great - I'm a snakefan and i have a matrix.  Thanks for sharing.

Actually though: explain something if you would.

You have a bunch of shift registers and drivers but, in the end, you're scanning one row at a time - right?  So the leds have a maximum 1/8 duty cycle?

hari

That's cool! Nice clean code too.
Thanks for sharing.

Blammers

Quote

Actually though: explain something if you would.

You have a bunch of shift registers and drivers but, in the end, you're scanning one row at a time - right?  So the leds have a maximum 1/8 duty cycle?


Indeed they have a 1/8 duty cycle max, so the darlington arrays are probably a bit overkill for the situation. Why I did it is because of 2 things.
1) Errors are easily made, and in this situation it will not hurt the setup if I decide to light them all at once by accident. And I am good at accidents ;)
2) These shift registers can sink a little bit of current, but their real job is to do the logic part. I feel that I shouldn't use parts for things they aren't meant to do. (see point 1 again :P)
secret 3) To learn. It's my first build in a long time, so a big part of it was curiosity ;)

Ran Talbott

So,  are you going to do a second display,  and have it put up an animation of a plane?   ;)

Blammers

Haha you're thinking about a side-scrolling shooter? or the game where you have to avoid incoming rocks?

Might just do that.. although I can't really add a second display to this pcb, so would have to create a new one, or at least move the display to a new pcb.

sciguy

How about a snake game with a specific goal
you have the snake game on one screen, and the plane on the other.  As you collect food, you move through the plane til you get to the cockpit.  Muahahahaha.
Soundcloud page: http://soundcloud.com/beefinator-2
Youtube channel: http://www.youtube.com/user/beefinator14
Old soundcloud page (ran out o

raron

Hi, really nice work! I love it!  :)

DeFex

Thats great it reminds me of learning to program with "snakes.bas" (and modifying "gorillas.bas" to have nuclear bananas :D ) silly basic programs that came with windows 3.1

virtualeb

Great Game - Do you have a schematic? :)

CowJam

Quote
Thats great it reminds me of learning to program with "snakes.bas" (and modifying "gorillas.bas" to have nuclear bananas  ) silly basic programs that came with windows 3.1


They were dos games, not windows games. They were still great though :)

Meinaart

QBasic brings back memories :D. Nice work on the snake game on the dotmatrix display.

I have one laying around, should come up with a good purpose for it ;-).

Efi

Where can i see the full diagram and circuit plans?

Go Up