A zombie game made for the uLCD

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

Fork of uLCD144G2_demo by jim hamblen

Revision:
10:9d16de327719
Parent:
8:31e63caf37e2
Child:
11:4b75ea66467d
--- a/main.cpp	Wed Oct 28 15:06:56 2015 +0000
+++ b/main.cpp	Sun Mar 13 16:00:46 2016 +0000
@@ -1,171 +1,336 @@
-// uLCD-144-G2 demo program for uLCD-4GL LCD driver library
-//
 #include "mbed.h"
 #include "uLCD_4DGL.h"
+#include "Speaker.h"
+#include "rtos.h"
 
-uLCD_4DGL uLCD(p9,p10,p11); // serial tx, serial rx, reset pin;
-
-int main()
+//First make the Nav_Switch class for using the joystick
+class Nav_Switch
 {
-    // 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);
+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;
 
-//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) );
+};
+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();
+}
+
+//Now initialize
+uLCD_4DGL uLCD(p28,p27,p30); // serial tx, serial rx, reset pin;
+Nav_Switch myNav(p11,p14,p13,p15,p12);
+Speaker mySpeaker(p21);
+
+//Game states: Start screen, playing, and game over
+enum gamestate {
+    start,
+    playing,
+    gameover
+};
+
+//Which way you're facing is where you fire your gun
+enum facingDirection {
+    up,
+    down,
+    left,
+    right
+};
+
+//Global variables used by SpeakerThread
+//The game state
+int state=start;
+//Checks for each bullet (up,down,left,right) to see if it hit an enemy
+bool hitU=false, hitD=false, hitL=false, hitR=false;
+
+void SpeakerThread(void const *args)
+{
+    while(1) {
+        if(myNav.fire() && state==playing) {
+            //Play noise when gun is fired
+            mySpeaker.PlayNote(500.0,0.1,0.5);
         }
-    }
-    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))));
-            }
+        if(hitU || hitD || hitL || hitR) {
+            //Play two notes when enemy hit.
+            mySpeaker.PlayNote(300.0,0.05,0.5);
+            mySpeaker.PlayNote(250.0,0.05,0.5);
         }
-        uLCD.BLIT(39, 39, 50, 50, &pixelcolors[0][0]);
-        c = c + 0.0314159*3.0;
-        if (c > 6.2831) c = 0.0;
-        frame++;
-    }
-    //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);
     }
 }
 
 
 
