Metroid Sidescroller Game
Overview
For our project, we made a sidescroller very loosely based on Metroid. This game uses the joystick to control the character and fire a shot at the oncoming metroids. If the metroids touch the player character, the character loses one point of health. At the loss of all points of health, the game ends. The joystick center button is used to fire the weapon, and cardinal directions are used for jumping, crouching, and movement left and right. One SD card is used for the image at the end, the other is used for the audio.
Components
- mbed LPC1768
- uLCD-144-G2 128 by 128 Smart Color LCD
- Sparkfun 5-Way Tactile Switch Breakout
- Sparkfun microSD Transflash Breakout
- Sparkfun PCB mount Speaker (8 Ohm, .1W)
- Either (2N3904 BJT) or (TI TPA2005D1 Class D Audio Amplifier)
- (Optional) 10KOhm Potentiometer for Volume Control
Wiring
Mbed | SD Card Reader |
---|---|
p5 | DI |
p6 | DO |
p7 | SCK |
p8 | CS |
GND | GND |
Vout | VCC |
Mbed | uLCD |
---|---|
p9 TX | RX |
p10 RX | TX |
p11 | Reset |
Vu | 5V |
GND | GND |
Mbed | Joystick |
---|---|
p12 | Up |
p13 | Center |
p14 | Left |
p15 | Down |
p16 | Right |
GND | - |
NC | + |
If Using Transistor and Speaker
Mbed | BJT | Speaker |
---|---|---|
p18 | Base | |
GND | Emitter | |
Collector | - | |
Vout | + |
If Using Audio Breakout and Potentiometer
Mbed | Audio Breakout | Potentiometer | Speaker |
---|---|---|---|
p18 | In+ | ||
GND | In-, Pwr-, | ||
Vu | Pwr+ | ||
Out+ | + | ||
Out- | - | ||
VOL pins | 1 pin/VOL pin |
Program
Main.cpp
main.cpp
#include <mbed.h> #include "uLCD_4DGL.h" #include "SDFileSystem.h" #include "wave_player.h" #include <rtos.h> #include <graphics.h> //define joystick DigitalIn up(p12); DigitalIn fire(p13); DigitalIn left(p14); DigitalIn down(p15); DigitalIn right(p16); DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); //define uLCD uLCD_4DGL ulcd(p9,p10,p11); //define sd card reader SDFileSystem sd(p5, p6, p7, p8, "sd"); //define speaker AnalogOut DACout(p18); wave_player waver(&DACout); //Mutex for uLCD Mutex uLCD_mutex; FILE *wave_file; Samus samus; Gunshot gunshot; Metroid metroid; bool GameOver=0; bool dFormula(int ux, int uy, int mx, int my) { double ans,dx,dy; dx = mx-ux; dy = my-uy; ans = sqrt((dx*dx)+(dy*dy)); if(ans<=8) return 1; else return 0; } void sound(void const *args){ while(true){ wave_file=fopen("/sd/brinstar.wav", "r"); led1 =1; waver.play(wave_file); led2 = 1; fclose(wave_file); Thread::wait(500); } } int main(){ Thread soundthread(sound); Thread::wait(1000); int score = 0; up.mode(PullUp); fire.mode(PullUp); left.mode(PullUp); right.mode(PullUp); down.mode(PullUp); Thread::wait(25); ulcd.filled_rectangle(samus.xpos,samus.ypos,samus.xpos-4,samus.ypos-samus.currentheight,0xFFA500); ulcd.filled_circle(118, 8, 3, RED); ulcd.filled_circle(108, 8, 3, RED); ulcd.filled_circle(98, 8, 3, RED); // while(1); while(!GameOver){ ulcd.locate(0,0); ulcd.printf("Score: %i", score); if(samus.isJumping){ samus.prevypos = samus.ypos; samus.prevxpos = samus.xpos; if(samus.jump<5){ samus.ypos -= 3; samus.jump += 1; ulcd.filled_rectangle(samus.prevxpos+1,samus.prevypos,samus.prevxpos-5,samus.prevypos-samus.height, BLACK); } else if(samus.jump<10){ samus.ypos += 3; samus.jump += 1; ulcd.filled_rectangle(samus.prevxpos+1,samus.prevypos,samus.prevxpos-5,samus.prevypos-samus.height, BLACK); } else{ samus.jump = 0; samus.isJumping = 0; } } ulcd.filled_rectangle(samus.xpos,samus.ypos,samus.xpos-4,samus.ypos-samus.currentheight,0xFFA500); if((up==0) && (!samus.crouch)) samus.isJumping = 1; if(down==0 && (!samus.isJumping)){ samus.crouch = !samus.crouch; if (samus.crouch==1){ samus.currentheight=samus.crouchheight; ulcd.filled_rectangle(samus.xpos,samus.ypos,samus.xpos-4,samus.ypos-samus.height, BLACK); ulcd.filled_rectangle(samus.xpos,samus.ypos,samus.xpos-4,samus.ypos-samus.currentheight,0xFFA500); } else{ samus.currentheight=samus.height; } } if(right==0){ samus.prevxpos=samus.xpos; samus.xpos=samus.xpos+1; ulcd.filled_rectangle(samus.prevxpos, samus.prevypos, samus.prevxpos-4, samus.prevypos-samus.currentheight, BLACK); ulcd.filled_rectangle(samus.xpos,samus.ypos,samus.xpos-4,samus.ypos-samus.currentheight,0xFFA500); } if(left==0){ samus.prevxpos=samus.xpos; samus.xpos=samus.xpos-1; ulcd.filled_rectangle(samus.prevxpos, samus.prevypos, samus.prevxpos-4, samus.prevypos-samus.currentheight, BLACK); ulcd.filled_rectangle(samus.xpos,samus.ypos,samus.xpos-4,samus.ypos-samus.currentheight,0xFFA500); } if((fire==0)&&(!gunshot.isOnScreen)){ gunshot.isOnScreen = 1; gunshot.xpos=samus.xpos; gunshot.ypos=samus.ypos-(samus.currentheight*.5); gunshot.prevxpos=gunshot.xpos; gunshot.prevypos=gunshot.ypos; } for(int j=0; j<3;j++){ if((rand()%30 == 1)&&(!metroid.isAlive[j])){ metroid.isAlive[j] = 1; metroid.xpos[j]=0; metroid.ypos[j]=(123-(rand()%15)); ulcd.filled_circle(metroid.xpos[j], metroid.ypos[j], metroid.radius, WHITE); } } if (gunshot.xpos<=0){ gunshot.isOnScreen=0; ulcd.filled_circle(gunshot.xpos, gunshot.ypos, gunshot.radius, BLACK); } if (gunshot.isOnScreen){ ulcd.filled_circle(gunshot.xpos, gunshot.ypos, gunshot.radius, BLACK); gunshot.Move(); ulcd.filled_circle(gunshot.xpos, gunshot.ypos, gunshot.radius, BLUE); } for(int j =0; j<3; j++){ if ((dFormula(gunshot.xpos,gunshot.ypos,metroid.xpos[j],metroid.ypos[j])) && (metroid.isAlive[j]) && (gunshot.isOnScreen)){ metroid.isAlive[j]=0; gunshot.isOnScreen=0; score++; ulcd.filled_circle(gunshot.xpos, gunshot.ypos, gunshot.radius, BLACK); ulcd.filled_circle(metroid.xpos[j], metroid.ypos[j], metroid.radius, BLACK); } } for(int j =0; j<3; j++){ if (metroid.isAlive[j]){ ulcd.filled_circle(metroid.xpos[j],metroid.ypos[j],metroid.radius,BLACK); metroid.Move(j); ulcd.filled_circle(metroid.xpos[j],metroid.ypos[j],metroid.radius,WHITE); } } for(int j =0; j<3; j++){ if ((metroid.isAlive[j]) && (metroid.xpos[j]>=128)){ metroid.isAlive[j] = 0; ulcd.filled_circle(metroid.xpos[j],metroid.ypos[j],metroid.radius,BLACK); } } for(int j =0; j<3; j++){ if ((dFormula(samus.xpos-2,samus.ypos-.5*samus.currentheight,metroid.xpos[j],metroid.ypos[j])) && metroid.isAlive[j]){ metroid.isAlive[j] = 0; ulcd.filled_circle(metroid.xpos[j],metroid.ypos[j],metroid.radius,BLACK); samus.health=samus.health-1;} } if (samus.health==2) ulcd.filled_circle(118, 8, 3, BLACK); else if (samus.health==1) ulcd.filled_circle(108, 8, 3, BLACK); if(samus.health==0){ GameOver=1; soundthread.terminate(); } } DACout = 0.0; Thread::wait(50); ulcd.cls(); //ulcd.media_init(); //ulcd.set_sector_address(0x0000, 0x0000); //ulcd.display_image(0,0); ulcd.printf("Game Over"); Thread::wait(3000); ulcd.cls(); FILE *fp = fopen("/sd/highscore.txt", "rw"); // open the file in 'read' mode char c[1]; //string sc; fgets(c,1,fp); // get a character/byte from the file if(score > atoi(c)){ ulcd.printf("You Beat the High Score\nYour Score: %i",score); sprintf(c,"%d",score); fprintf(fp,c);} else ulcd.printf("You Did Not Beat the High Score\nHigh Score: %c",c); fclose(fp); }
Please log in to post comments.