ECE 4180 - Target Shooting Game

/media/uploads/Luke95/img_20161108_153147.jpg

Overview

This notebook page details a target shooting game using the LCD screen, controlled by a 5-way tactile switch and pushbutton. The goal of the game is to score as many points as possible by shooting down targets as they fly randomly across the screen, at gradually increasing speeds. The tactile switch move the firing reticle around the screen, and the pushbutton fires. The player has 60 seconds to shoot as many targets as possible.

The code for this game was written in C++ using the mbed cloud compiler.

Demonstration

Here is included a video demonstration of the target shooting game being played.

Hardware

The game uses a Sparkfun Nav Switch and pullup pushbutton for controls, a uLCD-144-G2 screen for display, a Sparkfun Micro SD breakout board for loading sound, and a Sparkfun breadboard mount speaker with a Sparkfun TI TPA2005D1 class D audio amp chip for playing sound. Additionally, an external power supply of 5V is used for the audio amp. /media/uploads/Luke95/img_20161108_153040.jpg /media/uploads/Luke95/img_20161108_153002.jpg

uLCD Wiring

mbeduLCD Header
5V = Vu+5V
GndGnd
Tx = P13Rx
Rx = P14Tx
P12Reset

Sparkfun Nav Switch Wiring

mbedSparkfun Nav Switch Breakout
gnd-
p20U - up
p19C - center or fire
p17L - left
p16D - down
p15R - right
nc - using internal pullups+

MicroSD Breakout Wiring

mbedMicroSD Breakout
p8CD
p5DI
VOUTVCC
p7SCK
GNDGND
p6DO
CD

Speaker and Amp

mbedTPA2005D1Speaker
gndpwr-(gnd), in-
+5Vpwr+
p18in+
out++
out--

Code

Import programTargetShootingGame

A game using a navswitch and the LCD screen where you see how many targets you can shoot.

Main

int main()
{
{
 uLCD.cls();
 }
  fire.mode(PullUp);
    uLCD.baudrate(3000000); //jack up baud rate to max for fast display
    uLCD.text_width(2); //2x size text
    uLCD.text_height(2);
    Thread thread1(music_thread);
    Thread thread2(control_thread);
    
    Timer t;
    t.reset();
    t.start();

    tS = rand()%(int)speedCap + 1;
    chooseColor();
    targetPat = rand()%8;
    while (true) {
        while(t.read() < 60){
        uLCD.cls();
        //uLCD.locate(0,0);
        //uLCD.printf("tS: %i tX: %i tY: %i", tS, tX, tY);
        drawTarg();
        if(fire)
            drawCurs(curX, curY, curCol);
        else
            drawCurs(curX, curY, RED);
        
        if(!fire && curX > tX - 6 && curX < tX + 6 && curY > tY - 6 && curY < tY + 6)
        {
            tBroken = true;
            score++;
        }
        
        if(tX > 128 || tX < 0 || tY > 128 || tY < 0)
        {   switch(rand()%4) {
                case 0: uLCD.background_color(PURPLE);
                    curCol = WHITE;
                    break;
                case 1: uLCD.background_color(YELLOW);
                    curCol = BLACK;
                    break;
                case 2: uLCD.background_color(ORANGE);
                    curCol = BLACK;
                    break;
                case 3: uLCD.background_color(BLACK);
                    curCol = WHITE;
            }
                
            chooseColor();
            targetPat = rand()%8;
            speedCap += .5;
            tS = rand()%(int)speedCap + 1;
            switch(targetPat) {
                case 0: tX = rand()%64 + 32;
                    tY = 128;
                    break;
                case 1: tX = 0;
                    tY = 128;
                    break;
                case 2: tX = 0;
                    tY = rand()%64 + 32;
                    break;
                case 3: tX = 0;
                    tY = 0;
                    break;
                case 4: tX = rand()%64 + 32;
                    tY = 0;
                    break;
                case 5: tX = 128;
                    tY = 0;
                    break;
                case 6: tX = 128;
                    tY = rand()%64 + 32;
                    break;
                case 7: tX = 128;
                    tY = 128;
                    break;
            }
            tBroken = false;
        }
    }
    gameOver = true;
    tBroken = true;
    uLCD.background_color(BLACK);
    uLCD.cls();
    uLCD.locate(0,3);
    uLCD.printf("Your Score: %i", score);
    while(gameOver){}
    }
}

The main loop draw the cursor and target, and determines if the target has been hit or moved off-screen. Once the target is no longer on the screen, the main loop determines a new location, movement pattern, and color for the target, as well as a new background color. Finally, once 60 seconds have passed the main loop resets the background to black, prints the player's score, and hangs forever.

Music

void music_thread(void const *argument)
{
    FILE *wave_file;
 
    while (true) {
        if(!fire && ! gameOver){
        wave_file=fopen("/sd/wavfiles/Ray.wav","r");//open shooting sound file
        waver.play(wave_file);//play shooting sound file
        fclose(wave_file);//close file to prevent running out of memory
        }
        else if(gameOver)
        {
        wave_file=fopen("/sd/wavfiles/Androids.wav","r");//open ending sound file
        waver.play(wave_file);//play ending sound file
        fclose(wave_file);//close file to prevent running out of memory
        }
    }
}

The music thread plays a sound effect when the button is pressed while the game is still being played, or loops a song once the game has ended. The music is royalty free from www.dl-sounds.com.

Control

void control_thread(void const *argument)
{
  while(1){
    if(myNav.up())
        curY--;
    else if(myNav.down())
        curY++;
    if(myNav.right())
        curX++;
    else if(myNav.left())
        curX--;
    if(curX > 128)
        curX = 128;
    if(curY > 128)
        curY = 128;
    if(curX < 0)
        curX = 0;
    if(curY < 0)
        curY = 0;
    moveTarg();
    Thread::wait(25);
  }
}

The control thread updates the cursors position based on the input from the nav switch.


Please log in to post comments.