A skydiving game created using an mbed. This code used threads and mutexes to create a skydiving simulation on an uLCD. The sounds being played are read off of a microSD card and played through the speakers. The user controls the skydiver's movements with a navigation switch.

Dependencies:   4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player

main.cpp

Committer:
mhennessy3
Date:
2016-03-16
Revision:
0:2bc06deb0e7d
Child:
1:d0bc93562029

File content as of revision 0:2bc06deb0e7d:

#include "mbed.h"
#include "rtos.h"
#include "uLCD_4DGL.h"
#include "SDFileSystem.h"
#include "wave_player.h"

uLCD_4DGL uLCD(p28,p27,p30); // serial tx, serial rx, reset pin;
Mutex lcd_mutex;// Create the mutex lock object
PwmOut speaker(p21); //create a PwmOut object for the speaker
SDFileSystem sd(p5, p6, p7, p21, "sd"); //SD card
AnalogOut DACout(p18);
wave_player waver(&DACout);

/////////////////////////////////////////////////////////////////////////////////////////////
//Navigation Switch class
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();
}
 
Nav_Switch myNav( p12, p9, p10, p8, p11); //pin order on Sparkfun breakout


//////////////////////////////////////////////////////////////////////////////////////////////

// initialize variables

int rx1, ry1, rrx1, rry1, rrrx1, rrry1, length;
int rx2, rrx2, rrrx2;
int dis_top, midC, breakT;
int tx1, ty1, lx1, ly1;
int stopLength, circY, parachute;
int shapeColor1, count;
// thread to write to LCD screen
void thread1(void const *args){
    //generates obstacles
    
    while(true){

        lcd_mutex.lock();//acquire lock
        
        //Erase previous position of obstacles
        uLCD.filled_rectangle(rx1, ry1, rx1+10, ry1+10, BLUE);
        uLCD.filled_rectangle(rrx1, rry1, rrx1+10, rry1+10, BLUE);
        uLCD.filled_rectangle(rrrx1, rrry1, rrrx1+10, rrry1+10, BLUE);
         
        if(length<stopLength) {
            //continues the loop from offscreen to back on the screen when within a looped time
            if(ry1<0){
                ry1=137;
                rx1=(rx1+30)%127;
                shapeColor1 = (shapeColor1 + 0x110000) & 0xFFFFFF;
            }
            if(rry1<0){
                rry1=137;
                rrx1=(rrx1+65)%127;
            }
            if(rrry1<0){
                rrry1=137;
                rrrx1=(rrrx1+93)%127;
            }
            if(ly1<0){
                ly1=137;
                lx1 = (lx1+50)%127;
            }
        }
        // update positions of obstacles           
        ry1 = ry1-10;
        rry1 = rry1-10;
        rrry1 = rrry1-10;
        
        ty1 = ty1-10;
        ly1 = ly1-10;
            
        wait(.01);
        // draw updated obstacles
        uLCD.filled_rectangle(rx1, ry1, rx1+10, ry1+10,shapeColor1);//change position
        uLCD.filled_rectangle(rrx1, rry1, rrx1+10, rry1+10,0xFF3300);//change position
        uLCD.filled_rectangle(rrrx1, rrry1, rrrx1+10, rrry1+10,0x99ffcc);//change position
        lcd_mutex.unlock();//release lock
        
        
        //Checking for collisions with obstacles
        rx2 = rx1+10;
        rrx2 = rrx1+10;
        rrrx2 = rrrx1 +10;
        dis_top= 8+7; //y pos of circle +radius 7
        // detect a collision between skydiver and obstacle
        
        //circle 1
        if( (((midC-7)<=rx2 && rx2<=(midC+7)) || ((midC-7)<=rx1 && rx1<=(midC+7))) && ((ry1<dis_top) && (ry1>0))) {
            lcd_mutex.lock();
            uLCD.cls();
            uLCD.text_width(2); //2X size text
            uLCD.text_height(2);
            uLCD.color(RED);
            uLCD.locate(2,2);
            uLCD.printf("\n  GAME \n  OVER!\n");
            wait(.05);
            lcd_mutex.unlock();
            break;   
        }
        
        //circle 2
        if( (((midC-7)<=rrx2 && rrx2<=(midC+7)) || ((midC-7)<=rrx1 && rrx1<=(midC+7))) && ((rry1<dis_top) && (rry1>0))) {
            lcd_mutex.lock();
            uLCD.cls();
            uLCD.text_width(2); //2X size text
            uLCD.text_height(2);
            uLCD.color(RED);
            uLCD.locate(2,2);
            uLCD.printf("\n  GAME \n  OVER!\n");
            wait(.05);
            
            lcd_mutex.unlock();
            break;   
        }
        
        //circle 3
        if( (((midC-7)<=rrrx2 && rrrx2<=(midC+7)) || ((midC-7)<=rrrx1 && rrrx1<=(midC+7))) && ((rrry1<dis_top) && (rrry1>0))) {
            lcd_mutex.lock();
            uLCD.cls();
            uLCD.text_width(2); //2X size text
            uLCD.text_height(2);
            uLCD.color(RED);
            uLCD.locate(2,2);
            uLCD.printf("\n  GAME \n  OVER!\n");
            FILE *wave_file; 
            wave_file=fopen("/sd/mydir/loser.wav","r");
            waver.play(wave_file);
            fclose(wave_file);
            wait(2);
            
            lcd_mutex.unlock();
            break;   
        }
        
        length = length +1; //increment lenght or duration of the number of scrolls it goes through
        Thread::wait(500);
        
        // Begin the final fall to the ground
        if(length>=stopLength+15 && circY<109){
            
            
            //displays text to hit fire while falling until you hit fire and deploy the parachute
            if(count==0){
            lcd_mutex.lock();
            uLCD.text_width(1); //2X size text
            uLCD.text_height(1);
            uLCD.color(GREEN);
            uLCD.locate(2,2);
            uLCD.printf("\n Hit fire for \n a parachute! \n");
            //wait(2);
            lcd_mutex.unlock();
            }
            
            lcd_mutex.lock();
            uLCD.filled_rectangle(0, 128, 128, 118,GREEN);
            uLCD.filled_rectangle(90, 123, 105, 118,RED);
             
            if(parachute==1){
                uLCD.triangle(midC-10,circY -25, midC+10, circY -25, midC, circY -7, BLUE);
            }
            uLCD.filled_circle(midC, circY, 7, BLUE);
            midC = midC-1;
            circY = circY + 2;
            if(parachute==1){
                uLCD.triangle(midC-10,circY -25, midC+10, circY -25, midC, circY -7, BLACK);
            }
            uLCD.filled_circle(midC, circY, 7, BLACK);
        
            lcd_mutex.unlock();//release lock
            
            //if fire is pressed then parachute is deployed
            if(myNav.fire() == 1){
                parachute = 1;
                lcd_mutex.lock();
                uLCD.triangle(midC-10,circY -25, midC+10, circY -25, midC, circY -7, BLACK);
                uLCD.text_width(1); //2X size text
                uLCD.text_height(1);
                uLCD.color(BLUE);
                uLCD.locate(2,2);
                uLCD.printf("\n Hit fire for \n a parachute! \n");
                count = 1;
                lcd_mutex.unlock();
            }
            
            //checking to see if the botton of the circle touched the red space...if so you win
            if(circY+7==117 && (midC<=105 && midC>=90)) {
                lcd_mutex.lock();
                uLCD.text_width(2); //2X size text
                uLCD.text_height(2);
                uLCD.color(GREEN);
                uLCD.locate(2,2);
                if(parachute == 1) {
                    uLCD.printf("\n  You \n  WON!\n");
                    ///////////////////////////////////////////////////////SDcard reading from sound for winning!!!!
                    FILE *wave_file; 
                    wave_file=fopen("/sd/mydir/yababy.wav","r");
                    waver.play(wave_file);
                    fclose(wave_file);
                }
                
                //if you don't deploy your parachute but still land ont he red, you still lose
                if(parachute == 0) {
                    uLCD.printf("\n  You \n  lost.\n");
                    // SDcard reading for losing
                    FILE *wave_file; 
                    wave_file=fopen("/sd/mydir/loser.wav","r");
                    waver.play(wave_file);
                    fclose(wave_file);
                }
                lcd_mutex.unlock();
            }
            
            //checks to see if you touch green part of the ground
            if(circY+7>=117 && (midC>105 || midC<90)) {
                lcd_mutex.lock();
                uLCD.text_width(2); //2X size text
                uLCD.text_height(2);
                uLCD.color(GREEN);
                uLCD.locate(2,2);
                uLCD.printf("\n  You \n  lost.\n");
                // SDcard reading for losing
                FILE *wave_file; 
                wave_file=fopen("/sd/mydir/loser.wav","r");
                waver.play(wave_file);
                fclose(wave_file);
                //wait(2);
                lcd_mutex.unlock(); 
            } 
        }
    }
}

