Hackster is hosting Hackster Holidays, Ep. 5: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 5 on Friday!
Mirko Pavleski
Published © GPL3+

Space Invaders Game on 8x8 Homemade LED Matrix

The goal is to defeat wave after wave of descending aliens with a horizontally moving laser to earn as many points as possible.

IntermediateFull instructions provided5,304
Space Invaders Game on 8x8 Homemade LED Matrix

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
LED (generic)
LED (generic)
×64
Resistor 10k ohm
Resistor 10k ohm
×1
Rotary potentiometer (generic)
Rotary potentiometer (generic)
×1
Buzzer
Buzzer
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Schematics

Schematic diagram

Code

Arduino code

C/C++
Binary file (no preview)/*========================================================*/
/*
05-833 Applied Gadgets, Sensors and Activity Recognition in HCI
Class by Scott Hudson
Carnegie Mellon University
Spring 2012

*SpaceVaders* by Elwin Lee
Entertainment Technology Center
Carnegie Mellon University

Credits:
Drive matrix pattern http://arduino.cc/playground/Main/DirectDriveLEDMatrix
Play tones through speaker http://arduino.cc/en/Tutorial/Tone
*/
/*========================================================*/

#include "pitches.h"

/****TESTING****/
byte tempMatrix[8][8] = {  
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0} 
};

/*** Level 1 ***/
#define level1_ani { \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 1, 1, 1}, \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 1, 1}  \
}
#define level1 { \
  {0, 1, 0, 1, 0, 1, 0, 0}, \
  {0, 0, 1, 0, 1, 0, 1, 0}, \
  {0, 1, 0, 1, 0, 1, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}  \
}

/*** Level 2 ***/
#define level2_ani { \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 1, 1}, \
  {1, 1, 0, 1, 1, 0, 0, 1}, \
  {1, 1, 1, 1, 1, 0, 0, 1}, \
  {1, 1, 1, 1, 0, 0, 1, 1}, \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 0, 1}, \
  {1, 1, 0, 0, 0, 0, 0, 1}  \
}

#define level2 { \
  {0, 1, 0, 1, 0, 1, 0, 1}, \
  {0, 0, 1, 0, 1, 0, 1, 0}, \
  {0, 1, 0, 1, 0, 1, 0, 1}, \
  {0, 0, 1, 0, 1, 0, 1, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}  \
}

/*** Level 3 ***/
#define level3_ani { \
  {1, 1, 1, 0, 0, 0, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 0, 1}, \
  {1, 1, 0, 1, 1, 0, 0, 1}, \
  {1, 1, 1, 1, 0, 0, 1, 1}, \
  {1, 1, 1, 1, 0, 0, 0, 1}, \
  {1, 1, 0, 1, 1, 0, 0, 1}, \
  {1, 1, 0, 0, 0, 0, 0, 1}, \
  {1, 1, 1, 0, 0, 0, 1, 1}  \
}
#define level3 { \
  {0, 0, 0, 1, 1, 1, 0, 0}, \
  {0, 0, 1, 1, 1, 1, 1, 0}, \
  {0, 1, 1, 0, 1, 0, 1, 1}, \
  {0, 1, 0, 1, 1, 1, 0, 1}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}  \
}

/*** WIN ***/
#define win { \
  {1, 1, 1, 0, 0, 1, 1, 1}, \
  {1, 1, 0, 0, 0, 0, 1, 1}, \
  {1, 0, 1, 0, 0, 1, 0, 1}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {0, 0, 0, 0, 0, 0, 0, 0}, \
  {1, 0, 1, 0, 0, 1, 0, 1}, \
  {1, 0, 0, 1, 1, 0, 0, 1}, \
  {1, 1, 1, 0, 0, 1, 1, 1}  \
}


/*** GENERAL ***/
const int cols[8] = { 12, 11, 10, 9, 8, 7, 6, 5 };    // Array of all the Column pin numbers
const int rows[8] = { 4, 3, 2, A0, A1, A2, A3, A4 };  // Array of all the Row pin numbers

// 2-dimensional array of pixels in LED Matrix:
int pixels[8][8];  

int loopDelay = 2;

boolean levelAni = true;  //true
boolean levelStart = false;
boolean levelComplete = false;

int levelsArrayIndex = 0;

const int _lvls = 7;  //2 * number of levels
byte levels[_lvls][8][8] = { 
  level1_ani, level1, level2_ani, level2, level3_ani, level3, win
};

//copy of levels array for resetting purposes
byte initial[_lvls][8][8] = { 
  level1_ani, level1, level2_ani, level2, level3_ani, level3, win
};

