Pages: [1] 2   Go Down
Author Topic: Snake on a 8x8 led matrix  (Read 9122 times)
0 Members and 1 Guest are viewing this topic.
the Netherlands
Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-razz
All in all, even before I ordered it, I knew what I wanted to make.

Snake on a dotmatrix smiley-grin

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 smiley

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 smiley-razz)

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
« Last Edit: February 08, 2010, 05:38:42 pm by Blammers » Logged

the Netherlands
Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
#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();
}
« Last Edit: February 08, 2010, 05:30:14 pm by Blammers » Logged

Nowhere
Offline Offline
God Member
*****
Karma: 3
Posts: 852
|-\ |\|\
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Soundcloud page: http://soundcloud.com/beefinator-2
Youtube channel: http://www.youtube.com/user/beefinator14
Old soundcloud page (ran out o

ottawa, canada
Offline Offline
God Member
*****
Karma: 5
Posts: 989
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
« Last Edit: February 08, 2010, 09:01:18 pm by bill2009 » Logged

Lincoln, NE
Offline Offline
Full Member
***
Karma: 0
Posts: 105
Having lots of fun with Arduino. Thanks everyone!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

the Netherlands
Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-wink
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 smiley-razz)
secret 3) To learn. It's my first build in a long time, so a big part of it was curiosity smiley-wink
Logged

Rural Arizona
Offline Offline
Edison Member
*
Karma: 7
Posts: 1711
Incorrigible tinkerer
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So,  are you going to do a second display,  and have it put up an animation of a plane?   smiley-wink
Logged

the Netherlands
Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Nowhere
Offline Offline
God Member
*****
Karma: 3
Posts: 852
|-\ |\|\
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Soundcloud page: http://soundcloud.com/beefinator-2
Youtube channel: http://www.youtube.com/user/beefinator14
Old soundcloud page (ran out o

Norway
Offline Offline
Sr. Member
****
Karma: 4
Posts: 423
microscopic quantum convulsions of space-time
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, really nice work! I love it!  smiley
Logged

0
Offline Offline
Full Member
***
Karma: 0
Posts: 107
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Great Game - Do you have a schematic? smiley
Logged

Wigan, UK
Offline Offline
God Member
*****
Karma: 18
Posts: 814
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley
Logged

Netherlands
Offline Offline
Full Member
***
Karma: 0
Posts: 132
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

QBasic brings back memories smiley-grin. Nice work on the snake game on the dotmatrix display.

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

0
Offline Offline
Newbie
*
Karma: 0
Posts: 10
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Where can i see the full diagram and circuit plans?
Logged

Pages: [1] 2   Go Up
Jump to: