Project tutorial
Space Hinvaders

Space Hinvaders © GPL3+

A micro game with LED matrix where the pixels used for the entire game are about those of a single sprite of the original invader.

  • 72 views
  • 0 comments
  • 1 respect

Components and supplies

Necessary tools and machines

Apps and online services

About this project

I really like old video games, and I had never found a space invader style game on Arduino that used Dot matrix LED display. One day seeing one of these displays I said to myself: I could make a space invader in a space approximately equal to what was originally occupied by a single sprite of an invader. It would be great.

I got started and tried it, and in spite of all the limitations I managed to do something playable and at the same time fascinating considering the limits of the hardware.As you can see on the title is named Space Hinvaders, because is a Survival Hacking (SH) creation, so altered original Space Invader name according to SH Initials.

Have fun !!!

See also a updated version with WS2812 RGB dot matrix display !!!
https://www.hackster.io/davide-gatti/space-hinvaders-color-b7b124

(Background music on video is made by me too)

Time Lapse building video


Code

Space HinvadersC/C++
// Space Hinvader by Davie Gatti of Survival Hacking Channel - wwww.survivalhacking.it
// A small Space Invaders game, with 2 MAX7219 8x8 dot matrix module.
// for a total of 8x16 pixels, that is a small game in a couple of original invaders sprites space.
// Due lack of display space, there are some game limitation. Aliens never shoot, and ther are not any saucers
// Also ther are not a barriers. Each time you kill all aliens, the game speed was increased.
// At the end of game, a Score is shown alternate with HigScore (underlined).
//

#include "LedControl.h" // Need the library to be added from arduino ide
#include "pitches.h"    // Musical Notes include file 
#include "EEPROM.h"     // EEprom management include file

// pin 5 is connected to the DIN of MAX7219 pin 1
// pin 3 is connected to the CLK of MAX7219 pin 13
// pin 4 is connected to the LOAD of MAX7219 pin 12
// 2 as we are using 2 MAX7219
LedControl lc=LedControl(5,3,4,2); 

// Variables initialization
long Score = 0;          // Global Variable for Actual Score
long HighScore;          // Global Variable for HiScore 
long AlienSpeed = 80000; // Global Variable for Aliens speed
long AlienLevel = 0;     // Global Variable for Aliens speed on the level
long AlienMul = 5000;    // Global Variable for step speed increasing when shooting alien
long AlienDelay = 0;     // Global Variable for Aliens Delay
char AllKilled = 0;      // Global Variable that count active alien on screen
long HiscoreDelay =0;    // Global Variable used to flip score with hiscore
long CannonDelay = 0;    // Global Variable for Cannon Delay
byte CannonPos = 8;      // Global Variable for Cannon position
long Explode = 0;        // Global Variable for Explosion Marker
byte Ex = 0;             // Global Variable for Explosion X
byte Ey = 0;             // Global Variable for Explosion Y 
byte AlienXo = 16;       // Global Variable for Alien X previus (to remove aliens before redraw new position)
byte AlienYo = 0;        // Global Variable for Alien Y previus (to remove aliens before redraw new position)
byte AlienX = 16;        // Global Variable for Alien X
byte AlienY = 0;         // Global Variable for Alien Y
byte MaxAlienX = 0;      // Global Variable for Maximum Alien X position
byte MaxAlienY = 0;      // Global Variable for Maximum Alien Y position
byte MinAlienX = 0;      // Global Variable for Minimum Alien X position
byte AlienSound = 0;     // Global Variable for Alien Sound sequance
boolean AlienXs = false; // Global Variable for define alien direction march

long FireDelay = 0;      // Global Variable for Missile Delay
byte FireXPos = 8;       // Global Variable for Missile X
byte FireYPos = 1;       // Global Variable for Missile Y

const long CannonSpeed = 7000;    // Cannon speed
const long FireSpeed = 10000;     // Missile shooted speed
const byte FirstMax = 0;          // Addres of First DotMatrix display
const byte SecondMax = 1;         // Addres of Second DotMatrix display
const long ExplodeSpeed = 3000;   // Explosions Speed 
const long HiscoreSpeed = 100000; // Speed of flip from score to hiscore

const byte btnLeft = 12;          // Left Button assigned to IO 13 
const byte btnRight = 11;         // Right Button assigned to IO 12 
const byte btnFire = 10;          // Fire Button assigned to IO 11
const byte buzzer = 9;            // Buzzer assigned to IO 9