/*// Sound Thread for Wind
void thread2(void const *args) {
    if(parachute == 1) {
                FILE *wave_file; 
                wave_file=fopen("/sd/mydir/Wind.wav","r");
                waver.play(wave_file);
                fclose(wave_file);
    }
}*/

int main() {

    //uLCD.text_mode(OPAQUE);
    // Initial start screen and countdown to beginning of game
    uLCD.printf("\nSkydiving!\n"); //Default Green on black text
    uLCD.printf("\n  Starting Game \nShortly...");
    uLCD.text_width(4); //4X size text
    uLCD.text_height(4);
    uLCD.color(RED);
    wait(2);
    for (int i=3; i>=0; --i) {
        uLCD.locate(1,2);
        uLCD.printf("%2D",i);
        wait(1);
    }
    uLCD.cls();
    //uLCD.printf("Change baudrate......");
    uLCD.baudrate(3000000); //jack up baud rate to max for fast display
    //if demo hangs here - try lower baud rates
    //
    // printf text only full screen mode demo
    uLCD.background_color(BLUE);
    uLCD.cls();
    uLCD.locate(0,0);
    uLCD.color(WHITE);
    
    uLCD.textbackground_color(BLUE);
    uLCD.set_font(FONT_7X8);
    uLCD.text_mode(OPAQUE);



    //initialization of variables
    circY = 8;
    rx1 = 10; 
    ry1 = 160;
    rrx1 = 50; 
    rry1 = 128;
    rrrx1 = 100;
    rrry1 = 200;
    
    tx1=10;
    ty1=30;
    
    lx1 = 25;
    ly1 = 130;
    
    
    length =0;
    midC = 64;
    breakT = 0;
    stopLength = 50;
    shapeColor1 = 0x66FF33;
    
    uLCD.filled_circle(midC, 8, 7, BLACK); // draw initial skydiver
    

    // draw initial obstacles
    uLCD.filled_rectangle(rx1, ry1, rx1+10, ry1+10, WHITE);
    uLCD.filled_rectangle(rrx1, rry1, rrx1+10, rry1+10, WHITE);
    uLCD.filled_rectangle(rrrx1, rrry1, rrrx1+10, rrry1+10, WHITE);
    
    uLCD.filled_circle(midC, circY, 7, BLACK);

    ///// Sound of Scream jumping out of Airplane
    FILE *wave_file; 
    wave_file=fopen("/sd/mydir/scream_male.wav","r");
    waver.play(wave_file);
    fclose(wave_file);
    //// End Scream
    Thread t1(thread1);
    //Thread t2(thread2);
    
    while(true) {  
        if(breakT ==1){
            uLCD.cls();
            uLCD.filled_circle(midC, circY, 7, BLACK); 
        }
        
        
        //control if nav switch is switch left
        if(myNav.left() == 0x01){
            lcd_mutex.lock();//acquire lock
            if(parachute==1){
                uLCD.triangle(midC-10,circY -25, midC+10, circY -25, midC, circY -7, BLUE);
            }
            uLCD.filled_circle(midC, circY, 7, BLUE);
            if((midC-1)<=7){
                midC = 7;    
            }
            else{
                midC = midC-1;
            }
            if(parachute==1){
                uLCD.triangle(midC-10,circY -25, midC+10, circY -25, midC, circY -7, BLACK);
            }
            uLCD.filled_circle(midC, circY, 7, BLACK);
            lcd_mutex.unlock();//release lock
        }
        
        //control if nav switch is switched right
        if(myNav.right() == 0x01){
            lcd_mutex.lock();//acquire lock
            if(parachute==1){
                uLCD.triangle(midC-10,circY -25, midC+10, circY -25, midC, circY -7, BLUE);
            }
            uLCD.filled_circle(midC, circY, 7, BLUE);
            if((midC+1)>=120){
                midC = 120;    
            }
            else{
                midC = midC+1;
            }
            if(parachute==1){
                uLCD.triangle(midC-10,circY -25, midC+10, circY -25, midC, circY -7, BLACK);
            }
            uLCD.filled_circle(midC, circY, 7, BLACK);
            lcd_mutex.unlock();//release lock
        } 
    }    
}