How can I make a time condition? - c++

I am trying to create a ping pong game and I need to say "If the user doesn't press space within 500 milliseconds, say 'You lost!' And if not, send the ball flying toward the other end."
The problem is that I can't use a function like Sleep() in if statements like:
if (Sleep(500)) {cout << "You lost!"}
Is there any time function that I could use in an if statement?

No.
You're programming at a lower level than a language with simple expressions to define rules like this.
Some ideas
Fundamentally, you're going to need to:
Set up a timer for 500ms
Set up a handler for keypresses
Have your timer expiry handler say "You lost" if a boolean flag is set, or otherwise "send the ball flying into the net".
Have your handler toggle that boolean flag if the keypress was Space
At a very basic level you could achieve this:
directly with two worker threads, or
crudely just by "waiting" for keypress activity (select, poll, epoll come to mind) with a timeout parameter (and ensure you don't reset the timeout if some other key were pressed instead), or
with help from your operating system, using e.g. a POSIX timer (though be cautious; this will send you into platform-specific, C-compatible land, which is probably not where you ultimately want to end up).
Usually, though, to do things "properly", we'd embed this logic into functionality provided by some engine implementing an "event loop" (particularly common in games, or in I/O-heavy applications).
Further information is going to take a book to explain adequately, and is thus not really appropriate in this medium. However, at least now you know which topics to explore in existing material.
Potentially interesting anecdote
I once wrote a little scripting language for my application, so that I could just define neat, high-level rules and the "compiler" would make use of my event loop to implement them. It made maintenance and expansion of my application really easy, which was important at the time because the rules became fairly complex and the application was broad in scope. It's not uncommon for computer game engines to embed scripting abilities of their own (say, using the "Lua" language), to achieve the same goal.

It's good to start thinking about your game design as a whole from the beginning as it helps solve problems like this in the design phase rather than further into development.
I'm not sure what library you're using but in sfml it would look something like this:
// Clock holds the current time.
// When we call Restart it returns the elapsed time since the last restart.
// With the current time and the start time we can find the elapsed time.
sf::Clock clock;
sf::Time maxTime = sf::milliseconds(500);
while(window.isOpen())
{
clock.Restart();
while(window.PollEvents(sf::Event e))
{
if(e.type == sf::Event::KeyPressed)
{
if(e.key.code == UP || e.key.code == DOWN || e.key.code == AnyOfOurOtherKeys)
{
maxTime = sf::milliseconds(500);
}
if(e.key.code == UP)
{
// Handle each individual key
}
if(e.key.code == DOWN)
{
// Handle each individual key
}
etc..
}
maxTime -= clock.Restart();
if(maxTime < sf::milliseconds(0))
{
std::cout << "Game Over, no input detected for 500 ms" << std::endl;
}
}
Regardless of library you can always use std::chrono::high_resolution_clock, std::chrono::milliseconds and std::chrono::duration to achieve the same results.
When you do your game loop you want to get the startLoopTime and then at the end of the game loop you want your endLoopTime. You can then do:
totalLoopTime = endLoopTime - startLoopTime;
maxTime -= totalLoopTime;
When you handle input you want a system where if a key that has a function is used, you set the maxTime back to 500ms. You could alternatively set a bool to true when a key is pressed and then run a check on the bool to restart maxTime.

Related

How to call a function every x seconds but be able to do stuff in the meantime

I'm building a tetris game and I need the pieces to fall every x seconds; something like:
while(true){
moveDown();
sleep(x)
}
The problem is, I need to be able to move the pieces left and right in the meantime, i.e., call a function while it's sleeping.
How can I do that in c++?
Both time and key presses can be events which can be used to wait on. On UNIXes you'd use something like poll() with a suitable time for timeout and the input device used to recognize key presses. On other systems there are similar facilities (I'm a UNIX persons and I have never worked on Windows specific stuff although it seems the Windows facilities are actually more flexible). Depending on the result of poll() (timeout or activity on the I/O device in that case) you'd do the appropriate action.
This problem is solvable in multiple ways (another idea that comes to mind is multithreading, but that seems overkill). One approach would be to keep track of the number of "game cycles" and execute some function every n-th cycle like this:
for(int32_t count{1};;count++)
{
if (!count % 5)
{
// do something every 5th cycle
}
// do something every cycle
sleep(x);
}
you can measure how much time has passed since last fall and move piece down after given amount and then reset counter. In pseudo-code it could look like this:
while(true)
{
counter.update();
if(counter.value() == fall_period)
{
move_piece_down();
couter.reset();
}
// rotate pieces
}
If you are using typical implementation of game loop your counter can just accumulate elapsed time since last frame.

Rising edge interrupt triggering multiple times on STM32 Nucleo

I am using the STM32 NUCLEO-F401RE microcontroller board.
I have a speaker programmed to change frequency by a set amount when the joystick is pushed up/down. My issue is that sometimes (more often than not) when the joystick is pushed up/down the frequency increases/decreases multiple times, implying that the ISR is executing multiple times. Also, the InterruptIn object is set to trigger on the rising edge however sometimes it also executes on the falling edge (when the joystick is returend to neutral after pushing up/down). Any help for getting over this?
void upISR()
{
if (greenLED.getStatus())
{
myTicker.detach();
frequency+=200;
myTicker.attach(callback(&spkr, &Speaker::toggle), 0.5/frequency);
}
}
'
int main()
{
InterruptIn up(A2);
InterruptIn down(A3);
InterruptIn fire(D4);
up.rise(&upISR);
down.rise(&downISR);
fire.rise(&toggleISR);
redLED.on();
while (1){}
}
Mechanical switch bounce is a feature of all mechanical switches to a lesser or greater extent. It is often necessary to implement "debouncing" in software especially if the switch is directly driving an interrupt as in this case.
A quick Google search for software denounce techniques yields some rather poor techniques IMO. I seen it done poorly more times than well unfortunately.
I suggest that in the switch ISR you start (or restart in the event of a "bounce") a hardware timer for a period of say 20ms or so (longer than the switch bounce time, but shorter than the time you could possibly to genuinely release the switch). Then in the timer ISR, you test the state of the switch and change the frequency accordingly:
Pseudocode:
void upISR()
{
debounceTimerRestart() ;
}
void downISR()
{
debounceTimerRestart() ;
}
void debounceTimerISR()
{
debounceTimerStop() ;
tDirection dir = getJoystickDir() ;
swithc( dir )
{
case UP :
{
increaseFrquency() ;
}
break ;
case DN :
{
decreaseFrquency() ;
}
break ;
}
}
What this does is trigger a timer interrupt shortly ("debounce time") after the switch stops bouncing. Note the timer is "single-shot" not periodic.
Below I present an enhancement at #BenVoigt's suggestion (in comments). I am keeping it separate to make it clear it was his work. The above will generally work, but if you have a particularly poor switch the following would resolve issues, and at little cost, so you may as well:
void debounceTimerISR()
{
debounceTimerStop() ;
static tDirection previous_dir = CENTRE ;
tDirection dir = getJoystickDir() ;
// If the state changed...
if( previous_dir != dir )
{
previous_dir = dir ;
switch( dir )
{
case UP :
{
increaseFrquency() ;
}
break ;
case DN :
{
decreaseFrquency() ;
}
break ;
}
}
}
Simple do not use EXTI for mechanical yousticks and buttons.
Use regular interrupt (for example systick) to poll the status of the pins.
We clearly believe this is the normal and expected bouncing of the switch. Mechanically a switch is some piece of metal that when acted on moves that metal from one pole to another, even if they do not resemble a wiper and two poles. The metal that moves will collide and bounce, the electrical connection will show that. The bouncing is often slow enough for a processor to get multiple interrupts, although that may be an under-sampling of all the bounces possibly seen electrically. If you try to look at it on a scope the scope itself may not-intentionally be filtering some of it (but so will your chip).
One way to see the problem is as with anything, research first then write the application later. This is not a solution but a way to characterize the problem for your system
switch_isr ( void )
{
...
some_global_variable <<= 1;
some_global_variable |= (pin_state_register>>pin_number)&1;
...
}
main ( void )
{
...
some_local_variable = 0;
while(1)
{
if(some_local_variable != some_global_variable)
{
some_local_variable = some_global_variable;
primitive_hex_print(some_local_variable);
}
}
}
No reason to expect to see every state change in the shifted variable, but you should see some and get a feel for the problem. Another way is to just have a counter increment on every interrupt, print periodically in the foreground and you will see one button press may result in multiple counts. And from the time it takes for the printouts to stop changing roughly in human time the settling time.
Filtering is all about state changes per unit time though and you have to have some flavor of time, be it a loop in the foreground that polls some information set by the interrupt (up/down counters, etc), or state changes relative to a timer/clock.
I do not know what the complete rules are for your assignment, if you can only have an interrupt for each switch and not a timer, or preferably a timer instead, I do not see a clean solution that will actually work. You would have to filter in the foreground but all that is doing is polling a copy of the pin state collected by the interrupt and is that any different than not using the interrupt? You cannot use Clifford's answer if you cannot set a timer interrupt, if you could use a timer and an interrupt then you could just periodically sample the switch states with that interrupt or a copy of the pin state collected by the pin state change interrupts and filter in the timer interrupt. Not the same as Clifford's but in all cases you need state change history relative to time to see when the thing settles.
Without a time reference and states not changing with respect to time (which a pin interrupt cannot show since the state has not changed) you cannot filter out the bounces. Instead work on your dexterity and how you flick the joystick up and down.

Problem with programming a basic hardware

I have an animation shown on LEDs. When the button is pressed, the animation has to stop and then continue after the button is pressed again.
There is a method that processes working with the button:
void checkButton(){
GPIO_PinState state;
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
if (state == GPIO_PIN_RESET) {
while(1){
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
if (state == GPIO_PIN_SET){
break;
}
}
//while (state == GPIO_PIN_RESET) {
//state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
//}
}
}
GPIO_PIN_SET is the default button position. GPIO_PIN_RESET is the condition when the button is pressed. The commented section is what I tried instead of the while(1){...} loop. The checkButton() method is called in the main loop from time to time to be run. The program runs on STM32 with an extension module (here the type of an extension module does not matter).
The fact is that this method stops animation just for a moment and does not work as I would like it to. Could you correct anything about this program to make it work properly?
Could you correct anything about this program to make it work
properly?
My guess is that you are trying to add a 'human interaction' aspect to your design. Your current approach relies on a single (button position) sample randomly timed by a) your application and b) a human finger. This timing is simply not reliable, but the correction is possibly not too difficult.
Note 1: A 'simple' mechanical button will 'bounce' during it's activation or release (yes, either way). This means that the value which the software 'sees' (in a few microseconds) is unpredictable for several (tbd) milliseconds(?) near the button push or release.
Note 2: Another way to look at this issue, is that your state value exists two places: in the physical button AND in the variable "GPIO_PinState state;". IMHO, a state value can only reside in one location. Two locations is always a mistake.
The solution, then (if you believe) is to decide to keep one state 'record', and eliminate the other. IMHO, I think you want to keep the button, which seems to be your human input. To be clear, you want to eliminate the variable "GPIO_PinState state;"
This line:
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
samples the switch state one time.
HOWEVER, you already know that this design can not rely on the one read being correct. After all, your user might have just pressed or released the button, and it is simply bouncing at the time of the sample.
Before we get to accumulating samples, you should be aware that the bouncing can last much more than a few microseconds. I've seen some switches bounce up to 10 milliseconds or more. If test equipment is available, I would hook it up and take a look at the characteristics of your button. If not, well, you can try the adjusting the controls of the following sample accumulator.
So, how do we 'accumulate' enough samples to feel confident we can know the state of the switch?
Consider multiple samples, spaced-in-time by short delays (2 controls?). I think you can simply accumulate them. The first count to reach tbr - 5 (or 10 or 100?) samples wins. So spin sample, delay, and increment one of two counters:
stateCount [2] = {0,0}; // state is either set or reset, init both to 0
// vvv-------max samples
for (int i=0; i<100; ++i) // worst case how long does your switch bounce
{
int sample = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15); // capture 1 sample
stateCount[sample] += 1; // increment based on sample
// if 'enough' samples are the same, kick out early
// v ---- how long does your switch bounce
if (stateCount[sample] > 5) break; // 5 or 10 or 100 ms
// to-be-determined --------vvv --- how long does switch bounce
std::this_thread::sleep_for(1ms); // 1, 3, 5 or 11 ms between samples
// C++ provides, but use what is available for your system
// and balanced with the needs of your app
}
FYI - The above scheme has 3 adjustments to handle different switch-bounce durations ... You have some experimenting to do. I would start with max samples at 20. I have no recommendation for sleep_for ... you provided no other info about your system.
Good luck.
It has been a long time, but I think I remember the push-buttons on a telecom infrastructure equipment bounced 5 to 15 ms.