int win[] = {                     // Win melody array 
  NOTE_G3, NOTE_A4, NOTE_B4, NOTE_G3, NOTE_C4, 0, NOTE_C3
};
int noteDurations[] = {
  8, 8, 8, 8, 8, 8, 8
};



// Arrays for define X, Y and status (on off) of alien pattern
const byte MaxAliens = 16;        //  Number of aliens on screen (see followind array)

byte AliensY[MaxAliens] = {       // Y coordinate of lighted led
  0,0,0,0, // row 0
  1,1,1,1, // row 1
  2,2,2,2, // row 2
  3,3,3,3, // row 3
  };
  
byte AliensX[MaxAliens] = {       // X coordinate of lighted led
  0,3,6,9,  // row 0
  1,4,7,10, // row 1
  2,5,8,11, // row 2
  0,3,6,9,  // row 3
  };
  
 boolean AliensStat[MaxAliens] = {// status (true=ON    false=OFF)
  true,true,true,true, // row 0
  true,true,true,true, // row 1
  true,true,true,true, // row 2
  true,true,true,true, // row 3
  };



// define a graphic array for draw number on dot matrix used with pointer multiplied by 5
byte Numbers[] =
{
   B00000111,  // Number 0
   B00000101,
   B00000101,
   B00000101,
   B00000111,
   B00000010,  // Number 1 
   B00000010,
   B00000010,
   B00000010,
   B00000010,
   B00000111,  // Number 2 
   B00000100,
   B00000111,
   B00000001,
   B00000111,
   B00000111,  // Number 3 
   B00000100,
   B00000110,
   B00000100,
   B00000111,
   B00000101,  // Number 4 
   B00000101,
   B00000111,
   B00000100,
   B00000100,
   B00000111,  // Number 5
   B00000001,
   B00000111,
   B00000100,
   B00000111,
   B00000111,  // Number 6
   B00000001,
   B00000111,
   B00000101,
   B00000111,
   B00000111,  // Number 7 
   B00000100,
   B00000100,
   B00000100,
   B00000100,
   B00000111,  // Number 8 
   B00000101,
   B00000111,
   B00000101,
   B00000111,
   B00000111,  // Number 9 
   B00000101,
   B00000111,
   B00000100,
   B00000111,
};


// Array space needed to be filled with graphic data for print the score
byte Score1[] =
{
   B00000000,  // Score 1
   B00000000,
   B00000000,
   B00000000,
   B00000000,
   B00000000,
   B00000000,
   B00000000,
};

byte Score2[] =
{
   B00000000,  // Score 2
   B00000000,
   B00000000,
   B00000000,
   B00000000,
   B00000000,
   B00000000,
   B00000000,
};


// Game Over Alien animation graphics array
byte invader1[] =
{
  B00011000,  // Invader 1
  B00111100,
  B01111110,
  B11011011,
  B11111111,
  B00100100,
  B01011010,
  B10100101
};
 
byte invader2[] =
{
  B00011000, // Invader 2
  B00111100,
  B01011010,
  B11111111,
  B11111111,
  B00100100,
  B01011010,
  B01000010
};

// Main Screen animation graphics array
byte SH1[] =
{
  B00100000,  // Main Screen 1
  B01000000,
  B11110011,
  B10111001,
  B11111011,
  B11101010,
  B00101011,
  B01100000,
};

byte SH2[] =
{
  B00000010,  // Main Screen 2
  B10100001,
  B10100111,
  B11101110,
  B10101111,
  B10101011,
  B00001010,
  B00000011,
};

byte SH3[] =
{
  B00110000,  // Main Screen 3
  B01000011,
  B11111001,
  B11111011,
  B10111010,
  B11101011,
  B00100000,
  B00110000,
};

byte SH4[] =
{
  B00000110,  // Main Screen 4
  B00000001,
  B10101111,
  B10101111,
  B11101110,
  B10101011,
  B10100010,
  B00000110,
};

