Simple letter game testing dexterity and using several features of the microbit, such as button events, the display and the system timer

Dependencies:   microbit

Fork of microbit-letter-game by Anna Bridge

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002 The MIT License (MIT)
00003 Copyright (c) 2016 British Broadcasting Corporation.
00004 This software is provided by Lancaster University by arrangement with the BBC.
00005 Permission is hereby granted, free of charge, to any person obtaining a
00006 copy of this software and associated documentation files (the "Software"),
00007 to deal in the Software without restriction, including without limitation
00008 the rights to use, copy, modify, merge, publish, distribute, sublicense,
00009 and/or sell copies of the Software, and to permit persons to whom the
00010 Software is furnished to do so, subject to the following conditions:
00011 The above copyright notice and this permission notice shall be included in
00012 all copies or substantial portions of the Software.
00013 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00014 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00015 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00016 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00017 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00018 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00019 DEALINGS IN THE SOFTWARE.
00020 */
00021 
00022 /* The letter game....
00023 
00024    This simple game demonstrates the use of:
00025    1) The random function
00026    2) Events on the message bus to handle button presses
00027    3) Driving the display for both characters, numbers and animations.
00028    4) The system timer
00029    
00030    The start of the game will be preceeded by the following message:
00031    "Get Ready.."
00032    and then a small animation showing shrinking/expanding boxes.
00033    Once the game starts a random letter from A-Z will be displayed on the screen.
00034    If it is a consonant then you press the right button.
00035    If it is a vowel then you press the left button.
00036    You must press the corresponding button within the time period for the current level.
00037    Each time you level up, the time to respond decreases. When you level up the shrinking/
00038    expanding box animation will be displayed again.
00039    
00040    The initial allowed time is defined as INITIAL_LIMIT.
00041    The amount by which the time allowed decreases at each level is defined by SPEEDUP.
00042    The point at which a level up occurs is defined as LEVEL_UP.
00043    These can all be tweaked by updating the #defines.
00044     
00045 */
00046 
00047 #include "MicroBit.h"
00048 #include <stdio.h>
00049 
00050 void level_up();
00051 void start();
00052 void game_over();
00053 void display_letter();
00054 void check_press(unsigned long delay);
00055 void onButtonA(MicroBitEvent e);
00056 void onButtonB(MicroBitEvent e);
00057 
00058 
00059 MicroBit uBit;
00060 
00061 #define INITIAL_LIMIT  2000 //ms
00062 #define SPEEDUP         200 //ms
00063 #define LEVEL_UP         20  // level/speed up each time score accumulates by this amount
00064 
00065 typedef enum 
00066 {
00067     NONE,
00068     VOWEL,
00069     CONSONANT,
00070     LATE_PRESS
00071 } Letter_type;
00072 
00073 typedef enum
00074 {
00075     BUTTONS_ENABLED,
00076     BUTTONS_DISABLED
00077 } Button_state;
00078 
00079 Letter_type buttonPress = NONE;
00080 Letter_type type = NONE;
00081 unsigned long time_val;
00082 unsigned long limit;
00083 unsigned score = 0;
00084 Button_state b_state = BUTTONS_DISABLED;
00085 
00086 void level_up()
00087 {
00088     MicroBitImage outer("255,255,255,255,255\n255,0,0,0,255\n255,0,0,0,255\n255,0,0,0,255\n255,255,255,255,255\n");
00089     uBit.display.print(outer, 0, 0);
00090     uBit.sleep(200);
00091     MicroBitImage middle("0,0,0,0,0\n0,255,255,255,0\n0,255,0,255,0\n0,255,255,255,0\n0,0,0,0,0\n");
00092     uBit.display.print(middle, 0, 0);
00093     uBit.sleep(200);
00094     MicroBitImage inner("0,0,0,0,0\n0,0,0,0,0\n0,0,255,0,0\n0,0,0,0,0\n0,0,0,0,0\n");
00095     uBit.display.print(inner, 0, 0); 
00096     uBit.sleep(200);
00097     uBit.display.print(middle, 0, 0);
00098     uBit.sleep(200);
00099     uBit.display.print(outer, 0, 0);    
00100     uBit.sleep(200);
00101     uBit.display.clear();
00102     uBit.sleep(300);
00103 }
00104 
00105 void start()
00106 {
00107     score = 0;
00108     limit = INITIAL_LIMIT;
00109     uBit.display.clear();
00110     uBit.display.scroll("GET READY...", 100);
00111     uBit.sleep(500);
00112     level_up();
00113     uBit.sleep(500);
00114     display_letter();
00115     b_state = BUTTONS_ENABLED;
00116 }
00117 
00118 void game_over()
00119 {
00120     char val[5];
00121     uBit.display.clear();
00122     uBit.display.scroll("GAME OVER!", 100);
00123     uBit.display.scroll("SCORE = ");
00124     sprintf(val,"%u", score);
00125     uBit.display.scroll(val, 100);
00126 }
00127 
00128 
00129 void display_letter()
00130 {
00131     // random number from 65 - 90 ie ASCII A-Z
00132     char letter = uBit.random(26) + 65;
00133     
00134     switch(letter)
00135     {
00136        case 'A':
00137        case 'E':
00138        case 'I':
00139        case 'O':
00140        case 'U': 
00141           type = VOWEL;
00142           break;
00143           
00144        default:
00145            type = CONSONANT;
00146     }
00147 
00148     uBit.display.printChar(letter,500);
00149     //uBit.sleep(limit);
00150     uBit.display.clear();
00151     time_val = uBit.systemTime();
00152 }
00153 
00154 void check_press(unsigned long delay)
00155 {
00156     if (buttonPress == type && delay <= limit)
00157     {
00158         score++;            
00159         if ((score % LEVEL_UP) == 0 && limit > SPEEDUP)
00160         {
00161             // Increase speed
00162             limit -= SPEEDUP;    
00163             level_up();
00164             uBit.sleep(500);
00165         }
00166         buttonPress = NONE;
00167         display_letter();
00168     }
00169     else
00170     {
00171         game_over();            
00172         uBit.sleep(1000);
00173         start();
00174     }    
00175 }   
00176 
00177 void onButtonA(MicroBitEvent e)
00178 {
00179     if (b_state == BUTTONS_ENABLED)
00180     {
00181         b_state = BUTTONS_DISABLED;
00182         if (e.value == MICROBIT_BUTTON_EVT_CLICK)
00183         {
00184             unsigned long delay = uBit.systemTime() - time_val;
00185             buttonPress = VOWEL;
00186             check_press(delay);
00187         }
00188         
00189         b_state = BUTTONS_ENABLED;
00190     }
00191 }
00192 
00193 void onButtonB(MicroBitEvent e)
00194 {
00195     if (b_state == BUTTONS_ENABLED)
00196     {
00197         b_state = BUTTONS_DISABLED;
00198         if (e.value == MICROBIT_BUTTON_EVT_CLICK)
00199         {
00200             unsigned long delay = uBit.systemTime() - time_val;
00201             buttonPress = CONSONANT;
00202             check_press(delay);
00203         }
00204         b_state = BUTTONS_ENABLED;
00205     } 
00206 }
00207 
00208 
00209 int main()
00210 {
00211     
00212     // Initialise the micro:bit runtime.
00213     uBit.init();
00214     
00215     // Set up button event handlers
00216     uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, onButtonB);
00217     uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, onButtonA);
00218     
00219     start();
00220     while(1)
00221     {            
00222         uBit.sleep(100);
00223     }
00224 
00225     // If main exits, there may still be other fibers running or registered event handlers etc.
00226     // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
00227     // sit in the idle task forever, in a power efficient sleep.
00228     release_fiber();
00229 }