DuckHunt game using IMU sensor and uLCD display

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

Fork of uLCD144G2_demo by jim hamblen

Revision:
10:c19a945d9dca
Parent:
8:31e63caf37e2
--- a/main.cpp	Wed Oct 28 15:06:56 2015 +0000
+++ b/main.cpp	Mon Oct 31 21:20:17 2016 +0000
@@ -2,170 +2,255 @@
 //
 #include "mbed.h"
 #include "uLCD_4DGL.h"
+#include "LSM9DS1.h"
+#include <math.h>
+#include "PinDetect.h"
+#include "SDFileSystem.h"
+#include "wave_player.h"
 
-uLCD_4DGL uLCD(p9,p10,p11); // serial tx, serial rx, reset pin;
+
+
+#define PI 3.14159
+// Earth's magnetic field varies by location. Add or subtract
+// a declination to get a more accurate heading. Calculate
+// your's here:
+// http://www.ngdc.noaa.gov/geomag-web/#declination
+#define DECLINATION -4.94 // Declination (degrees) in Atlanta,GA.
 
-int main()
-{
-    // basic printf demo = 16 by 18 characters on screen
-    uLCD.printf("\nHello uLCD World\n"); //Default Green on black text
-    uLCD.printf("\n  Starting Demo...");
-    uLCD.text_width(4); //4X size text
-    uLCD.text_height(4);
-    uLCD.color(RED);
-    for (int i=10; i>=0; --i) {
-        uLCD.locate(1,2);
-        uLCD.printf("%2D",i);
-        wait(.5);
-    }
-    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);
-    int i=0;
-    while(i<64) {
-        if(i%16==0) uLCD.cls();
-        uLCD.printf("TxtLine %2D Page %D\n",i%16,i/16 );
-        i++; //16 lines with 18 charaters per line
-    }
-    wait(0.5);
-    //demo graphics commands
-    uLCD.background_color(BLACK);
-    uLCD.cls();
-    uLCD.background_color(DGREY);
-    uLCD.filled_circle(60, 50, 30, 0xFF00FF);
-    uLCD.triangle(120, 100, 40, 40, 10, 100, 0x0000FF);
-    uLCD.line(0, 0, 80, 60, 0xFF0000);
-    uLCD.filled_rectangle(50, 50, 100, 90, 0x00FF00);
-    uLCD.pixel(60, 60, BLACK);
-    uLCD.read_pixel(120, 70);
-    uLCD.circle(120, 60, 10, BLACK);
-    uLCD.set_font(FONT_7X8);
-    uLCD.text_mode(TRANSPARENT);
-    uLCD.text_bold(ON);
-    uLCD.text_char('B', 9, 8, BLACK);
-    uLCD.text_char('I',10, 8, BLACK);
-    uLCD.text_char('G',11, 8, BLACK);
-    uLCD.text_italic(ON);
-    uLCD.text_string("This is a test of string", 1, 4, FONT_7X8, WHITE);
-    wait(2);
+uLCD_4DGL uLCD(p9,p10,p30); // serial tx, serial rx, reset pin;
+DigitalOut myled(LED1);
+Serial pc(USBTX, USBRX);
+Serial device(p28, p27);
+
+PinDetect trigger(p21);
+
+//speaker
+SDFileSystem sd(p5, p6, p7, p8, "sd"); //SD card
+AnalogOut DACout(p18);
+wave_player waver(&DACout);
+//
+
+
+
 