// Startup function
void setup()
{
  Serial.begin(9600);                             // Start Serial debug line
  Serial.println("Space Hinvader");               // Debug string
  pinMode(btnLeft, INPUT_PULLUP);                 // Define I/O data direction and pullups
  pinMode(btnRight, INPUT_PULLUP);
  pinMode(btnFire, INPUT_PULLUP);
  pinMode(buzzer, OUTPUT);

  lc.shutdown(FirstMax,false);                    // turn off power saving, enables display
  lc.setIntensity(FirstMax,8);                    // sets brightness (0~15 possible values)
  lc.clearDisplay(FirstMax);                      // clear screen
  lc.shutdown(SecondMax,false);                   // turn off power saving, enables display
  lc.setIntensity(SecondMax,8);                   // sets brightness (0~15 possible values)
  lc.clearDisplay(SecondMax);                     // clear screen

  MainScreen();                                   // Print Main Screen
  GameInit();                                     // Initialize Variables    
  HighScore=EEPROMReadlong(0);                    // Read Hiscore From EEprom
  PrintCannon(CannonPos);                         // Print initial cannon on screen
  PrintAliens(AlienX,AlienY,AlienXo,AlienYo);     // Print inital aliens
}

// read number (higscore) from eeprom
long EEPROMReadlong(long address) {
  long four = EEPROM.read(address);
  long three = EEPROM.read(address + 1);
  long two = EEPROM.read(address + 2);
  long one = EEPROM.read(address + 3);
  return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}

// write number (higscore) to eeprom
void EEPROMWritelong(int address, long value) {
  byte four = (value & 0xFF);
  byte three = ((value >> 8) & 0xFF);
  byte two = ((value >> 16) & 0xFF);
  byte one = ((value >> 24) & 0xFF);
  
  EEPROM.write(address, four);
  EEPROM.write(address + 1, three);
  EEPROM.write(address + 2, two);
  EEPROM.write(address + 3, one);
}


// Show main screen animation (Press fire to start)
void MainScreen() {
long MainAni = 0;
  while (digitalRead(btnFire) == true) {
    MainAni++;
    if (MainAni == 30000) {
      for (int i = 0; i < 10; i++) {
        lc.setColumn(FirstMax,i,SH1[i]);
        lc.setColumn(SecondMax,i,SH2[i]);
      }
    } else if (MainAni == 60000) {
      for (int i = 0; i < 10; i++) {
        lc.setColumn(FirstMax,i,SH3[i]);
        lc.setColumn(SecondMax,i,SH4[i]);
      }
      MainAni=0;
    }    
  }
  while (digitalRead(btnFire) == false);                    // wait release fire key to continue
}


// Caluclate max/min of X & Y coordinates of active aliens on screen, and detect if all aliens are killed
// In this function I add an offset of 16 to fix a negative calculation, next when this result was used.
void CalcMaxAlien() {
  MaxAlienX=0;
  MaxAlienY=0;
  MinAlienX=999;
  AllKilled=0;
  for (int nal = 0; nal < MaxAliens; nal++) {                      // cicle on all aliens in array
    if (AliensStat[nal] == true) {                                 // if alien is enabled, check coordinates
      AllKilled++;
      if (AliensX[nal] >= MaxAlienX) MaxAlienX = AliensX[nal];     // set new maximum X  
      if (AliensY[nal] >= MaxAlienY) MaxAlienY = AliensY[nal];     // set new maximum Y  
      if (MinAlienX >= AliensX[nal]) MinAlienX = AliensX[nal];     // set new minimum X  
    }
  }
  if (AllKilled==0) {                                              // if all alien are disabled mean you killed all aliens !!!
    PrintCannon(CannonPos);                                        // Print cannon on screen to refresh at last kill
    NextLevel();                                                   // go to next level 
  }
}

// Play WIN melody and set parameters for next level
void NextLevel() {
  delay(500);
  PlayMelody();                                                   // play WIN melody  
  AlienLevel+=500;                                                // increase alien speed
  Explode =ExplodeSpeed*4;                                        // set variable to clear last explosion starting new level
  GameInit();   
}

// Set Default Variable for initial Game values
void GameInit() {
  lc.clearDisplay(FirstMax);                                     // clear screen
  lc.clearDisplay(SecondMax);                                    // clear screen
  for (int nal = 0; nal < MaxAliens; nal++) {                    // Enable all aliens
    AliensStat[nal] = true;
  }  
  AlienX =16;                                                    // reset alien position on top (16 means position 0)
  AlienY =0;
  AlienXo =16;
  AlienYo =0;
  AlienXs = false;                                               // Se flag alien go to left direction    
  Explode = 0;
  PrintCannon(CannonPos);                                        // Print initial cannon on screen
  PrintAliens(AlienX,AlienY,AlienXo,AlienYo);                    // Print inital aliens
  CalcMaxAlien();                                                // calculate new aliens edges
  AlienSpeed = (AllKilled * AlienMul) + AlienMul;                // set alien speed 
  AlienSpeed -= AlienLevel;                                      // Add more speed trough level
  Serial.print("Speed=");
  Serial.println(AlienSpeed);
}