/*** SOUND ***/
int boom = NOTE_C4;

boolean loseSound = true;
int lose[] = { NOTE_F4, NOTE_A4, NOTE_C5 };
int loseNoteDurations[] = { 2, 4, 4};

/*** TIMERS ***/
unsigned long aniTime;
unsigned long completeTime;
unsigned long enemyTime;
unsigned long gameOverTime;

/*** PLAYER ***/
int bulletRow = 5;
int bulletCol;
byte bulletArray[6];

int bulletDelayCount = 0;
boolean fired = false;


/*** CONTROLS ***/
int btnPin = A5;
int potPin = A6;
int potVal;

boolean btnDown = false;

/*** ENEMY ***/
boolean enemyWon = false;
boolean enemyWaiting = false;
boolean enemyFired = false;
boolean enemyBulletCollision = false;

int enemyAttackSpeed[7] = {0, 150, 0, 100, 0, 25, 0};
int enemyBulletSpeed[7] = {0, 16, 0, 12, 0, 8, 0};
int enemyBulletRow;
int enemyBulletDelayCount = 0;
int enemyBulletArray[8][2] = { {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0} };
int enemyBottomCount = 0;
int randomBullet;

/*** SHIFTING ***/
boolean shiftLevel = false;
boolean shiftLeft = true;
boolean shiftDown = false;
boolean shiftRight = false;
boolean shiftUp = false;

int shiftCount = 0;
int shiftSpeed[2] = {70, 35};


void setup() {
  Serial.begin(9600);
  // initialize the I/O pins as outputs:

  // iterate over the pins:
  for (int thisPin = 0; thisPin < 8; thisPin++) {
    // initialize the output pins:
    pinMode(cols[thisPin], OUTPUT); 
    pinMode(rows[thisPin], OUTPUT);  
    // take the col pins (i.e. the cathodes) high to ensure that
    // the LEDS are off: 
    //both HIGH so no connection
    digitalWrite(cols[thisPin], HIGH);
    digitalWrite(rows[thisPin], HIGH);  
  }
  
  //set button and potentio meter as input
  pinMode(btnPin, INPUT);
  pinMode(potPin, INPUT);

  clearLeds();  //clear LED Matrix
//  shiftLevel = true;
  aniTime = millis();  //start level # animation timer
  
}

