A Demo Tap-Game for the 4D Systems GEN4-24PT touch display

Dependencies:   mbed uLCD_4D_Picaso

Files at this revision

API Documentation at this revision

Comitter:
csteinmetz
Date:
Wed Nov 02 20:58:36 2016 +0000
Commit message:
DEMO GAME

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
uLCD_4D_Picaso.lib Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 2254d7e8172a main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Nov 02 20:58:36 2016 +0000
@@ -0,0 +1,419 @@
+#include "mbed.h"
+#include "uLCD_4D_Picaso.h"
+#include <iostream>
+#include <queue>
+#include <math.h>
+
+/**
+* Demo program for uLCD_4D_Picaso resistance touchscreen 
+* Simple demo game-application on resistive touchscreen display displaying images and using printf.
+* @version 1.0
+* @author Christian Steinmetz, Sam Horwich
+*/
+// three pins are: TX   RX  RESET
+
+uLCD_4D_Picaso lcd(p9, p10, p11);
+uint16_t handle;    //for images (countdown 3,2,1)
+double level=3.0;   //current level indicator, level=((game_level+5)/2)
+int menu=0;         //menu==0 --> start menu
+unsigned long xpos[]={0,40,120,200,40,120,200,40,120,200};  //centers of the nine circular buttons
+unsigned long ypos[]={0,40,40,40,120,120,120,200,200,200};
+Timer t;            //used for timing later
+Timer randt;        //used as a random number generator
+int err=0;          //error indicator
+bool redo=0;        //true if same pattern shall be displayed after error
+int games=0;        //number of games started
+
+
+//creates a random integer out of the current time (random as human input is varying)
+int rnd()
+{
+    return (int) randt.read_us();
+}
+
+//displays the image with name "image.gci" (created from graphics composer) at position (x,y)
+void disp_im(int x, int y, char * name)
+{
+    handle=lcd.file_Open(name,'r');
+    lcd.file_Image(x,y,handle);
+}    
+
+//colors the button number 'pos' in color col
+void col(int pos, Picaso::Color col)
+{
+    int j=(pos-1)/3;
+    int i=pos-j*3-1;
+    lcd.gfx_CircleFilled(40+80*i,40+80*j,37, col);
+}
+
+//creates the setting of the beginning (white background, 9 black circular buttons)
+void black()
+{
+    lcd.gfx_RectangleFilled(0, 0, 240, 320, Picaso::WHITE);
+    for(int i=0;i<3;i++)
+    {
+        for(int j=0;j<3;j++)
+        {
+            lcd.gfx_CircleFilled(40+80*i,40+80*j,37, Picaso::BLACK);
+        }
+    }
+}
+
+int main() {
+    randt.start();//for random numbers!
+    wait(1);
+    // change the baudrate to improve or decrease the latency and plotting quality
+    lcd.setbaudWait(Picaso::BAUD_600000);
+    
+    //initialize SD card in LCD
+    lcd.file_Mount();
+    
+    //text color
+    lcd.txt_FGcolour(Picaso::BLUE);
+            
+    //qu: Queue in which the current pattern is stored
+    //qu2: when qu is dequeued bc of human input, qu2 stores the information from qu which may later be needed in case of an error, ...
+    queue <int> qu;
+    queue <int> qu2;
+    
+    lcd.touch_Set(0);   //initialize touch screen
+    int status = 0;     //stores information from touch screen: 0 if untouched, 1 if touched (2 if released, 3 if moved)
+    int oldst = 0;      //stores old status (so that only changes in status result in events) [may not be needed here...]
+    unsigned long x = 0;//position of finger contact (updated when screen is touched)
+    unsigned long y = 0;
+    while(1) {
+        if(menu==0)     //start menu
+        {
+            lcd.txt_BGcolour(Picaso::ORANGE);
+            lcd.txt_Height(4);
+            lcd.txt_Width(2);
+            lcd.txt_MoveCursor(1,2);
+            lcd.printf(" DEMO-GAME ");
+            
+            lcd.txt_Height(3);
+            lcd.txt_Width(1);
+            lcd.txt_MoveCursor(5,9);
+            lcd.printf(" Start Game ");
+            
+            lcd.txt_Height(3);
+            lcd.txt_MoveCursor(7,8);
+            lcd.printf(" Instructions ");
+            lcd.txt_Height(1);
+            
+            oldst=status;
+            status = lcd.touch_Get(0);  //get status from touch screen as explained above
+            if (status&&(oldst==0))     //change in status from 0 to 1
+            {
+                x = lcd.touch_Get(1);
+                y = lcd.touch_Get(2);
+                if(x>70&&x<170&&y>170&&y<230)   //start game button-->reset everything
+                {
+                    lcd.txt_BGcolour(Picaso::WHITE);    //white backgound for texts
+                    menu=1;                             //pattern show mode
+                    redo=0;                             //in the beginning, new pattern shall be created
+                    err=0;                              //no errors in the beginning
+                    level=3.0;                          //beginner's level is 3 (=(game_level+5)/2
+                    t.stop();                           //reset timer if used before
+                    t.reset();
+                    lcd.gfx_Cls();                      //clear
+                    lcd.gfx_RectangleFilled(0, 0, 240, 320, Picaso::WHITE);     //white background for screen
+                    if(games<5)
+                    {
+                        disp_im(68,110,"three.gci");         //countdown
+                        wait(1);
+                        disp_im(68,110,"two.gci");
+                        wait(1);
+                        disp_im(68,110,"one.gci");
+                        wait(1);
+                        games++;    //needs to be updated/needs to be updated now every time the images are displayed-->see comment below
+                    }
+                    //countdown without displaying images: memory space allows only to display ~16 of these images, so afterwards the screen would freeze
+                    //if we still try to display them-->alternative without images is a text countdown...
+                    else                    
+                    {
+                        lcd.txt_Height(5);
+                        lcd.txt_MoveCursor(2,14);
+                        lcd.txt_Width(3);
+                        lcd.printf("3");
+                        wait(1);
+                        lcd.txt_Width(1);
+                        lcd.txt_MoveCursor(2,14);
+                        lcd.txt_Width(3);
+                        lcd.printf("2");
+                        wait(1);
+                        lcd.txt_Width(1);
+                        lcd.txt_MoveCursor(2,14);
+                        lcd.txt_Width(3);
+                        lcd.printf("1");
+                        wait(1);
+                        lcd.txt_Height(1);
+                        lcd.txt_Width(1);
+                    }
+                    black();                            //game setting (9 circular black buttons)
+                }
+                else if(x>65&&x<175&&y>255&&y<290)      //show instructions as a text
+                {
+                    menu=4;                             //go to instructions menu
+                    lcd.gfx_Cls();
+                    lcd.txt_MoveCursor(1,1);
+                    lcd.printf("Tap the buttons in the shown\n\rorder. Do not tap the wrong \n\rbuttons, as you can only    \n\rmake a maximum of 3 mistakes\n\rbefore losing.\n\r");
+                    lcd.printf("\n\rThe longer you play, the \n\rharder the levels will be. \n\rThere are no time limits, so\n\rhave fun and try to remember\n\ran infinitely long \n\rcombination.\n\r");
+                    lcd.printf("\n\rTap anywhere to get back to \n\rthe menu and get going!");
+                }
+            }
+        }
+        if(menu==1)     //show pattern mode
+        {
+            lcd.txt_MoveCursor(22,13);  //write level
+            lcd.txt_Height(1);
+            lcd.printf("Level");
+            lcd.txt_MoveCursor(24,15);
+            lcd.txt_Height(2);
+            lcd.printf("%i",((int)ceil(level*2-5)));
+            
+            lcd.txt_Height(1);      //write errors
+            lcd.txt_MoveCursor(22,3);
+            lcd.printf("Lives");
+            lcd.txt_MoveCursor(24,4);
+            lcd.txt_Height(2);
+            lcd.printf("%i/3",3-err);
+            
+            lcd.txt_Height(1);      //MENU-button
+            lcd.txt_MoveCursor(23,22);
+            lcd.txt_Height(3);
+            lcd.printf("M E N U");
+            lcd.txt_Height(2);
+        
+            if(err==3)          //in that case, you lost--> menu=3
+            {
+                lcd.gfx_RectangleFilled(0, 240, 240, 320, Picaso::WHITE);
+                lcd.txt_MoveCursor(11,10);
+                lcd.printf("GAME  OVER");
+                
+                lcd.txt_Height(1);
+                lcd.txt_MoveCursor(25,11);
+                lcd.printf("Level %2i",(int)ceil(level*2-5));
+                
+                lcd.txt_Height(1);
+                lcd.txt_MoveCursor(23,22);
+                lcd.txt_Height(3);
+                lcd.printf("M E N U");
+                lcd.txt_Height(2);
+            
+                lcd.txt_Height(1);
+                lcd.txt_MoveCursor(23,2);
+                lcd.txt_Height(3);
+                lcd.printf("N E W");
+                lcd.txt_Height(2);
+                
+                menu=3;
+            }
+            else        //show pattern
+            {
+                double wt=0.1*log(level/1.4);   //speed of showed pattern decreases iwth length of pattern!--> makes rnd() more random!
+                wait(3*wt);
+                if(redo==0)     //new pattern wanted
+                {
+                    for(int i=0;i<level;i++)    //creates a new pattern (integer numbers of buttons) of length ceil(level) and writes it in the queue qu
+                    {
+                        int pos=rnd()%9+1;  
+                        qu.push(pos);
+                        col(pos,Picaso::ORANGE);    //shows pattern: button blinking in orange
+                        wait(wt*3);
+                        col(pos,Picaso::BLACK);     //back to black
+                        wait(wt);
+                        if(qu2.size()>0)            //if qu2 exists, we want to clear it as it is not needed (redo==1!)
+                        {
+                            qu2.pop();
+                        }
+                    }
+                }
+                else        //we want to show the old pattern again (there was an error...)
+                {
+                    redo=0;             //want to get a new pattern next time if no mistake is made!
+                    for(int i=0;i<level;i++)    //restore old pattern from qu2 in qu (afterwards, qu2 is not needed anymore-->cleared)
+                    {
+                        qu.push(qu2.front());
+                        col(qu2.front(),Picaso::ORANGE);    //buttons blink again
+                        wait(wt*3);
+                        col(qu2.front(),Picaso::BLACK);
+                        wait(wt);
+                        qu2.pop();
+                    }
+                }
+                menu=2;         //go to human input mode
+            }
+        }
+        if(menu==2)     //now we try to retap the buttons in the right order
+        {
+            t.start();  //timer needed later
+            oldst=status;
+            status = lcd.touch_Get(0);
+            if (status&&(oldst==0))
+            {
+                x = lcd.touch_Get(1);   //positions of finger contact
+                y = lcd.touch_Get(2);
+                
+                if((unsigned long)((x-xpos[qu.front()])*(x-xpos[qu.front()])+(y-ypos[qu.front()])*(y-ypos[qu.front()]))<=1444)  //checks if we are more or less inside the circle at the first position of qu
+                {
+                    col(qu.front(),Picaso::GREEN);  //green==good
+                    t.reset();
+                    //this loop is needed so that the green light is actually shown and it is not continuously trying to get green and black again at the same time
+                    //only if button is released for at least 0.15s (so not due to a too light pressure on the screen for a few milliseconds),
+                    //the button goes back to black
+                    while(1)                      
+                    {
+                        oldst=status;
+                        status = lcd.touch_Get(0);
+                        
+                        if(status!=0){t.reset();}
+                        if(status==0&&t.read()>0.15){break;}
+                    }
+                    col(qu.front(),Picaso::BLACK);
+                    if(qu.size()==1)        //after the last element , a longer green signal shows that the pattern is finished and correct
+                    {
+                        col(qu.front(),Picaso::BLACK);
+                        wait(.2);
+                        col(qu.front(),Picaso::GREEN);
+                        wait(.1);
+                        col(qu.front(),Picaso::BLACK);
+                        wait(.1);
+                        col(qu.front(),Picaso::GREEN);
+                        wait(1);
+                        col(qu.front(),Picaso::BLACK);
+                        wait(0.8);
+                        level+=0.5;         //now, as we were correct, we can also increase our level and go back to the new show pattern-phase (menu==1)
+                        menu=1;
+                    }
+                    qu2.push(qu.front());   //store qu in qu2 (as it may be needed above)
+                    qu.pop();               //clear first element from qu
+                }
+                else if(y<240)          //if we press the wrong button...
+                {
+                    unsigned long dist=100000;
+                    unsigned long min=0;    //the following writes the button in 'min' that is closest to the finger contact
+                    for(int i=1;i<10;i++)
+                    {
+                        if((x-xpos[i])*(x-xpos[i])+(y-ypos[i])*(y-ypos[i])<dist)
+                        {
+                            min=i;
+                            dist=(x-xpos[i])*(x-xpos[i])+(y-ypos[i])*(y-ypos[i]);
+                        }
+                    }
+                    if(min!=qu.front()) //if closest button is the right one, but we press outside of it, nothing happens. IF NOT: Error routine in following lines
+                    {
+                        col(min,Picaso::RED);   //red==bad
+                        wait(1.5);
+                        col(min,Picaso::BLACK);
+                        redo=1;     //now we want to show the right pattern again next time (good that we have qu2...)
+                        menu=1;     //new show pattern-phase
+                        err++;      //error number updated
+                    }
+                    while(qu.size()>0)  //shift remaining information from qu in qu2
+                    {
+                        qu2.push(qu.front());
+                        qu.pop();
+                    }
+                }
+                else if(x>170&&y>270)   //MENU-button
+                {
+                    menu=0;     //back to start menu
+                    lcd.gfx_Cls();  //reset lcd
+                    while(qu.size()>0)  //clear queues
+                    {
+                        qu.pop();
+                    }
+                    while(qu2.size()>0)
+                    {
+                        qu2.pop();
+                    }
+                }
+            }
+        }
+        if(menu==3)     //GAME OVER...
+        {
+            oldst=status;
+            status = lcd.touch_Get(0);
+            if (status&&(oldst==0))
+            {
+                x = lcd.touch_Get(1);
+                y = lcd.touch_Get(2);
+                if(x>170&&y>270)        //MENU-button as above
+                {
+                    menu=0;
+                    lcd.gfx_Cls();
+                    while(qu.size()>0)
+                    {
+                        qu.pop();
+                    }
+                    while(qu2.size()>0)
+                    {
+                        qu2.pop();
+                    }
+                }
+                else if(x<70&&y>270)    //NEW game-button
+                {
+                    while(qu.size()>0)  //clear queues
+                    {
+                        qu.pop();
+                    }
+                    while(qu2.size()>0)
+                    {
+                        qu2.pop();
+                    }
+                    menu=1;     //back to show-mode
+                    redo=0;     //new pattern required
+                    err=0;      //no errors in the beginning
+                    level=3.0;  //first level is that (you should know by now)
+                    t.stop();   //reset timer (as the other timer is used for random numbers, we don't reset it, an overflow would not matter at all!)
+                    t.reset();
+                    lcd.gfx_Cls();  //reset lcd
+                    lcd.gfx_RectangleFilled(0, 0, 240, 320, Picaso::WHITE); //countdown:
+                    if(games<5)
+                    {
+                        disp_im(68,110,"three.gci");         //countdown
+                        wait(1);
+                        disp_im(68,110,"two.gci");
+                        wait(1);
+                        disp_im(68,110,"one.gci");
+                        wait(1);
+                        games++;    //needs to be updated now every time the images are displayed-->see comment below
+                    }
+                    //countdown without displaying images: memory space allows only to display ~16 of these images, so afterwards the screen would freeze
+                    //if we still try to display them-->alternative without images is a text countdown...
+                    else
+                    {
+                        lcd.txt_Height(5);
+                        lcd.txt_MoveCursor(2,14);
+                        lcd.txt_Width(3);
+                        lcd.printf("3");
+                        wait(1);
+                        lcd.txt_Width(1);
+                        lcd.txt_MoveCursor(2,14);
+                        lcd.txt_Width(3);
+                        lcd.printf("2");
+                        wait(1);
+                        lcd.txt_Width(1);
+                        lcd.txt_MoveCursor(2,14);
+                        lcd.txt_Width(3);
+                        lcd.printf("1");
+                        wait(1);
+                        lcd.txt_Height(1);
+                        lcd.txt_Width(1);
+                    }
+                    black();        //first screen of game
+                }
+            }
+        }
+        if(menu==4)
+        {
+            oldst=status;
+            status = lcd.touch_Get(0);
+            if (status&&(oldst==0)) //tap ANYWHERE to get back to the menu screen
+            {
+                menu=0;
+                lcd.gfx_Cls();
+            }
+        }
+    }
+}    
diff -r 000000000000 -r 2254d7e8172a mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Nov 02 20:58:36 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/7e07b6fb45cf
\ No newline at end of file
diff -r 000000000000 -r 2254d7e8172a uLCD_4D_Picaso.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uLCD_4D_Picaso.lib	Wed Nov 02 20:58:36 2016 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/shorwich/code/uLCD_4D_Picaso/#72f00cef468b