// Draw cannon on screen position, also clear all pixel around cannon to avoid shadows
void PrintCannon(byte pos)
{
  pos--;                      // fix offset due position variable go fro 1 to 16, bud display go fro 0 to 15
  SetLed(pos,6,true);         // draw cannon head
  SetLed(pos,7,true);         // draw cannon base1
  if (pos>0) {                // check if outside the screen
    SetLed(pos-1,6,false);    // remove head shadow left
    SetLed(pos-1,7,true);     // draw cannon base2
  } 
  if (pos>1) {                // check if outside the screen
    SetLed(pos-2,7,false);    // remove base shadow left
  }
  if (pos<16) {               // check if outside the screen  
    SetLed(pos+1,6,false);    // remove head shadow right
    SetLed(pos+1,7,true);     // draw cannon base3
  }
  if (pos<15) {               // check if outside the screen  
    SetLed(pos+2,7,false);    // remove base shadow right
  }
}

// Print Aliens giving values from array with X, Y offset and clear old alien with oX and oY offset
void PrintAliens(byte x, byte y,byte ox, byte oy){
  for (int nal = 0; nal < MaxAliens; nal++) {                // Remove old Aliens
    if (AliensStat[nal] == true) {                           // check if enabled     
      SetLed( (AliensX[nal]+ox)-16, AliensY[nal]+oy,false);    
    }
  }
  for (int nal = 0; nal < MaxAliens; nal++) {                // Draw Aliens if enabled   
    if (AliensStat[nal] == true) {                           // check if enabled     
      SetLed((AliensX[nal]+x)-16, AliensY[nal]+y,true);      // draw
    }
  }
}

// Game Over animation e scoring
void GameOver() {
int mel = 2600;                                             // setup local var
long InvaderAni = 0;
int AniCount = 0;
  
  while (AniCount <= 10) {                                  // 10 cycle animation 
    InvaderAni++;
    mel--;
    tone(buzzer, mel/10, 10);                               // Make sound
    if (InvaderAni == 100) {
      for (int i = 0; i < 10; i++)                          // show invaders
      {
        lc.setColumn(FirstMax,i,invader1[i]);
        lc.setColumn(SecondMax,i,invader1[i]);
      }
    } else if (InvaderAni == 200) {
      for (int i = 0; i < 10; i++)                          // show invaders
      {
        lc.setColumn(FirstMax,i,invader2[i]);
        lc.setColumn(SecondMax,i,invader2[i]);
      }
      InvaderAni=0;
      AniCount++;
    }    
  }
  ShowScore();                                              // show score and wait for a keypress
}

// Show final Score an High score
void ShowScore() {
  int waitk = 0;                                            // Set waikey flag
  PrintNumber(Score,false);                                 // Show score
  while (waitk == 0) {                                      // wait fire key to continue
    if (digitalRead(btnFire) == false) {                    // If Fire button pressed
      while (digitalRead(btnFire) == false);                // wait release fire key to continue
      MainScreen();                                         // Show Main Screen
      Score=0;                                              // reset score
      GameInit();                                           // Initialize game                                      
      waitk =1;                                             // reset waitkey flag  
    }
    HiscoreDelay++;
    if (HiscoreDelay >= HiscoreSpeed * 2) {
      PrintNumber(HighScore,true);                          // Show Hi score
      HiscoreDelay = 0;
    } else if (HiscoreDelay == HiscoreSpeed) {
      PrintNumber(Score,false);                             // Show score
    }
  }
}

// Function to play melody
void PlayMelody() {
  for (int mel = 0; mel < 7; mel++) {
    int noteDuration = 1000 / noteDurations[mel];
    tone(buzzer, win[mel], noteDuration);
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    noTone(buzzer);
    }
}

// Function to set pixel on 16x8 matrix addressed by column, row and status 0,0 = top left
void SetLed(byte X,byte Y, boolean OnOff)
{
  if (X>7) { 
    lc.setLed(SecondMax,8-(X-7),Y,OnOff);                // turns on/off LED at X, Y
  } else {
    lc.setLed(FirstMax,7-X,Y,OnOff);                     // turns on/off LED at X, Y
  }
}

