//====================================================== // TIME ATTACK GAME MAIN ROUTINE //====================================================== /* This Game Can Be Called From * Stand Alone Mode / Bluetooth Connection * The primary mode is the standalone but * if the bluetooth is connected it has the priority * so it will take over the control of the device * * If you want to control the game via bluetooth * you need to call : time_attack_bluetooth(JSON String) * If you want to use the stand alone mode * you need to call : time_attack_standalone() * * the game returns a float point number which is * in seconds. so the athlete know how long he takes to react */ // Game Time Attack DataType struct gtdt { uint16_t time = 30; // Max Time Of The Game In Sec uint16_t limit = 0; // Max Kick Count bool limit_ena = false; // Enable End Game If Max Kicks Meet float kicksPerSecond = 0; // Game Time Attack Result }; //====================================================== // Request From Stand Alone Buttons //====================================================== void time_attack_standalone() { // Variables uint16_t time = 0; uint16_t timer = 0; uint16_t limit = 0; bool limitEnable = 0; // Display Screen Menu And Button Actions // If The Menu Number 1 -> We Set The Value Of Min Delay // If The Menu Number 2 -> We Set The Value Of Max Delay // If The Menu Number 3 -> We Set The Number Of Trials // Call the Game Play game_timeAttack(time, timer, limit, limitEnable); } //====================================================== // Request From Bluetooth Via JSON //====================================================== /* TIME ATTACK GAME SETTINGS PARAMETERS NOTE: * ------------------------------------------ * * FORMAT : * -------- * {"tm": 10, "le": false, "lm": 10} * * tm : count down timer starting value * le : stands for limit enable, if is TRUE the game end if target value is meet * lm : targeted amount of kicks * * THINGS THAT ENDS THE GAME : * --------------------------- * 1. BY COUNT DOWN "tm" REACH TO ZERO * 2. BY A COMMAND "FROM APP VIA BLUETOOTH" * 3. BY LIMITS MEET "WHEN NUMBER OF YOUR KICKS REACH TO lm VALUE" * * CALCULATING RESULTS : * --------------------- * Rapid Kick Speed = Number Of Kickes Made / Elasped Time In Sec * Delay Between Kicks = Time Of Current Kick - Time Of Last Kick * * RETURNNING JSON FORMAT : * ------------------------ * {"tm" : 82, "ct" : 10, "dl" : 1234, "st" : 585} * * tm : timer count in Sec * ct : strike counter (number of kicks) * dl : delay between strikes * st : time stampe of the strike in milli Seconds */ void time_attack_bluetooth(String settings) { // Deserialize the JSON document DeserializationError error = deserializeJson(JSON, settings); // the main JSON body container // JSON ERROR if(error) { dualcomm(JSON_ERROR); return; } // PUBLIC VARIABLES uint16_t time = JSON["tm"]; // Time Window To JSON uint16_t timer = time; uint16_t limit = JSON["lm"]; // Kick Target Limit bool limitEnable = JSON["le"]; // Enable Kick Target Limit // Clearing Buffer JSON.clear(); // Play The Game game_timeAttack(time, timer, limit, limitEnable); } //====================================================== // Play Time Atack Game //====================================================== void game_timeAttack(uint16_t time, uint16_t timer, uint16_t limit, bool limitEnable) { // Building Timers 1000mSec -> 1Sec TimeTrigger sec_tick(1000); // Kick Counter uint16_t counter = 0; // Start LED Signal //LED_SIGNAL_START(); //------------------------- // PREPARE FOR GAME START //------------------------- // Send Initial DisJSON dualcomm(timeAttack_JSON_json(timer, counter, 0, 0)); // staring Of time stamp unsigned long startStamp = millis(); // store the time of the previous kick unsigned long lastStamp = 0; // reseting time ticker sec_tick.Reset(); // While The Game Is Still On while(timer != 0) { // Time Stamp unsigned long timeStamp = millis() - startStamp; // If Stop Command Came From Smart Phone if(isBluetooth) { String msg = Bluetooth.readStringUntil('\n'); flushBluetooth; msg.trim(); if(msg == CM_STOP) { dualcomm(GAME_OVER); // Grean Light In //LED_SIGNAL_END(); // Return return; } else if(msg == CM_RESET) { timer = time; counter = 0; startStamp = millis(); timeStamp = startStamp; lastStamp = timeStamp; sec_tick.Reset(); dualcomm(timeAttack_JSON_json(timer, counter, lastStamp, timeStamp)); //LED_SIGNAL_RESET(); } } // Every Kick ---------------------------->>> if(PIEZO_MAP > VTH) { counter++; dualcomm(timeAttack_JSON_json(timer, counter, lastStamp, timeStamp)); lastStamp = timeStamp; delay(100); } // Every Second ---------------------------->>> if(sec_tick.Trigger()) { timer--; dualcomm(timeAttack_JSON_json(timer, counter, 0, 0)); } // If Limits Are Enabled And Meet if(limitEnable == true && counter == limit) { // END GAME dualcomm(GAME_OVER); // Celebrate //LED_SIGNAL_CELEBRATION(); // Return return; } } // Send End Game Signal To Smart Phone dualcomm(GAME_OVER); // LightUp //LED_FADEIN(255, 0, 0); // RED Color delay(2000); // Delay 2000 //LED_CLEAR(); // CLEAR OFF // Return return; } //====================================================== // TIME ATTACK KICK JSON -> To Send Back To Mobile //====================================================== String timeAttack_JSON_json(unsigned int RunningTime, unsigned int KickCount, unsigned int LastStamp, unsigned int TimeStamp) { // Building The Buffer JSON["tm"] = RunningTime; JSON["ct"] = KickCount; // Calculations if(TimeStamp > 0) { // Calculate Time Stamp In Seconds float st = TimeStamp; st /= 1000; JSON["st"] = String(st, 3).toFloat(); // Calculate Strike Delay In Seconds float dl = TimeStamp - LastStamp; dl /= 1000; JSON["dl"] = String(dl, 3).toFloat(); } String output; serializeJson(JSON, output); JSON.clear(); return output; } //------------------------------------------------------ // OLED - GAME TIMEATTACK PLAY //------------------------------------------------------ void GAME_TIMEATTACK_DISPLAY(uint16_t count) { OLED_CLEAR(); drawTextCenter(128/2, 0, 2, "KICKS"); drawTextCenter(128/2, 20, 3, String(count)); drawTextCenter(128/2, 50, 1, "<< EXIT >>"); OLED_SHOW(); }