8x8 Matrix Pong

I only got my Arduino a while ago but don't have many components at the moment to mess about with. Last week I got an 8x8 matrix through the post however, and have been playing with that.

After making some scrolling text, a php script to convert 8x8 images to hex arrays and such I decided I could make a fairly simple implementation of pong using the matrix (http://www.futurlec.com/LED/LEDMS88R.shtml), MAX7221 driver, a potentiometer and my Arduino Duemilanove.
As for the game, it's fairly basic pong. You vs AI (the AI isn't 100% accurate meaning you can win, but not often). The ball speed increases exponentially up to a certain limit to keep round times down. When someone scores 3 rounds the game is over, letting you know the final score and all the game variables are reset.

Here's a little video of it in action:

As you can see, it's not the best; The bat hit detection could be improved, the ball movement could be tweaked and currently the AI is almost impossible to beat.
I definitely need a bigger breadboard too!

I took the scrolling text off it in that example, but it does have a lovely nuke animation when you lose a point which was generated by my php script and friends paint skills.

I'll soon be near a maplins, so I might be able to grab some more components and make something a little more on the useful side in future!

Nice

Yeah that's pretty cool. You got any code for that?

Mowcius

I do have some code, will post it when it's a bit neater though (probably later this evening.)
At the moment it's a big mess of debugging and half-working test code :stuck_out_tongue:
I'll see if I can tidy up the PHP script enough to be generally useful too :slight_smile:

Yeah I have to admit that I often post code up too early when it looks like someone wrote it in their sleep...

Ok cool, I look forward to seeing it.

Mowcius

//Include LED control
#include "LedControl.h"
//Include header to handle text output
#include "font.h"

//New instance of LedControl. d12 = DataIn(1), d11 = CLK(13), 10 = LOAD(12)
LedControl lc=LedControl(12,11,10,1);

//Regulate ball speed
int ballDelayLimit = 500;
int ballDelay = 0;

//Controller Analog input pin
int controller = 0;

//Define byte-map for bat
byte bat = B11100000;

int cval = 0;
int pos = 0;
float epos = 2;
float eskill = 1;
float br = 4;
float bc = 2;
float brr = 1;
float bcc = 1;

//Scores, 0 = you, 1 = enemy
int score[2] = {0, 0};
boolean gameOver = false;

//Setup code
void setup() {
  //Wake up the driver IC
  lc.shutdown(0, false);

  //Set a medium brightness for the LEDs
  lc.setIntensity(0, 8);

  //Clear the display
  lc.clearDisplay(0);

  //Seed random number generator
  randomSeed(analogRead(0));
}


//Game code
void loop(){
  if(gameOver){
    animExplode();
    //Run endgame sequence
    if(score[0] < 3 && score[1] < 3){
      showScores();
    }else{
      showScores();
      endGame();
    }

    //Reset game
    br = (int)random(2, 5);
    bc = (int)random(2, 5);
    brr = 1;
    bcc = 1;
    eskill = 1;
    gameOver = false;
    ballDelayLimit = 500;
    delay(1000);
    lc.clearDisplay(0);
  }else{
    //Read controller value
    cval = analogRead(controller);
    //Map the value
    pos = map(cval, 50, 950, 5, 0);
    //Draw my bat
    drawBat(pos, 0);

    //Update ball position/enemy position with delay
    if(ballDelayLimit == 70){
      eskill = 0.9;
    }
    if(ballDelay > ballDelayLimit){
      //Turn off current ball
      lc.setLed(0, br, bc, false);
      //Make new position
      br = br + brr;
      bc = bc + bcc;
      //Draw the new ball
      lc.setLed(0, br, bc, true);

      //Reset the delay
      ballDelay = 0;

      //Increase ball speed
      ballDelayLimit = max(ballDelayLimit - 0.5, 70);

      //Move the enemy bat
      if(bc < epos){
        epos = epos - eskill;
      }else if(bc > epos+2){
        epos = epos + eskill;
      }

      //Draw enemy bat
      drawBat(epos, 7);

      //Figure out bounces/angles for next draw
      bounce();
    }else{
      ballDelay++;
    }
  }
}

void drawBat(int offset, int row){
  offset = constrain(offset, 0, 5);
  lc.setRow(0, row, bat>>offset);
}

void bounce(){
  //Add bouncing on top/bottom walls (column checks)
  if(bc <= 0){
    bcc = bcc * -1;
  }else if(bc >= 7){
    bcc = 0-bcc;
  }

  //Add bouncing off bats with angles for where on the bat got hit (row checks)
  if(br < 2 && br >= 1 && brr < 0){
    if((int)bc == pos){
      brr = brr * -1;
      if(bcc > 0){
        bcc = bcc * 0.9;
      }else{
        bcc = bcc * 1.1;
      }
    }else if((int)bc == pos+1){
      brr = brr * -1;
    }else if((int)bc == pos+2){
      brr = brr * -1;
      if(bcc > 0){
        bcc = bcc * 1.1;
      }else{
        bcc = bcc * 0.9;
      }
    }
    return;
  }else if(br < 7 && br >= 6 && brr > 0){
    if((int)bc == epos){
      brr = 0-brr;
      if(bcc > 0){
        bcc = bcc * 0.9;
      }else{
        bcc = bcc * 1.1;
      }
    }else if((int)bc == epos+1){
      brr = 0-brr;
    }else if((int)bc == epos+2){
      brr = 0-brr;
      if(bcc > 0){
        bcc = bcc * 1.1;
      }else{
        bcc = bcc * 0.9;
      }
    }
    return;
  }

  //Check for losers
  if(br < 0){
    //Game over, you lose
    score[1] = score[1]+1;
    gameOver = true;
  }else if(br > 7){
    //Game over, they lose
    score[0] = score[0]+1;
    gameOver = true;
  }
}