// Function to print decimal number from 0000 to 9999 on screen with underline flag
void PrintNumber(long num, boolean underline) {
  byte Digit1;                                           // convert long to 4 digit BCD
  byte Digit2;
  byte Digit3;
  byte Digit4;

  Digit1 = num/1000;                                     // convert long to 4 digit BCD
  Digit2 = (num-(Digit1*1000))/100;
  Digit3 = (num-((Digit2*100)+(Digit1*1000)))/10;
  Digit4 = num-((Digit3*10)+(Digit2*100)+(Digit1*1000));
 
  for (int i = 0; i < 5; i++)                            // create bitmap graphics 
  {
    Score1[i] = (Numbers[(Digit2*5)+i] << 4) + (Numbers[(Digit1*5)+i] & B00001111);
    Score2[i] = (Numbers[(Digit4*5)+i] << 4) + (Numbers[(Digit3*5)+i] & B00001111);
  }
  if (underline == true) {                               // add underline
    Score1[6] = 255;
    Score2[6] = 255;
  } else {                                               // remove underline 
    Score1[6] = 0;
    Score2[6] = 0;
  }

  for (int i = 0; i < 8; i++)                            // show score
  {
    lc.setColumn(FirstMax,i,Score1[i]);
    lc.setColumn(SecondMax,i,Score2[i]);
  }
}