void loop() {
  
  /***reset all to no circuit***/
  for (int i = 0; i < 8; i++) {
    digitalWrite(rows[i], HIGH);  //all rows to high
    digitalWrite(cols[i], LOW);
  }
  
  
    
  /***Row 0***/
  for (int col = 0; col < 8; col++) {
    if (pixels[0][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[0], LOW);
  delay(loopDelay);
  digitalWrite(rows[0], HIGH);

  setPattern(levelsArrayIndex);  //create levels
  
  /***Row 1***/
  for (int col = 0; col < 8; col++) {
    if (pixels[1][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[1], LOW);
  delay(loopDelay);
  digitalWrite(rows[1], HIGH);
  
  if (levelAni) playLevelAni();  //play animation

  /***Row 2***/
  for (int col = 0; col < 8; col++) {
    if (pixels[2][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[2], LOW);
  delay(loopDelay);
  digitalWrite(rows[2], HIGH);
  
  if (levelStart) readPot();  //read potentiometer value

  /***Row 3***/
  for (int col = 0; col < 8; col++) {
    if (pixels[3][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[3], LOW);
  delay(loopDelay);
  digitalWrite(rows[3], HIGH);
  
  if (levelStart) refreshPlayer();  //update player's position based on potentiometer value
  if (levelStart) readBtn();      //read button state
  
  /***Row 4***/
  for (int col = 0; col < 8; col++) {
    if (pixels[4][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[4], LOW);
  delay(loopDelay);
  digitalWrite(rows[4], HIGH);
  
  if (levelStart && !enemyWon) readEnemy();  //get highest row # of enemy and fire bullet
  
  /***Row 5***/
  for (int col = 0; col < 8; col++) {
    if (pixels[5][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[5], LOW);
  delay(loopDelay);
  digitalWrite(rows[5], HIGH);
  
  if (levelStart && !levelComplete) checkLevelState();  //check all pixels of the level are gone
  if (levelComplete) levelFinished();                //win level

  
  /***Row 6***/
  for (int col = 0; col < 8; col++) {
    if (pixels[6][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[6], LOW);
  delay(loopDelay);
  digitalWrite(rows[6], HIGH);
  
  if (levelStart && shiftLevel)  shiftRow();  //shift pixels in the level
  
  /***Row 7***/
  for (int col = 0; col < 8; col++) {
    if (pixels[7][col] == 1) {
      digitalWrite(cols[col], HIGH); 
    } else {
      digitalWrite(cols[col], LOW);
    }
  }
  digitalWrite(rows[7], LOW);
  delay(loopDelay);
  digitalWrite(rows[7], HIGH);
  
  if (enemyWon) gameOver();  //lose if hit by enemy
  updatePixels();  //update all pixels of the LED Matrix 

}

void clearLeds() {
  // Clear display array
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      pixels[i][j] = 0;
    }
  }
}

/*** Populate Level on LED Matrix***/
void setPattern(int pattern) {
  
  if (levelsArrayIndex < 7) {  //if not last level
    for (int i = 0; i < 8; i++) {
      for (int j = 0; j < 8; j++) {
        if ( levels[levelsArrayIndex][i][j] == 1 ) {  //copy only "ones" to temporary matrix
          tempMatrix[i][j] = levels[levelsArrayIndex][i][j];  
        }
      }
    }
  } else {
    restart();  //restart if end of the game has been reached
  }
  
}


/***READ POTMETER***/
void readPot() {
  potVal = analogRead(potPin);      //read potentiometer value
  potVal = map(potVal, 0, 1024, 0, 6);  //map 1023 to 6 values for LED Matrix; 
                                          //only column 0~6 are used to display player
                                          //raise max_in and max_out by one for even value distribution http://arduino.cc/forum/index.php?topic=72153.0  
}
/*** Refresh PLAYER ***/
void refreshPlayer() {

  byte _playerRows[2][8] = {   //temp array to store player's position
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0}
  };
  
  //draw player pixels
  _playerRows[0][potVal+1] = 1;
  _playerRows[1][potVal] = 1;
  _playerRows[1][potVal+1] = 1;
  _playerRows[1][potVal+2] = 1;

  for (int i = 6; i < 8; i++) {     //rows 6-7 (where the player is)
    for (int j = 7; j >= 0; j--) {  //update player positions
       if(_playerRows[i-6][j] == 1) {  //copy only "ones" to temporary matrix
         tempMatrix[i][j] = _playerRows[i-6][j];
       }
    }
  } 
}


/***READ BUTTON***/
void readBtn() {
  
  int btnPress = digitalRead(btnPin);  //read button state
  if (btnPress == 1 && !fired && !btnDown){      //if button is pressed
    bulletCol = potVal+1;      //bullet column value on matrix
    btnDown = true;
    fired = true;
  } 
  if (btnDown) {
    if (btnPress == 0) {
      btnDown = false;
    }  
  }
  if (fired) {   
    shoot(bulletCol);    //play shoot animation
  } 
}

/*** SHOOT ***/
void shoot(int _bulletCol) {
  
  if (bulletDelayCount == 2) {    //act as a delay & determines bullet's speed
    bulletRow--;
    
    if (bulletRow < 0) {  //if bullet reaches top (row 0)
      bulletRow = 5;    //reset bullet row position
      fired = false;    //bullet fire done
    } else {
      if (tempMatrix[bulletRow][_bulletCol] == 0) {  //check if next pixel position is empty or not
        tempMatrix[bulletRow][_bulletCol] = 1;  //new bullet pixel position and turn on
      } else {
        collisionBullet(bulletRow, _bulletCol);  //bullet collides with pixel
      }
     }
  } else {
    tempMatrix[bulletRow][_bulletCol] = 1;  //draw bullet pixel
  }
  bulletDelayCount = (bulletDelayCount+1) % 3;  //bullet's speed counter
  
}
/*** BULLET COLLISION ***/
void collisionBullet(int _row, int _col) {
  int boomNoteDuration = 1000/4;      //sound duration
  tone(13, boom, boomNoteDuration);      //play sound when hit
//  noTone(13);
  levels[levelsArrayIndex][_row][_col] = 0;    //remove 1 pixel that got shot from original level matrix
  tempMatrix[_row][_col] = 0;  //update temp matrix for pixel display
  
  bulletRow = 5;    //set original bullet row position back to 5
  fired = false;    //bullet fire done
}


/*** READ ENEMY ***/
void readEnemy() {
  
  if (!enemyWaiting && !enemyFired && !enemyBulletCollision){  //if enemy isn't doing anything
    enemyTime = millis();  //start timer
    enemyWaiting = true;
  }
  
  if (enemyWaiting) {
    if (millis() - enemyTime > enemyAttackSpeed[levelsArrayIndex]) {  //attack speed for each level according to array 
      
      int _row = 3;   //temp row value
      boolean dobreak = false;    //for double break;
      
      //loop to get the enemy's pixels of highest row (closest to the player) 
      for (int i = 3; !dobreak && i >= 0; i--) {  //backwards loop to get highest row
        for (int j = 0; j < 8; j++) {
            if(levels[levelsArrayIndex][i][j] == 1) {  //if a "one" is found in the row
              _row = i;          //save row index
              enemyBulletRow = _row + 1;  //value to put enemy bullet 1 row below enemy
              dobreak = true;    //double break;
              break;
            }
         }  
      }
      
      enemyBottomCount = 0; //counter for number of "one" pixels in highest row (closest to the player) 
      for (int c = 0; c < 8; c++) {  //loop through highest row
        if(levels[levelsArrayIndex][_row][c] == 1) {   //check if column contains "one" 
          enemyBulletArray[enemyBottomCount][0] = _row;  
          enemyBulletArray[enemyBottomCount][1] = c;
          enemyBottomCount++;  
        }
      }
       
      enemyWaiting = false;
      enemyFired = true;  //fire enemy bullet
      randomBullet = random(enemyBottomCount);  //randomly select one of the column pixels
    }
  }
  
  if (enemyFired) {
    if (enemyBulletDelayCount == (enemyBulletSpeed[levelsArrayIndex]-1)) {  //enemy bullet speed (higher value = slower)
      enemyBulletArray[randomBullet][0]++;  //row + 1
      if  (enemyBulletArray[randomBullet][0] > 7) {  //if bullet reaches bottom
        enemyBulletDelayCount = 0;  //reset and remove bullet
        enemyFired = false;
      } else {
        if (tempMatrix[enemyBulletArray[randomBullet][0]] [enemyBulletArray[randomBullet][1]] == 0) {  //if next row is empty
          tempMatrix[enemyBulletArray[randomBullet][0]] [enemyBulletArray[randomBullet][1]] = 1;  //bullet claims row
        } else {  //bullet hit something!!
          if (!levelComplete) {
            enemyBulletDelayCount = 0;  
            enemyFired = false;
            enemyBulletCollision = true;
          }
        }
      }
    } else {
      tempMatrix[enemyBulletArray[randomBullet][0]][enemyBulletArray[randomBullet][1]] = 1;
    }
    enemyBulletDelayCount = (enemyBulletDelayCount+1) % enemyBulletSpeed[levelsArrayIndex];  //enemy bullet speed
  }
  
  if (enemyBulletCollision) {
    if (enemyBulletArray[randomBullet][0] == 6 || enemyBulletArray[randomBullet][0] == 7) {  //check if enemy's bullet hit player
//      digitalWrite(13, HIGH);
      Serial.println("HIT!");
      enemyWon = true;
      gameOverTime = millis();
    }
    enemyBulletCollision = false;
  }
}




/*** SHIFTING LEVEL ***/
void shiftRow() {  //testing purposes
  int _speed;
  if (levelsArrayIndex == 3) {
      _speed = shiftSpeed[0];
  } else if (levelsArrayIndex == 5) {
      _speed = shiftSpeed[1];
  }
  byte _levelTemp[5][8] = {   //temp matrix array to store level pixel positions
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0, 0}
  };
  for (int i = 0; i < 5; i++) {    //store in temp array
    for (int j = 0; j < 8; j++) {
        _levelTemp[i][j] = levels[levelsArrayIndex][i][j];
    }
  }
  
  if (shiftCount == (_speed-1)) {  //delay before shifting (roughly 100*18ms)
    if (shiftLeft == true) {  //shift left
      //loops through top 5x8 of the matrix
      for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 8; j++) {
          if (j == 7) {     //prevents shifting column index 8 which doesn't exist
            levels[levelsArrayIndex][i][7] = _levelTemp[i][0];
          } else {
            levels[levelsArrayIndex][i][j] = _levelTemp[i][j+1];
          }
        }
      }
      shiftCount = 0;
      shiftLeft = false;
      shiftDown = true;
    } else if (shiftDown == true) {  //shift down
      for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 8; j++) {
          if ( i == 0 ) {    //prevents shifting row index -1 which doesn't exist
            levels[levelsArrayIndex][i][j] = 0;
          } else {
            levels[levelsArrayIndex][i][j] = _levelTemp[i-1][j];  //shift down
          }
        }
      }
      shiftDown = false;
      shiftRight = true;
     } else if (shiftRight == true) {  //shift right
        for (int i = 0; i < 5; i++) {
          for (int j = 7; j >= 0; j--) {
            if (j == 0) {     //prevents shifting column index -1 which doesn't exist
              levels[levelsArrayIndex][i][0] = _levelTemp[i][7];
            } else {
              levels[levelsArrayIndex][i][j] = _levelTemp[i][j-1];
            }
          }
        }
        shiftCount = 0;
        shiftRight = false;
        shiftUp = true;
      
      } else if (shiftUp == true) {  //shift up
        for (int i = 0; i < 5; i++) {
          for (int j = 0; j < 8; j++) {
            if ( i == 4 ) {  //prevents shifting row index 5
              levels[levelsArrayIndex][i][j] = 0;
            } else {
              levels[levelsArrayIndex][i][j] = _levelTemp[i+1][j];  //shift down
            }
          }
        }
        shiftUp = false;
        shiftLeft = true;
      }
    }
    shiftCount = (shiftCount+1) % _speed;  //shifting delay
  
}




/*** PLAY LEVEL NUMBER ANIMATION ***/
void playLevelAni() {
  
  
  if (millis() - aniTime < 3000) {  //time before transition from level number to actual level    
//    if (levelsArrayIndex < 6 && millis() - aniTime > 3750) {  //3000
//      delay(500);
//    } 
  } else {
    levelAni = false;  //end animation
    levelStart = true;

    
    levelsArrayIndex++;
    if (levelsArrayIndex == 3 || levelsArrayIndex == 5) {  //if level 2 or 3, initiate shifting
      shiftLeft = true;
      shiftDown = false;
      shiftRight = false;
      shiftUp = false;
      shiftLevel = true;
    } else {
      shiftLevel = false;
    }
    clearLeds();
    
  }
}

void checkLevelState() {  //check if all level pixels (enemies) are dead
  int _countLevelPixels = 0;
  for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 8; j++) {
      if(levels[levelsArrayIndex][i][j] == 1){
        _countLevelPixels++;  //count the number of "one" pixels
      }
    }  
  }
  if((_countLevelPixels) == 0){  //if nothing left, congratz! you beat the level!
//    digitalWrite(13, HIGH);
//    Serial.println("COMPLETE!");
    completeTime = millis();
    levelComplete = true;
  }  
}

void levelFinished() { 
  
  if (millis() - completeTime > 2000) {  //time before transitioning to next level
  
    //reset all booleans
    enemyWaiting = false;
    enemyFired = false;
    enemyBulletCollision = false;

    levelStart = false;  
    levelComplete = false;
    levelAni = true;
    aniTime = millis();
    levelsArrayIndex++;
  }
}


/*** UPDATE PIXEL MATRIX ***/
void updatePixels() {
  //Use temporary 8x8 matrix to update actual matrix to prevent any bugs
  //Tends to get buggy when apply values straight to pixels[] matrix 
  //Instead, storing all matrix values in a temp and apply values to pixels[] at once is more stable
  
  //copy all temp matrix values to actual display matrix
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      pixels[i][j] = tempMatrix[i][j]; 
    }
  }
  
  //reset all values for temp matrix
  for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
      tempMatrix[i][j] = 0;
    }
  }
}