I left out the animated bits because it's just extra twiddly bits, and I assume people can guess how the text gets output.

Not really sure if some of that is the best way to do things, but hey, I'm new to the arduino and C.

If people can suggest better ways to do things I'd appreciate it a lot :slight_smile:
Especially a good way to scroll whole words. Scrolling letters on the matrix was fine, but when I tried letter after letter there were big gaps as one letter had to finish scrolling before the next one could start. Should I put the hex arrays of the letters into whole word arrays?
Also, the ball/bat hit detection is astoundingly bad and very much hacked together until it worked, and left that way.
The enemy bat AI is hardly top notch either :frowning:

I'm afraid that I cannot really suggest any better ways to code that because I am new to all this too... Until 2 weeks ago, the only knowledge of coding that I had was minimal HTML.

I have to say though that that code seems better looking than any of my code still... :smiley:

Have you thought of coding any other games and then having a button input to change game at startup?

Mowcius

I've coded other stuff before, but not in C and not direct for hardware either. So some things are a bit confusing, but I managed.

Not sure about other games really. A monochrome 8x8 LED matrix isn't the best display I don't think. I can't think of many other games that would translate well to a tiny mono display. Snake perhaps might work?

I also thought of snake but yes it is a bit small for anything else perhaps:

a very small tetris,
mini breaker,
mini game of life,
helecopter,
mario (i've seen this somewhere but can't remember where)

Not very practical for playing games I suppose... :slight_smile:

Mowcius

SOmewhere on the interwebnet is a video of a complete donkey kong game on an 8x8 matrix. It's pretty darned cool.

Yes, I think I have seen that also...

The thing is, apart from the sound, it could be absolutely any game like that because it's not as if you can pick out the shape of donkey kong in one pixel... :smiley:

Mowcius

Yeah but even if you didn't know what it was you could have guess edi t was Donkey Kong.

Eithr that or 'Chuckey Egg' - remember that? (i'm showing my age now)

nope, I'm afraid that anything before 1990s i got no idea about...

Mowcius

:-[

It was a game on the ZX Spectrum that was a blatant rip-off of Donkey Kong. Before that I had a ZX81 with a 16K Ram Pack :slight_smile: (You haven't got a clue what I am saying do you?)

I know what a ZX spectrum is... How could I not? :smiley:

I have never had one... But I know what it is...

The first games console I had was an original Game Boy... Similar in graphics... I also had donkey kong on that...

Mowcius

Still got mine in the attic. Spectrum +3. As well as a ZX81, Dragon 64 and an Amiga.

You said you did an 8x8 scrolling text. Would you have some code for that by any chance? I've been trying to use a Max7221 but I can't get it to work. Any help would be nice.

The 8x8 scrolling text was done with a PHP script to convert 8x8 images into C byte arrays:

byte A[8]={0x0, 0x0, 0x7e, 0x90, 0x90, 0x90, 0x7e, 0x0};
byte B[8]={0x0, 0x0, 0xfe, 0x92, 0x92, 0x92, 0x6c, 0x0};
byte C[8]={0x0, 0x0, 0x7c, 0x82, 0x82, 0x82, 0x44, 0x0};

Here's the PHP code:

<?php
      $strImgFolder = './font'; //Relative to the php script

      if ($handle = opendir($strImgFolder)) {
            while(false !== ($file = readdir($handle))){
                  if(substr($file, -3) == 'gif'){ // I used gif images
                        $aryFiles[] = $strImgFolder . '/' . $file;
                  }
            }
            closedir($handle);
      }

      function is_dark($xx, $yy, $im){
            $rgb = imagecolorat($im, $xx, $yy);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            if($r == 0 && $g == 0 && $b == 0){
                  return true;
            }else{
                  return false;
            }
      }

      foreach($aryFiles as $strFile){
            $image = @imagecreatefromgif($strFile);
            echo 'byte ' . substr($strFile, 0, -4) . '[8]={';
            for ($x = 0; $x <= 7; $x++) {
                  $line = '';
                  for ($y = 0; $y <= 7; $y++) {
                        if(is_dark($x, $y, $image)){
                              $line .= '0';
                        }else{
                              $line .= '1';
                        }
                  }
                  echo '0x' . base_convert($line, 2, 16);
                  if($x < 7){
                        echo ', ';
                  }
            }
            echo "};\r\n";
      }
?>

The is_dark function was used over a simple colour to colour match because at one point I was using aliased images and wanted to have more control on the threshold of what was dark enough with the rgb values.

To have scrolling text, all I did was append the byte arrays of the letters that made up the word I wanted into a new array, occasionally tweak it by hand due to kerning issues.
Then it's just a loop going through the bytes in the array, moving each column to the left and putting them one by one into the rightmost column of your LED matrix.

To get it to look good you do have to add in delays and tweak the loop conditions so it doesn't loop again too soon and so on.

Hope that makes sense and helps you a bit :slight_smile:

Hi, I am a noob and am trying to leaen to make things exactly like this. I was wondering if there was any way to show us how the display was hooked up to the Arduino. Thank you

Looks like shift registers are used maybe.

I'm currently working on a permanent (i.e. not breadboard) 8*16 RG matrix led "shield".
I use quotes because it actually is 3 protoboards, one with 6 shift registers, one with headers for the matrices and sink drivers, and a last one to connect to arduino pins. Maybe i should call it a "super reinforced armor" instead of a shield? :slight_smile:
I'm pretty proud of it because it all has the roughly same footprint as the arduino, except just rectangular. It is about 1&1/2 - 2&1/2 inches tall though.