// main loop game
void loop()
{
  if (digitalRead(btnRight) == false) {                  // If Right button pressed
    if (CannonDelay==0) {                                // check cannon delay counter to decide if cannon need be moved 
      CannonPos++;                                       // move the cannon
      if (CannonPos>16) CannonPos = 16;                  // check if position is outside display (right)
      PrintCannon(CannonPos);                            // draw cannon in updated position 
    }
    CannonDelay++;                                       // if button continu to be pressed increase cannon delay counter
    if (CannonDelay > CannonSpeed) CannonDelay = 0 ;     // if cannon delay reach cannon speed value, clear it to allow to move cannon again 
  } else if (digitalRead(btnLeft) == false) {            // If Left button pressed
    if (CannonDelay==0) {                                // check cannon delay counter to decide if cannon need be moved 
      CannonPos--;                                       // move the cannon
      if (CannonPos < 1) CannonPos = 1;                  // check if position is outside display (right)
      PrintCannon(CannonPos);                            // draw cannon in updated position 
    }
    CannonDelay++;                                       // if button continue to be pressed increase cannon delay counter
    if (CannonDelay > CannonSpeed) CannonDelay = 0 ;     // if cannon delay reach cannon speed value, clear it to allow to move cannon again 
  } else {                                               // If left and right are released
    CannonDelay=0;
  }

  if (digitalRead(btnFire) == false) {                   // Press fire button
    if (FireYPos==0) {                                   // check if fire is already shooted 
      FireXPos = CannonPos-1;                            // if not shooted, assign currect cannon X position to missile
      FireYPos = 7;                                      // set Missile Y position (Y>1 = shooting in progress)  
      tone(buzzer, NOTE_C6, 100);
    }
  }

// explosion management
  if (Explode != 0) {                                   // Check if active Explosion to Ex and Ey Position
    Explode++;
    if (Explode > ExplodeSpeed * 5) {
     SetLed(Ex,Ey,false);                               // Clear explosion
     Explode =0;
    } else if (Explode == (ExplodeSpeed * 4)) {
     SetLed(Ex,Ey,true);                                // Set explosion
    } else if (Explode == (ExplodeSpeed * 3)) {
     SetLed(Ex,Ey,false);                               // Clear explosion
    } else if (Explode == (ExplodeSpeed * 2)) {
     SetLed(Ex,Ey,true);                                // Set explosion
    } else if (Explode == ExplodeSpeed) {
     SetLed(Ex,Ey,false);                               // Clear explosion
    }
  }


// move aliens with tipycal pattern
  if (AlienDelay > AlienSpeed) {                       // speed checking function                 
    AlienDelay = 0;
    if (AlienXs == false) {                            // check direction 
      AlienX++;                                        // direction R 
    } else {
      AlienX--;                                        // direction L 
    } 

    if (MaxAlienX+AlienX > 31) {                       // if last alien on screen reach right edge of screen, invert direction and step down   
      AlienXs = true;                                  // invert direction
      AlienX--;                                         
      AlienY++;                                        // scrolling down aliens
    } else if (MinAlienX+AlienX < 16) {                // if last alien on screen reach left edge of screen, invert direction and step down 
      AlienXs = false;                                 // invert direction
      AlienX++; 
      AlienY++;                                        // scolling down aliens
    }

    if (MaxAlienY+AlienY >= 6) {                       // If aliens reached cannon GAME OVER 
      GameOver();                                      // call gameover function    
    }
    
    PrintAliens(AlienX, AlienY, AlienXo, AlienYo);     // draw updated aliens on screen

    if (AlienSound == 0) {                             // Generate alien sound pattern
      tone(buzzer, NOTE_F3, 100);
      AlienSound =1;
    } else if (AlienSound == 1) {
      tone(buzzer, NOTE_E3, 100);
      AlienSound =2;
    } else if (AlienSound == 2) {
      tone(buzzer, NOTE_D3, 100);
      AlienSound =3;
    } else if (AlienSound == 3) {
      tone(buzzer, NOTE_C3, 100);
      AlienSound =0;
    } else {
      AlienSound = 0;
    }
    AlienXo = AlienX;                                   // store previous alien position offset, used to clear it when moving
    AlienYo = AlienY;
  } else {
    AlienDelay++;
  }
 
// missile management
  if (FireYPos != 0) {                                   // Fire active and check for collisions
    if (FireDelay==0) {                                  // Wait until firedelay was 0 to do next fire step
      FireYPos--;                                        // decrease missile position 
      if (FireYPos < 1) {                                // if missile reached top 
        SetLed(FireXPos,FireYPos,false);                 // Clear missile shadow when reach top
        FireYPos = 0;
      }
      SetLed(FireXPos,FireYPos-1,true);                  // Draw missile

      for (int nal = 0; nal < MaxAliens; nal++) {        // Check for missile collided Alien
        if ((((AliensX[nal]+AlienX)-16) == FireXPos) && (AliensY[nal]+AlienY == FireYPos-1) && (AliensStat[nal] == true)){
          tone(buzzer, NOTE_C4, 100);
          SetLed(FireXPos,FireYPos,false);               // clear Alien fired
          Ex=FireXPos;                                   // Set X of explosion 
          Ey=FireYPos-1;                                 // Set y of explosion
          Explode = 1;                                   // Activate Explosion 
          Score += (6-FireYPos)*4;                       // Increase score
          if (Score >= 9999) Score = 9999;               // Set 9999 limit to High Score due limitation to 4 digit
          if (Score >= HighScore) HighScore = Score;     // Set HiScore
          EEPROMWritelong(0, HighScore);                 // Write HigScore on EEprom
          Serial.print ("Score=");
          Serial.println (Score);
          FireYPos = 0;                                  // Reset Fire status  
          AliensStat[nal] = false;                       // Set alien as fired in the array
          CalcMaxAlien();                                // Calculate new alien edges on screen
          AlienSpeed = (AllKilled * AlienMul) + AlienMul;// set alien speed 

        }      
      }

      if ((FireYPos > 0) && (FireYPos < 6)) {
        SetLed(FireXPos,FireYPos,false);              // clear missile shadow 
      }
    }
    FireDelay++;                                          // increase delay variable
    if (FireDelay > FireSpeed) FireDelay = 0 ;           // check if fredelay reached firespped setting
  }

}

Schematics

Space Invaders
Nano Invaders.fzz
nano_invaders_7wp2Symxp8.fzz

Comments

Similar projects you might like

A Simple Kerbal Space Program Arduino Leonardo Controller

Project showcase by Alan Wang

  • 3,180 views
  • 0 comments
  • 8 respects

Space Trash Game using Arduino and OLED Display

Project tutorial by Pi BOTS MakerHub

  • 1,936 views
  • 3 comments
  • 10 respects

Arduino Simon Says

Project tutorial by Debreczeni Tamas

  • 4,559 views
  • 1 comment
  • 15 respects

LED Roulette Game

Project tutorial by Arduino “having11” Guy

  • 14,436 views
  • 7 comments
  • 23 respects

Arduino Simple Simon Says

Project tutorial by Metonymy

  • 9,149 views
  • 2 comments
  • 11 respects

The Tetris

Project showcase by Archiev Kumar

  • 8,099 views
  • 9 comments
  • 7 respects
Add projectSign up / Login