Galaga
Introduction
This page shows the code and pin connections for a retro style Galaga game. The game consists of a space ship with horizontal capability of moving left and right and the ability to shoot missiles at enemy intruders. The intruders start at the top of the screen and make their way towards the space craft. The goal is to shoot your missiles and destroy your enemies before your enemies get to you.
Devices used:
- SD Card
- Class D Amplifier
- uLCD
- Haptic Feedback Motor
- 2N3904 NPN BJT (including 1Kohm resistor)
- Potentiometer
Pin connections made
| mbed | Device |
|---|---|
| p18 | Class D + In |
| p27 | uLCD RX |
| p29 | uLCD Reset |
| p28 | uLCD TX |
| p6 | SD DO |
| p7 | SD SCK |
| p8 | SD CS |
| p6 | SD DO |
| p5 | SD DI |
| p16 | Nav U |
| p15 | Nav C |
| p14 | Nav L |
| p13 | Nav D |
| p12 | Nav R |
| p21 | Transistor Base in series with 1Kohm |
| Class D Amp | Device |
|---|---|
| Out + | Speaker + |
| Out- | Speaker - |
| Pwr - | Gnd |
| Pwr+ | VCC |
| Vol(3) | Potentiometer |
| Haptic Feedback | Connection |
|---|---|
| Red wire | VCC |
| Blue wire | BJT Collector |
| Gnd | BJT Emitter |
Import programGalaga
Mbed Galaga Game
Program Code
Mbed Galaga
#include "mbed.h"
#include "uLCD_4DGL.h"
#include "wave_player.h"
#include "SDFileSystem.h"
//#include "enemies.h"
#include <vector>
#include "rtos.h"
uLCD_4DGL uLCD(p28,p27,p29);
AnalogOut DACout(p18);
DigitalOut vib(p21);
wave_player waver(&DACout);
SDFileSystem sd(p5, p6, p7, p8, "sd"); // mosi, miso, sck, cs
BusOut mbedleds(LED1,LED2,LED3,LED4);
//BusOut/In is faster than multiple DigitalOut/Ins
int playLaser = 0;int playEnemyExplode = 0;int playerExplode = 0;//variables to trigger the speaker to play sounds
void sdcard_thread(void const *argument)//thread to play the sounds
{
while(1) {
if(playLaser){//play sound if player fires
FILE *wave_file;
wave_file=fopen("/sd/laser.wav","r");
waver.play(wave_file);
fclose(wave_file);
playLaser = 0;
}
if(playerExplode) { //play sound if player dies
FILE *wave_file;
wave_file=fopen("/sd/Bomb.wav","r");
waver.play(wave_file);
fclose(wave_file);
playerExplode = 0;
}
if(playEnemyExplode){//play sound if enemies get hit
FILE *wave_file;
wave_file=fopen("/sd/Bombnew.wav","r");
waver.play(wave_file);
fclose(wave_file);
playEnemyExplode = 0;
}
Thread::wait(50);
}
}
class Nav_Switch
{
public:
Nav_Switch(PinName up,PinName down,PinName left,PinName right,PinName fire);
int read();
//boolean functions to test each switch
bool up();
bool down();
bool left();
bool right();
bool fire();
//automatic read on RHS
operator int ();
//index to any switch array style
bool operator[](int index) {
return _pins[index];
};
private:
BusIn _pins;
};
Nav_Switch::Nav_Switch (PinName up,PinName down,PinName left,PinName right,PinName fire):
_pins(up, down, left, right, fire)
{
_pins.mode(PullUp); //needed if pullups not on board or a bare nav switch is used - delete otherwise
wait(0.001); //delays just a bit for pullups to pull inputs high
}
inline bool Nav_Switch::up()
{
return !(_pins[0]);
}
inline bool Nav_Switch::down()
{
return !(_pins[1]);
}
inline bool Nav_Switch::left()
{
return !(_pins[2]);
}
inline bool Nav_Switch::right()
{
return !(_pins[3]);
}
inline bool Nav_Switch::fire()
{
return !(_pins[4]);
}
inline int Nav_Switch::read()
{
return _pins.read();
}
inline Nav_Switch::operator int ()
{
return _pins.read();
}
// Declar player dimensions
int playerWidth = 7;
int playerHeight = 3;
int playerDelta = 3;
int playerXpos = 64;
int playerYpos = 113;
#define maxNumPlayerMissiles 5
#define numEnemies 10
//struct for missiles
typedef struct {
int x; ///< The x-coordinate of missile current position
int y; ///< The y-coordinate of missile current position
int status; ///< The missile status, see MISSILE_STATUS
} playerMissile; // infomration about missile position and status
//struct for enemies
typedef struct {
int x;
int y;
int size;
int status;
} enemy;
enemy enemies[numEnemies];//create a struct array of enemies
// initialize the player's position, missile status, draw player,
void player_draw(int x, int y, int playerColor) {
uLCD.filled_rectangle(x, y, x+playerWidth, y+playerHeight, playerColor);
uLCD.filled_rectangle(x+playerDelta, y-playerDelta, x+playerWidth-playerDelta, y+playerHeight, playerColor);
}
playerMissile playerMissiles[maxNumPlayerMissiles]; //struct array of player missiles
//function to fire a missile
void player_fire(void){
playerMissile PM;
PM.x = playerXpos + (playerWidth/2);
PM.y = playerYpos-playerDelta;
PM.status = 1;
for(int i=0;i<maxNumPlayerMissiles;i++){
if(playerMissiles[i].status==0){
playerMissiles[i]=PM;
break;
}
}
}
//function to update all parts of the game
void updateGame(){
for(int i=0;i<maxNumPlayerMissiles;i++){
// update all missiles
if(playerMissiles[i].status == 1){
uLCD.circle(playerMissiles[i].x,playerMissiles[i].y,1,0x0);
playerMissiles[i].y-=5;
uLCD.circle(playerMissiles[i].x,playerMissiles[i].y,1,0xFF0000);
}
if(playerMissiles[i].y==0 || playerMissiles[i].status==0){
uLCD.circle(playerMissiles[i].x,playerMissiles[i].y,1,0x0);
playerMissiles[i].status = 0;
}
//update all enemies
for(int j=0;j<numEnemies;j++){
if(playerMissiles[i].status==1 && enemies[j].status==1 && playerMissiles[i].x>enemies[j].x && playerMissiles[i].x<enemies[j].x+enemies[j].size && playerMissiles[i].y>enemies[j].y && playerMissiles[i].y<enemies[j].y+enemies[j].size){
enemies[j].status = 0;
playerMissiles[i].status = 0;
playEnemyExplode=1;
uLCD.filled_rectangle(enemies[j].x,enemies[j].y,enemies[j].x+enemies[j].size,enemies[j].y+enemies[j].size,0x0);
}
}
}
}
//function to set initial position of enemies
void enemies_init(void){
enemies[0].x = 1;enemies[0].y = 1;enemies[0].size = 8;
enemies[1].x = 26;enemies[1].y = 1;enemies[1].size = 8;
enemies[2].x = 51;enemies[2].y = 1;enemies[2].size = 8;
enemies[3].x = 76;enemies[3].y = 1;enemies[3].size = 8;
enemies[4].x = 101;enemies[4].y = 1;enemies[4].size = 8;
enemies[5].x = 1;enemies[5].y = 20;enemies[5].size = 8;
enemies[6].x = 26;enemies[6].y = 20;enemies[6].size = 8;
enemies[7].x = 51;enemies[7].y = 20;enemies[7].size = 8;
enemies[8].x = 76;enemies[8].y = 20;enemies[8].size = 8;
enemies[9].x = 101;enemies[9].y = 20;enemies[9].size = 8;
}
Nav_Switch myNav( p15, p12, p13, p11, p14); //pin order on Sparkfun breakout
int main()
{
Thread thread1(sdcard_thread);
int ctr = 0;int distance=5;int vertical = 1;int win = 1;int numDeadEnemies=0;
//initialize enemy statuses
enemies[0].status = 1;enemies[1].status = 1;enemies[2].status = 1;enemies[3].status = 1;enemies[4].status = 1;
enemies[5].status = 1;enemies[6].status = 1;enemies[7].status = 1;enemies[8].status = 1;enemies[9].status = 1;
enemies_init();
//draw enemies
for(int i=0;i<numEnemies;i++){
uLCD.filled_rectangle(enemies[i].x,enemies[i].y,enemies[i].x+enemies[i].size,enemies[i].y+enemies[i].size,0x00FF00);
}
int i;
while(1) {
//with pullups a button hit is a "0" - "~" inverts data to leds
if(ctr%10==0){
for(i=0;i<numEnemies;i++){
if(enemies[i].status!=0){
//update enemy positions
uLCD.filled_rectangle(enemies[i].x,enemies[i].y,enemies[i].x+enemies[i].size,enemies[i].y+enemies[i].size,0x0);
if(vertical<0){enemies[i].x+=distance;}else{enemies[i].y+=5;}
uLCD.filled_rectangle(enemies[i].x,enemies[i].y,enemies[i].x+enemies[i].size,enemies[i].y+enemies[i].size,0x00FF00);
}
}
if(vertical<0){distance*=-1;}vertical*=-1;
}
mbedleds = ~(myNav & 0x0F); //update leds with nav switch direction inputs
if(myNav.fire()){//fire missile
vib = 1;
Thread::wait(100);
vib=0;
playLaser = 1;
player_fire();
mbedleds = 0x0F; //special all leds on case for fire (center button)
}
//or use - if(myNav[4]==0) mbedleds = 0x0F; //can index a switch bit like this
if(myNav.right() && playerXpos <= 110){//player moves right
player_draw(playerXpos,playerYpos,0x0);
playerXpos+=5;
}
if(myNav.left() && playerXpos >= 0){//player moves left
player_draw(playerXpos,playerYpos,0x0);
playerXpos-=5;
}
player_draw(playerXpos,playerYpos,0xFFFF00);//draw the player
updateGame();
//check if player has been hit
for(i=0;i<numEnemies;i++){
if(enemies[i].status==1 && playerXpos>enemies[i].x && playerXpos<enemies[i].x+enemies[i].size && playerYpos>enemies[i].y && playerYpos<enemies[i].y+enemies[i].size){
player_draw(playerXpos,playerYpos,0x0);win=0;playerExplode=1;vib=1;
}
if(enemies[i].status==0)numDeadEnemies++;
if(enemies[i].y>128)enemies[i].y=1;
}
// check for end game conditions
if(numDeadEnemies==numEnemies){Thread::wait(1000);break;}
if(!win){Thread::wait(1000);vib=0;playerExplode=0;break;}
numDeadEnemies = 0;
ctr++;
Thread::wait(10);
}
uLCD.locate(5,5);
if(win){
uLCD.printf("You Win!!");
}else{
uLCD.printf("GAME OVER");
}
}
Breadboard Overview
YouTube Link
Please log in to post comments.