GetAsyncKeyState() very CPU heavy? Am I using it correctly?

I am using GetAsyncKeyState() in a simple pong game of mine to check if the user has pressed the arrow keys. I read online that you need to use this function a certain way however I found out that it is very CPU heavy (using 50% of my CPU!). This was rather disconcerting, however, after some playing around I found out that if I added a sleep(1); then the CPU usage went down to 0% and everything still worked fine. There must be a better way of using this function or at least a better way of lowering CPU usage.
Any help here would be much appreciated!
My Code:
while(true)
{
for(i = 8; i < 191; ++i)
{
if(GetAsyncKeyState(i) == -32767)
{
if(i == VK_LEFT)
// do stuff
else if(i == VK_RIGHT)
// do stuff
else if(i == VK_UP)
// do stuff
else if(i == VK_DOWN)
// do stuff
}
}
Sleep(1);
}
It's not that GetAsyncKeyState is CPU-heavy; it's that you're calling it all the time as quickly as you can. It's equivalent to saying that i++ is CPU-heavy when you run it in an infinite loop.
You either should use GetMessage to wait until you actually have input, or if that's not good enough (because you perhaps also want to update some animation without waiting for a message), then you should pick some polling interval and use something like MsgWaitForMultipleObjects (or create frequently recurring timer messages with SetTimer).
Anything your program repeats infinitely without some sort of message mechanism, user input or something that blocks program execution, will by default cause the program to use up all the available CPU resources.
Your original implementation of keyboard input handling was grossly inefficient. By blocking the execution flow with Sleep you have managed to overcome that problem, but in the cost of accuracy - if the user manages to press a key in less than 1ms your program will simply ignore it.
Instead of using GetAsyncKeyState for constantly checking the keys for presses, you can utilize SetWindowsHookEx to set a keyboard hook and directly intercept and handle keystrokes directly. These should help.
Other options are to use DirectInput, external input handling libraries or wrappers.

C++ Timer control

I want to create a timer so that after completing the time(suppose 10 sec) the control should come out of the function..Please note that am starting the timer inside the function.Code is given below..I want to give certain time limit to that function so that after completing the time the control should come out of the function..I don't want to calculate the time..I want to give my own time so that the function should complete its execution within that time period..suppose if function is waiting for an input then also after completing time limit the control should come out indicating that "time has expired"..once it comes out of the function then it should continue with the next function execution...Is this possible in c++...
Begin();
// here I would like to add timer.
v_CallId = v_CallId1;
call_setup_ind();
call_alert_ind();
dir_read_search_cnf();
dir_save_cnf();
END();
If the code is linear and the functions called cannot be chopped into smaller pieces, your stuck to letting an external process/thread do the timing and abort the worker thread when the timeout is exceeded.
When you can chop the worker into smaller pieces you could do something like this
Timeout.Start(5000);
while ((TimeOut.TimeOut() == false) && (completed == false))
{
completed = WorkToDo()
}
This is a pattern we frequently use in our embbeded application. The timeout class was in house develop. It just reads the tick counter and looks if the time has passed. An framework like QT or MFC should have such a class itself.