Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: 4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player
SharpShooter
Overview¶
SharpShooter is a hyper-interactive third person shooting game. Your job is to complete all three levels by shooting the targets using timing and accuracy. As the levels increase, you will face more moving obstacles that will block your shot and test your shooting expertise.
Gameplay¶
Controls¶
Using Navigation Switch or Joystick:
- Left = Move Left
- Right = Move Right
- Center = Shoot
Links to Necessary Components¶
Joystick: https://developer.mbed.org/users/4180_1/notebook/using-a-navigation-switch-digital-joystick/
uLCD: https://developer.mbed.org/users/4180_1/notebook/ulcd-144-g2-128-by-128-color-lcd/
sD Card Reader: https://developer.mbed.org/cookbook/SD-Card-File-System
Amplifier (TPA2005D1 Class D) and Speaker: https://developer.mbed.org/users/4180_1/notebook/tpa2005d1-class-d-audio-amp/
Code¶
Import programECE4180_Lab4_Sharpshooter
SharpShooter
MainGame.cpp
#include "mbed.h"
#include "Speaker.h"
#include "uLCD_4DGL.h"
#include "SDFileSystem.h"
#include "wave_player.h"
#include "Nav_Switch.h"
#include "rtos.h"
#include "Obstacle.h"
#include "Shooter.h"
#include "Bullet.h"
/*DIRECTIVES*/
#define NUMTRIES 10
/*INSTANTIATION*/
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);
InterruptIn center(p25);
InterruptIn left(p26);
InterruptIn right(p28);
uLCD_4DGL uLCD(p9,p10,p11); // serial tx, serial rx, reset pin;
Nav_Switch myNav( p24, p25, p26, p27, p28); //up, down, left, right, fire
SDFileSystem sd(p5, p6, p7, p8, "sd");
AnalogOut DACout(p18);
wave_player waver(&DACout);
Shooter player1;
Bullet bullet;
bool isBullet;
Mutex mutex;
/*STRUCT INITIALIZATION*/
struct TargetLocation {
int x,y,r;
};
/*GLOBAL VARIABLES*/
int numTries;
int levelNum;
BulletLocation bulletLocation;
Obstacle obsArr[3];
TargetLocation * targetsPtr = new TargetLocation[3];
bool play = 0;
int targetY = 15;
int targetRad = 5;
int targetsLeft = 3;
bool targetsHit[3];
void startGame() {
uLCD.background_color(BACKGROUND);
uLCD.filled_rectangle(0,0,127,127,BLUE);
uLCD.locate(3,6);
uLCD.printf("Sharp Shooter!");
wait(0.1);
FILE *wave_file;
wave_file=fopen("/sd/wavfiles/intro.wav","r");
waver.play(wave_file);
fclose(wave_file);
wait(0.3);
uLCD.cls();
}
void createTargets() {
//draw all targets
uLCD.filled_circle(24,targetY,targetRad,TARGET);
uLCD.filled_circle(64,targetY,targetRad,TARGET);
uLCD.filled_circle(104,targetY,targetRad,TARGET);
targetsLeft = 3;
for (int i=0; i<targetsLeft; i++) {
targetsHit[i] = 0;
}
}
void createShooter() {
player1.drawShooter();
}
void createObstacles(int num) {
//instantiate obstacles and store in obsArr
if (num == 1) { //if Level 1
obsArr[0] = Obstacle(2, 62, 50, 65);
obsArr[0].setDirection(1);
} else if (num == 2) { //if Level 2
obsArr[0] = Obstacle(2, 62, 50, 65);
obsArr[0].setDirection(1);
obsArr[1] = Obstacle(67, 32, 115, 35);
obsArr[1].setDirection(0);
} else if (num == 3) { //if Level 3
obsArr[0] = Obstacle(2, 62, 50, 65);
obsArr[0].setDirection(1);
obsArr[1] = Obstacle(67, 32, 115, 35);
obsArr[1].setDirection(0);
obsArr[2] = Obstacle(48, 48, 96, 51);
obsArr[2].setDirection(1);
}
//draw obstacles
for (int i = 0; i < num; i++) {
obsArr[i].drawObstacle();
}
}
void drawHeader() {
mutex.lock();
if (numTries>=9) uLCD.filled_rectangle(0,0,128,7,BLACK); //clear header if over double digits
uLCD.locate(0,0);
uLCD.printf("LEVEL:%d BULLETS:%d", levelNum, numTries);
mutex.unlock();
}
void initializeLevel() {
mutex.lock();
uLCD.cls();
mutex.unlock();
numTries = NUMTRIES;
drawHeader();
createTargets();
createObstacles(levelNum);
createShooter();
}
void gameOver() {
play = 0;
mutex.lock();
uLCD.filled_rectangle(0,0,127,127,RED);
uLCD.locate(5,6);
uLCD.printf("GAM3 0V3R");
mutex.unlock();
FILE *wave_file;
wave_file=fopen("/sd/wavfiles/gameover.wav","r");
waver.play(wave_file);
fclose(wave_file);
while(1); //gameOver screen forever
}
void removeBullet() {
bullet.eraseBullet();
isBullet = 0;
numTries -= 1;
drawHeader();
if (numTries==0 && targetsLeft>0) gameOver();
}
void killTarget(BulletLocation currBullet,int i) {
targetsHit[i] = 1;
targetsLeft -= 1;
uLCD.filled_circle(currBullet.x,targetY,targetRad,BLUE);
uLCD.line(currBullet.x-targetRad,targetY+targetRad,currBullet.x+targetRad,targetY-targetRad,BLACK);
uLCD.line(currBullet.x-targetRad,targetY-targetRad,currBullet.x+targetRad,targetY+targetRad,BLACK);
FILE *wave_file;
wave_file=fopen("/sd/wavfiles/hittarget.wav","r");
waver.play(wave_file);
fclose(wave_file);
}
void movingBullet(void const *args) {
while (true) {
if(isBullet) {
mutex.lock();
bullet.move();
// Remove bullet if it hits an obstacle
ObstLocation currObs;
BulletLocation currBullet;
for (int i=0; i<levelNum; i++) {
currObs = obsArr[i].getLocation(); // {x1, y1, x2, y2}
currBullet = bullet.getLocation(); // {x, topY, bottomY}
if ((currBullet.topY<=currObs.y2 && currBullet.topY>=currObs.y1) || (currBullet.bottomY<=currObs.y2 && currBullet.bottomY>=currObs.y1)) {
if (currBullet.x>=currObs.x1 && currBullet.x<=currObs.x2) {
removeBullet();
FILE *wave_file;
wave_file=fopen("/sd/wavfiles/hitobstacle.wav","r");
waver.play(wave_file);
fclose(wave_file);
}
}
}
// Remove bullet, and draw dead target if it hits a target
if (currBullet.topY<=targetY+targetRad) {
//if target is already hit
if (currBullet.x==24 && targetsHit[0]==0) killTarget(currBullet,0);
if (currBullet.x==64 && targetsHit[1]==0) killTarget(currBullet,1);
if (currBullet.x==104 && targetsHit[2]==0) killTarget(currBullet,2);
removeBullet();
}
mutex.unlock();
Thread::wait(100);
}
}
}
void movingObs(void const *args) {
while (true) {
if(play) {
mutex.lock();
if (levelNum == 1) {
obsArr[0].move(3);
} else if (levelNum == 2) {
obsArr[0].move(3);
obsArr[1].move(6);
} else if (levelNum == 3) {
obsArr[0].move(3);
obsArr[1].move(6);
obsArr[2].move(9);
}
mutex.unlock();
Thread::wait(500);
}
}
}
void shoot() {
if (!isBullet) {
bullet.drawBullet(player1.getLocation(), 115);
isBullet = 1;
FILE *wave_file;
wave_file=fopen("/sd/wavfiles/shoot.wav","r");
waver.play(wave_file);
fclose(wave_file);
}
}
int main() {
levelNum = 1;
isBullet = 0;
Thread bulletThread(movingBullet);
Thread obstacleThread(movingObs);
startGame();
while(1) {
initializeLevel();
play = 1;
while (play) { //actual game play code
if(targetsLeft==0) {
play = 0;
levelNum++;
}
if(!right.read()) player1.moveRight();
if(!left.read()) player1.moveLeft();
if(!center.read()) shoot();
wait(0.12);
}
}
}
