//====================================================== // 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 */ //====================================================== // Request From Stand Alone Buttons //====================================================== void time_attack_standalone() { // Variables uint16_t time = 30; uint16_t limit = 10; bool limitEnable = true; // Call the Game Play game_timeAttack(time, limit, limitEnable); // Give Permision To Change Display DISPLAY_CHANGED = false; } //====================================================== // 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 const uint16_t time = JSON["tm"]; // Time Window To JSON 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, limit, limitEnable); // Give Permision To Change Display DISPLAY_CHANGED = false; } //====================================================== // Play Time Atack Game //====================================================== void game_timeAttack(uint16_t time, uint16_t limit, bool limitEnable) { // Building Timers 1000mSec -> 1Sec TimeTrigger sec_tick(1000); // Kick Counter uint16_t counter = 0; // This is what counts your kicks uint16_t timer = time; // This is what your running timer // Start LED Signal //LED_SIGNAL_START(); // Initial Display Of Game Data Before Start GAME_TIMEATTACK_DISPLAY(timer, 0); // Send Initial DisJSON dualcomm(timeAttack_JSON_json(timer, counter, 0, 0)); //------------------------- // PREPARE FOR GAME START //------------------------- // 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(); GAME_TIMEATTACK_DISPLAY(counter, timer); //LED_SIGNAL_RESET(); } } // Reset The Counter if(BTN_INCREASE.pressed()) { timer = time; counter = 0; startStamp = millis(); timeStamp = startStamp; lastStamp = timeStamp; sec_tick.Reset(); GAME_TIMEATTACK_DISPLAY(counter, timer); } // Will Exit The Game if(BTN_CENTER.pressed()) { dualcomm(GAME_OVER); DISPLAY_CHANGED = false; return; } // Every Kick ---------------------------->>> if(PIEZO_MAP > VTH) { // Count As A Strike counter++; // Display On OLED GAME_TIMEATTACK_DISPLAY(counter, timer); // Send JSON String Out dualcomm(timeAttack_JSON_json(timer, counter, lastStamp, timeStamp)); // Time Snap Shot lastStamp = timeStamp; // Wait For Analog Sampler To by pass the strike delay(100); } // Every Second ---------------------------->>> if(sec_tick.Trigger()) { // Decrement Time After Every Second timer--; // Display Time And Count Every Second GAME_TIMEATTACK_DISPLAY(counter, timer); // Send JSON String Out dualcomm(timeAttack_JSON_json(timer, counter, 0, 0)); } // If Limits Are Enabled And Meet if(limitEnable == true && counter == limit) { // END GAME dualcomm(GAME_OVER); // Time Difference Between Start & Count Down Timer const uint16_t diff = time - timer; // Display The Game Result GAME_TIMEATTACK_RESULT(counter, diff); // Celebrate //LED_SIGNAL_CELEBRATION(); // Return return; } } // Send End Game Signal To Smart Phone dualcomm(GAME_OVER); // Display The Result GAME_TIMEATTACK_RESULT(counter, time); // 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, uint16_t time) { OLED_CLEAR(); drawTextCenter(128/2, 0, 2, "TIME ( " + String(time) + " ) Sec"); drawTextCenter(128/2, 20, 2, "KICKS ( " + String(count) + " )"); drawTextCenter(128/2, 50, 1, "<< EXIT >>"); OLED_SHOW(); } //------------------------------------------------------ // OLED - GAME TIMEATTACK RESULT //------------------------------------------------------ void GAME_TIMEATTACK_RESULT(uint16_t count, uint16_t time) { OLED_CLEAR(); float avgSpeed = 0.0; avgSpeed = (float)count/time; drawTextCenter(128/2, 0, 2, "RESULT"); drawTextCenter(128/2, 20, 2, String(avgSpeed, 2) + " K/s"); drawTextCenter(128/2, 50, 1, "<< EXIT >>"); OLED_SHOW(); // Waiting For Center Button To Move On while(1){ if(BTN_CENTER.pressed()) { break; } } }