-//Bouncing Ball Demo
-    float fx=50.0,fy=21.0,vx=1.0,vy=0.4;
-    int x=50,y=21,radius=4;
-    uLCD.background_color(BLACK);
-    uLCD.cls();
-    //draw walls
-    uLCD.line(0, 0, 127, 0, WHITE);
-    uLCD.line(127, 0, 127, 127, WHITE);
-    uLCD.line(127, 127, 0, 127, WHITE);
-    uLCD.line(0, 127, 0, 0, WHITE);
-    for (int i=0; i<1500; i++) {
-        //draw ball
-        uLCD.filled_circle(x, y, radius, RED);
-        //bounce off edge walls and slow down a bit?
-        if ((x<=radius+1) || (x>=126-radius)) vx = -.90*vx;
-        if ((y<=radius+1) || (y>=126-radius)) vy = -.90*vy;
-        //erase old ball location
-        uLCD.filled_circle(x, y, radius, BLACK);
-        //move ball
-        fx=fx+vx;
-        fy=fy+vy;
-        x=(int)fx;
-        y=(int)fy;
-    }
-    wait(0.5);
-//draw an image pixel by pixel
-    int pixelcolors[50][50];
-    uLCD.background_color(BLACK);
-    uLCD.cls();
-//compute Mandelbrot set image for display
-//image size in pixels
-    const unsigned ImageHeight=128;
-    const unsigned ImageWidth=128;
-    //"c" region to display
-    double MinRe = -0.75104;
-    double MaxRe = -0.7408;
-    double MinIm = 0.10511;
-    double MaxIm = MinIm+(MaxRe-MinRe)*ImageHeight/ImageWidth;
-    double Re_factor = (MaxRe-MinRe)/(ImageWidth-1);
-    double Im_factor = (MaxIm-MinIm)/(ImageHeight-1);
-    unsigned MaxIterations = 2048;
-    for(unsigned y=0; y<ImageHeight; ++y) {
-        double c_im = MaxIm - y*Im_factor;
-        for(unsigned x=0; x<ImageWidth; ++x) {
-            double c_re = MinRe + x*Re_factor;
-            double Z_re = c_re, Z_im = c_im;
-            int niterations=0;
-            for(unsigned n=0; n<MaxIterations; ++n) {
-                double Z_re2 = Z_re*Z_re, Z_im2 = Z_im*Z_im;
-                if(Z_re2 + Z_im2 > 4) {
-                    niterations = n;
-                    break;
-                }
-                Z_im = 2*Z_re*Z_im + c_im;
-                Z_re = Z_re2 - Z_im2 + c_re;
-            }
-            if (niterations!=(MaxIterations-1))
-                uLCD.pixel(x,y,((niterations & 0xF00)<<12)+((niterations & 0xF0)<<8)+((niterations & 0x0F)<<4) );
+//duck
+int duckWidth = 20;
+int duckHeight = 20;
+int duckx = 64;
+int ducky = 40;
+int duckDY = 3;
+int duckDX = 3;
+int duckMaxSpeed = 10;
+int duckMinSpeed = 4;
+//
+
+//aimer
+int aimerWidth = 20;
+int aimerHeight = 20;
+int aimerx = 64;
+int aimery = 64;
+//
+
+//trigger
+bool hit = false;
+
+//duckreset
+bool duckReset = false;
+
+//scoreboard
+int scoreCount = 0;
+bool scoreChange = false;
+
+// countinghits.wav
+// duck-hunt-intro.wav
+
+
+void trigger_hit_callback() {
+    device.putc(pc.printf("aimerx: %d,    aimery: %d \n\r",aimerx,aimery));
+    device.putc(pc.printf("duckx: %d,    ducky: %d \n\r",duckx,ducky));
+    device.putc(pc.printf("duckx: %d,    ducky: %d \n\r",duckx + duckWidth,ducky + duckHeight));
+    hit = true;
+    if (aimery >= duckx && aimery <= (duckx + duckWidth)){
+        if (aimerx >= ducky && aimerx <= (ducky + duckHeight)){
+            duckReset = true;  
+            scoreCount = scoreCount + 1;
+            scoreChange = true;
+            device.putc(pc.printf("HIT \n"));
         }
     }
-    wait(5);
-// PLASMA wave BLIT animation
-//draw an image using BLIT (Block Image Transfer) fastest way to transfer pixel data
-    uLCD.cls();
-    int num_cols=50;
-    int num_rows=50;
-    int frame=0;
-    double a,b,c=0.0;
-    while(frame<75) {
-        for (int k=0; k<num_cols; k++) {
-            b= (1+sin(3.14159*k*0.75/(num_cols-1.0)+c))*0.5;
-            for (int i=0; i<num_rows; i++) {
-                a= (1+sin(3.14159*i*0.75/(num_rows-1.0)+c))*0.5;
-                // a and b will be a sine wave output between 0 and 1
-                // sine wave was scaled for nice effect across array
-                // uses a and b to compute pixel colors based on rol and col location in array
-                // also keeps colors at the same brightness level
-                if ((a+b) <.667)
-                    pixelcolors[i][k] =  (255-(int(254.0*((a+b)/0.667)))<<16) | (int(254.0*((a+b)/0.667))<<8) | 0;
-                else if ((a+b)<1.333)
-                    pixelcolors[i][k] = (0 <<16) | (255-(int (254.0*((a+b-0.667)/0.667)))<<8) | int(254.0*((a+b-0.667)/0.667));
-                else
-                    pixelcolors[i][k] = (int(255*((a+b-1.333)/0.667))<<16) | (0<<8)  | (255-(int (254.0*((a+b-1.333)/0.667))));
-            }
-        }
-        uLCD.BLIT(39, 39, 50, 50, &pixelcolors[0][0]);
-        c = c + 0.0314159*3.0;
-        if (c > 6.2831) c = 0.0;
-        frame++;
+}
+
+int calcDuckXPos()
+{
+    int newX = duckx + duckDX;
+    if (newX > 128 - duckWidth){
+        duckDX = rand()%(duckMaxSpeed-duckMinSpeed + 1) + duckMinSpeed;
+        duckDX = -duckDX;
+        newX = duckx + duckDX;
+    }
+    if (newX < 0){
+        duckDX = rand()%(duckMaxSpeed-duckMinSpeed + 1) + duckMinSpeed;
+        newX = duckx + duckDX;
+    }
+    return newX;
+}
+
+
+int calcDuckYPos()
+{
+    
+    int newY = ducky + duckDY;
+    if (newY > 128 - duckHeight){
+        duckDY = rand()%(duckMaxSpeed-duckMinSpeed + 1) + duckMinSpeed;
+        duckDY = -duckDY;
+        newY = ducky + duckDY;
     }
-    //Load Image Demo
-    uLCD.cls();
-    //SD card needed with image and video files for last two demos
-    uLCD.cls();
-    uLCD.media_init();
-    uLCD.printf("\n\nAn SD card is needed for image and video data");
-    uLCD.set_sector_address(0x001D, 0x4C01);
-    uLCD.display_image(0,0);
-    wait(10);
-    //Play video demo
-    while(1) {
-        uLCD.cls();
-        uLCD.media_init();
-        uLCD.set_sector_address(0x001D, 0x4C42);
-        uLCD.display_video(0,0);
+    if (newY < 25){
+        duckDY = rand()%(duckMaxSpeed-duckMinSpeed + 1) + duckMinSpeed;
+        newY = ducky + duckDY;
     }
+    return newY;
+}
+
+
+void drawDuck()
+{
+    uLCD.display_image(duckx,ducky);
+
+}
+
+void eraseDuck()
+{
+    uLCD.filled_rectangle(duckx, ducky, duckx + duckWidth, ducky + duckHeight, BLACK);
+}
+
+void drawAimer()
+{
+    uLCD.circle(aimery, aimerx, (aimerWidth/2) - 5, WHITE);
+    uLCD.line(aimery - aimerHeight/2, aimerx, aimery + aimerHeight/2, aimerx, WHITE);
+    uLCD.line(aimery, aimerx - aimerWidth/2, aimery,aimerx + aimerHeight/2, WHITE);
+}
+
+void eraseAimer()
+{
+    uLCD.circle(aimery, aimerx, (aimerWidth/2) - 5, BLACK);
+    uLCD.line(aimery - aimerHeight/2, aimerx, aimery + aimerHeight/2, aimerx, BLACK);
+    uLCD.line(aimery, aimerx - aimerWidth/2, aimery,aimerx + aimerHeight/2, BLACK);
 }
 
 
 
+int main()
+{
+    uLCD.media_init();
+    uLCD.set_sector_address(0x0001, 0x2B71);
+    //LSM9DS1 IMU(p9, p10, 0x6B, 0x1E);
+    
+    LSM9DS1 IMU(p28, p27, 0xD6, 0x3C);
+    IMU.begin();
+
+    if (!IMU.begin()) {
+        pc.printf("Failed to communicate with LSM9DS1.\n");
+    }
+
+    IMU.calibrate(1);
+//    IMU.calibrateMag(0);
+    
+
+
+    
+    //demo graphics commands
+    uLCD.background_color(BLACK);
+    uLCD.cls();
+    trigger.mode(PullUp);
+    wait(.001);
+    trigger.attach_deasserted(&trigger_hit_callback);
+    trigger.setSampleFrequency();
+    
+    float mult = 160.0;
+    float rawx = 0;
+    float rawy = 0;
+    
+
+    
+    int duckResetCounter = 25;
+    
+    uLCD.set_font(FONT_7X8);
+    uLCD.text_width(1);
+    uLCD.text_height(1);
+    uLCD.locate(1,1);
+    uLCD.printf("Score: %d",scoreCount);
+    
+    while(1){
+        
+        drawAimer();
+        eraseAimer();
+    
+        if (!duckReset){
+            drawDuck();
+            eraseDuck();
+        } else {
+            duckResetCounter = duckResetCounter - 1;
+            if (duckResetCounter <= 0){
+                duckResetCounter = 50;
+                duckReset = false;
+            }
+        }
+        
+        
+        
+//        if (fire){
+//            fire = false;
+//            if (aimerx >= duckx && aimerx <= (duckx + duckWidth)){
+//                device.putc(pc.printf("X Good"));
+//                if (aimery >= ducky && aimery <= (ducky + duckHeight)){
+//                    led = !led;
+//                    device.putc(pc.printf("HIT"));
+//                }
+//            }
+//        }
+        
+        while(!IMU.accelAvailable());
+        IMU.readAccel();
+        while(!IMU.gyroAvailable());
+        IMU.readGyro();
+
+        rawx = IMU.calcAccel(IMU.ax);
+        rawy = IMU.calcAccel(IMU.ay);
+//        device.putc(pc.printf("ax: %f,    ay: %f \n\r",rawx,rawy));
+
+
+        aimerx = 64 + int(rawx * mult);
+
+        if (aimerx < 25){
+            aimerx = 25;  
+        }
+        aimery = 64 - int(rawy * mult);
+        
+        
+        duckx = calcDuckXPos();
+        ducky = calcDuckYPos();
+    
+        if (hit){
+            hit = false;
+            FILE *wave_file=fopen("/sd/gunsound.wav","r");
+            waver.play(wave_file);
+            fclose(wave_file);  
+            
+        }
+        
+        if (scoreChange){
+            scoreChange = false;
+            uLCD.set_font(FONT_7X8);
+            uLCD.text_width(1);
+            uLCD.text_height(1);
+            uLCD.locate(1,1);
+            uLCD.printf("Score: %d",scoreCount);
+        }
+
+    }
+
+}
+
+
+