+int main()
+{
+    while(1) {
+        //Score
+        int score=0;
+        //Player position (initialized at center).
+        int Px1=63-1,Px2=63+1,Py1=63-1,Py2=63+1;
+        //X and Y coordinates for each bullet
+        int BUx=0, BUy=0, BLx=0, BLy=0;
+        int BDx=127, BDy=127, BRx=127, BRy=127;
+        //Zombie coordinates. Z[0][0] = x coordinate of zombie 1, Z[0][1] = y coordinate of zombie 1.
+        //Z[0][0] = x1 coordinate, Z[0][0]+2 = x2 coordinate. Same method for y1 and y2.
+        int Z[1][2];
+        for(int i=0; i<2; i++) {
+            for(int j=0; j<2; j++) {
+                Z[i][j]=0;
+            }
+        }
+        //Which way the player is facing
+        int facing=down;
+        //Threads
+        Thread speaker(SpeakerThread);
+        //Display the start screen
+        uLCD.media_init();
+        uLCD.set_sector_address(0x001D, 0x4C01);
+        uLCD.display_image(0,0);
+        //Switch to the playing state when FIRE is pressed
+        while(state==start) {
+            if(myNav.fire()) {
+                uLCD.cls();
+                wait(1.0);
+                state=playing;
+            }
+        }
+
+        //Draw player and zombie
+        uLCD.filled_rectangle(Px1,Py1,Px2,Py2,BLUE);
+        uLCD.filled_rectangle(Z[0][0],Z[0][1],Z[0][0]+2,Z[0][1]+2,GREEN);
+
+        //Game starts here
+        while(state==playing) {
+
+            //Player Movement
+            //Move the player when buttons are pressed (but don't go off the screen)
+            if(myNav.up() && (Py1!=0)) {
+                facing=up;
+                Py1--;
+                Py2--;
+                uLCD.filled_rectangle(Px1,Py1,Px2,Py2,BLUE);
+                uLCD.filled_rectangle(Px1,Py2+1,Px2,Py2+1,BLACK);
+            } else if(myNav.down() && (Py2!=127)) {
+                facing=down;
+                Py1++;
+                Py2++;
+                uLCD.filled_rectangle(Px1,Py1,Px2,Py2,BLUE);
+                uLCD.filled_rectangle(Px1,Py1-1,Px2,Py1-1,BLACK);
+            } else if(myNav.left() && (Px1!=0)) {
+                facing=left;
+                Px1--;
+                Px2--;
+                uLCD.filled_rectangle(Px1,Py1,Px2,Py2,BLUE);
+                uLCD.filled_rectangle(Px2+1,Py1,Px2+1,Py2,BLACK);
+            } else if(myNav.right() && (Px2!=127)) {
+                facing=right;
+                Px1++;
+                Px2++;
+                uLCD.filled_rectangle(Px1,Py1,Px2,Py2,BLUE);
+                uLCD.filled_rectangle(Px1-1,Py1,Px1-1,Py2,BLACK);
+            }
+            //Firing the gun depending on where you are facing
+            if(myNav.fire() && facing==up && BUy==0) {
+                BUx=Px1+1;
+                BUy=Py1-1;
+                uLCD.pixel(BUx,BUy,WHITE);
+            } else if(myNav.fire() && facing==down && BDy==127) {
+                BDx=Px1+1;
+                BDy=Py2+1;
+                uLCD.pixel(BDx,BDy,WHITE);
+            } else if(myNav.fire() && facing==left  && BLx==0) {
+                BLx=Px1-1;
+                BLy=Py2-1;
+                uLCD.pixel(BLx,BLy,WHITE);
+            } else if(myNav.fire() && facing==right && BRx==127) {
+                BRx=Px2+1;
+                BRy=Py2-1;
+                uLCD.pixel(BRx,BRy,WHITE);
+            }
+            //Keep moving the bullets until they hit the wall or a zombie
+            if(BUy!=0 && !hitU) {
+                BUy--;
+                uLCD.pixel(BUx,BUy,WHITE);
+                uLCD.pixel(BUx,BUy+1,BLACK);
+                //Hit detection
+                for(int i=0; i<3; i++) {
+                    for(int j=0; j<3; j++) {
+                        if((Z[0][0]+i)==BUx && (Z[0][1]+j)==BUy) {
+                            hitU=true;
+                        }
+                    }
+                }
+            } else  {
+                uLCD.filled_rectangle(BUx-2,BUy-2,BUx+2,BUy+1,BLACK);
+                BUy=0;
+                hitU=false;
+            }
+            if(BDy!=127 && !hitD) {
+                BDy++;
+                uLCD.pixel(BDx,BDy,WHITE);
+                uLCD.pixel(BDx,BDy-1,BLACK);
+                //Hit detection
+                for(int i=0; i<3; i++) {
+                    for(int j=0; j<3; j++) {
+                        if((Z[0][0]+i)==BDx && (Z[0][1]+j)==BDy) {
+                            hitD=true;
+                        }
+                    }
+                }
+            } else  {
+                uLCD.filled_rectangle(BDx-2,BDy-1,BDx+2,BDy+2,BLACK);
+                BDy=127;
+                hitD=false;
+            }
+            if(BLx!=0 && !hitL) {
+                BLx--;
+                uLCD.pixel(BLx,BLy,WHITE);
+                uLCD.pixel(BLx+1,BLy,BLACK);
+                //Hit detection
+                for(int i=0; i<3; i++) {
+                    for(int j=0; j<3; j++) {
+                        if((Z[0][0]+i)==BLx && (Z[0][1]+j)==BLy) {
+                            hitL=true;
+                        }
+                    }
+                }
+            } else {
+                uLCD.filled_rectangle(BLx-2,BLy-2,BLx+1,BLy+2,BLACK);
+                BLx=0;
+                hitL=false;
+            }
+            if(BRx!=127 && !hitR) {
+                BRx++;
+                uLCD.pixel(BRx,BRy,WHITE);
+                uLCD.pixel(BRx-1,BRy,BLACK);
+                //Hit detection
+                for(int i=0; i<3; i++) {
+                    for(int j=0; j<3; j++) {
+                        if((Z[0][0]+i)==BRx && (Z[0][1]+j)==BRy) {
+                            hitR=true;
+                        }
+                    }
+                }
+            } else {
+                uLCD.filled_rectangle(BRx-1,BRy-2,BRx+2,BRy+2,BLACK);
+                BRx=127;
+                hitR=false;
+            }
+
+
+            //Zombie Movement
+            if(!hitU && !hitD && !hitL && !hitR) {
+                if(Px1 > (Z[0][0]+2)) {
+                    Z[0][0]=Z[0][0]+1;
+                    uLCD.filled_rectangle(Z[0][0]-1,Z[0][1],Z[0][0]-1,Z[0][1]+2,BLACK);
+                } else if(Px2 < Z[0][0]) {
+                    Z[0][0]--;
+                    uLCD.filled_rectangle(Z[0][0]+3,Z[0][1],Z[0][0]+3,Z[0][1]+2,BLACK);
+                }
+                if(Py1 > Z[0][1]+2) {
+                    Z[0][1]++;
+                    uLCD.filled_rectangle(Z[0][0],Z[0][1]-1,Z[0][0]+2,Z[0][1]-1,BLACK);
+                } else if(Py2 < Z[0][1]) {
+                    Z[0][1]--;
+                    uLCD.filled_rectangle(Z[0][0],Z[0][1]+3,Z[0][0]+2,Z[0][1]+3,BLACK);
+                }
+                uLCD.filled_rectangle(Z[0][0],Z[0][1],Z[0][0]+2,Z[0][1]+2,GREEN);
+            }
+            //If zombie is hit, add 10 points and move the zombie to a random spot outside of the
+            //map that doesn't hit (0,0) or (127,127), which is where the bullets are held
+            if(hitU || hitD || hitL || hitR) {
+                score += 10;
+                if(rand() % 2) {
+                    Z[0][0] = (rand() % 120)+1;
+                    if(rand() % 2)
+                        Z[0][1] = -3;
+                    else
+                        Z[0][1] = 128;
+                } else {
+                    Z[0][1] = (rand() % 120)+1;
+                    if(rand() % 2)
+                        Z[0][0] = -3;
+                    else
+                        Z[0][0] = 128;
+                }
+            }
+            //Check if zombie touches player, resulting in game over
+            for(int i=0; i<3; i++) {
+                for(int j=0; j<3; j++) {
+                    if((Z[0][0]+i)==Px1+j) {
+                        for(int m=0; m<3; m++) {
+                            for(int n=0; n<3; n++) {
+                                if((Z[0][1]+m)==Py1+j) {
+                                    state=gameover;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            //Display score in the top
+            uLCD.locate(6,0);
+            uLCD.printf("Score: %d",score);
+        }
+        //Display Game Over Screen
+        uLCD.media_init();
+        uLCD.set_sector_address(0x001D, 0x4C65);
+        uLCD.display_image(0,0);
+        //Reset when FIRE is pressed
+        while(state==gameover) {
+            if(myNav.fire()) {
+                uLCD.cls();
+                wait(1.0);
+                state=start;
+            }
+        }
+    }
+
+}
+
+
+