void gameOver() {
  
  if( loseSound) {
    loseSound = false;
     for (int thisNote = 0; thisNote < 3; thisNote++) {
  
      // to calculate the note duration, take one second 
      // divided by the note type.
      int noteDuration = 250/loseNoteDurations[thisNote];
      tone(13, lose[thisNote],noteDuration);
  
      // to distinguish the notes, set a minimum time between them.
      // the note's duration + 30% seems to work well:
      int pauseBetweenNotes = noteDuration * 1.30;
      delay(pauseBetweenNotes);
      // stop the tone playing:
      noTone(13);
    }
  }
  
  if (millis() - gameOverTime < 3000) {  //time before restarting
    delay(250);
  } else {
    restart();  
  }
  

}

void restart() {
  //reset all booleans
  enemyWon = false;
  enemyWaiting = false;
  enemyFired = false;
  enemyBulletCollision = false;
  
  levelAni = true;
  levelStart = false;  
  levelComplete = false;
  levelsArrayIndex = 0;
  
  loseSound = true;
  
  //reset all levels
  for (int level = 0; level<_lvls; level++) {
     for (int x = 0; x<8; x++) {
       for (int y = 0; y<8; y++) {
         levels[level][x][y] = initial[level][x][y];
       }
     }
   }

  aniTime = millis();  //run level 1 animation 
};

pitches.h

C/C++
No preview (download only).

Credits

Mirko Pavleski

Mirko Pavleski

153 projects • 1300 followers

Comments