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.
Related
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.
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.
I am currently writing a program where I need to run a loop that can be interrupted at any time. In this case, a series of tones are playing over and over again but should stop when one of the values from a sensor comes back as HIGH.
At the moment, I've got this:
void loop() {
while(digitalRead(ctsPin) == LOW) {
// Some code here
}
}
However, the while loop will only break when the instructions inside it have finished running. Is there a way that I can run these over and over again but stop them at any time, even if it is part-way through?
Thanks in advance.
I take it that you are actually asking how to immediately break a loop which has many hard-coded delays (tones) in it, no matter what code inside that loop that is currently executing. That isn't possible.
Adding a lot of if statments all over the loop won't help, because that won't prevent delay-based code from playing out the current tone until it is done.
The alternative would be to create some sort of queue/ring buffer containing the items to be played. The PWM interrupt that plays the tones will go through this queue and play them one at a time.
When you wish to stop, you would then simply disable the interrupt and pull the port pin to a silent state. This will cause it to stop immediately, even if the program is playing the part between two edges of the tone signal.
The break statement will interrupt the current loop. So you should have a conditional statement for the condition you are monitoring, and if it evaluates to true, call break.
if (digitalRead(ctsPin) == HIGH){
break
}
Question is not clear. To stop running the loop you can use break as given below. Check if this is what you're looking for.
void loop() {
while(digitalRead(ctsPin) == LOW) {
// Some code here
if (digitalRead(ctsPin) == HIGH){
break;
}
// Some code here
}
}
There are two ways to break "instantly." One is to use an interrupt and the other is to check for the condition more often -- after each instruction if really necessary, and break out then:
void loop()
{
while(digitalRead(ctsPin) == LOW)
{
// code block (or even a single statement)...
if (digitalRead(ctsPin) == HIGH) break;
// code block (or even a single statement)...
if (digitalRead(ctsPin) == HIGH) break;
// code block (or even a single statement)...
if (digitalRead(ctsPin) == HIGH) break;
// etc.
}
}
If you get too many of these, it may be advisable then to look into an interrupt instead. For an example of how to do that, and the various interrupts available for your target board, I suggest taking a look at Arduino Interrupt Documentation.
If you decide to go that way, give it a try and then if you run into issues, ask a different question and we'll help you out.
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.
I have tried various setups with input and my one second timer but nothing is working. The entire code is brought to a halt when it reaches the part asking for input. I have an unbuffered stream, so I don't need to press enter to send the input. Also the purpose of this is for a pac-man game I'm designing for terminal use. What I want is basically to have a one second interval where the user can enter a command. If no command is entered, I want the pac-man to continue moving the direction it was moving the last time a command was entered.
EDIT:
time_t startTime, curTime;
time(&startTime);
do
{
input=getchar();
time(&curTime);
} while((curTime - startTime) < 1);
You could try using alarm() (or similar timer function) to throw and have your application catch a SIGALRM, though this is definitely overkill for PacMac. Consider using a separate thread (POSIX thread) to control a timer.
On Unix, you can simply use select or poll with a timeout on the standard input file descriptor (STDIN_FILENO, or fileno(stdin)). I would not bring in mouse traps built of signals and threads just for this.
My gut feeling tells me this:
Have one thread dedicated to processing user input and putting key events into a queue
The timer-activated thread, on every activation, consumes all key events in the queue, using the one that happened last, at the point of thread activation.
Make sure your access to the queue is synchronized.
// I/O Thread:
while (!stop) {
input = getchar();
lock_queue();
queue.push_back(input);
unlock_queue();
}
// Timer Thread:
while (!stop) {
lock_queue();
if (queue.size() == 0) {
action = DEFAULT_ACTION;
} else {
// either handle multiple key events somehow
// or use the last key event:
action = queue.back();
queue.clear();
}
unlock_queue();
perform_action(action);
sleep();
}
Full example posted as a Github Gist.
You could use a non-blocking input function such as getch() but it isn't very cross platform compatible.
Ideally you should be using events to update the game state, depending on which OS you are targeting you could use the OS events for key press or maybe a library such as SDL.