SharpShooter

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

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);
        }
    }
}


All wikipages