2020-04-03 14:28:36 +03:00

317 lines
8.6 KiB
C++

//======================================================
// 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;
}
}
}