So, inside the game loop function that tracks user input is called multiple times. I guess this happens because game loop goes like 40 iterations each second and if I hold down the key for a 0.5 second, function gets called 20 times. I tried to handle this with sfml events too but it didn't work window.setKeyRepeatEnabled(false). How can I solve this?
//this gets called 20-30times
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
leftPlayerPoints++;
}
Use two boolean flags: One for checking if the key is pressed or not, and one that is used to check if the action have happened yet.
In short something like
if (key_is_pressed)
{
if (!action_have_happened)
{
// Perform action...
action_have_happened = true;
}
// Else: Action have already happened this key-press, don't do it again
}
When the key is released reset both flags (to false).
That's what exactly IsKeyPressed is suppose to do , you have to use bitmasking and make it toggle state instead of continuing pressing.
Below is code from Win32API (C++). I know SFML has different events than Win32API but Masking should work in SFML also.
BOOL IsKeyToggled(CONST INT key)
{
SHORT key_state = GetAsyncKeyState(key);
BOOL is_toggled = key_state & 0x1;
return is_toggled;
}
The main point here is key_state & 0x1; bit masking with 0x1
Related
this is my first post!
I'm writing a C++ program to control main character in Touhou Games series; i'm making it for those who have hands disabilities and can't click arrow keys, but still can use mouse.
The player should trigger Arrow Keys with mouse movements (mouse goes left and left key is pressed, and so on..). I already did that part, but the character moves as if the arrow keys were pressed multiple times, so the character movements are a little clumsy and rough, not smooth and clean as if the key was HOLD.
My problem is that i have to know when mouse is idling/not moving (to understand how long the player wants to hold the arrow key -- the more the player slides the mouse in a direction, the more that arrow key is hold), but can't figure out how. Searching on Stackoverflow i've found GetLastInput function, but it triggers for EVERY input, and is not mouse-only related.
It should come out something like:
while( *mousenotidling* )
{
//holdbutton
}
What would you suggest? How can i know when mouse is idling (for short-times, like 20ms)? (or if you suggest other solutions, every opinion is welcomed)
I'm writing it in C++, with Codeblock and GCC compiler, my OS is Windows 7 x86 :)
You can call TrackMouseEvent and set the idling time to what is desire like 2000ms for 2sec idle time. Also you can use GetLastInputInfo to get the amount of milliseconds the last key or mouse movement was performed.
DWORD GetIdleTime()
{
LASTINPUTINFO pInput;
pInput.cbSize = sizeof(LASTINPUTINFO);
if (!GetLastInputInfo(&pInput))
{
// any errors will be reported
}
// return idle time in milliseconds
return pInput.dwTime;
}
Also you can try this one suggestion
int prev_x = 0, prev_y = 0; while (1)
{int x = ..., y = ...; if (x == prev_x && y == prev_y) {mouse was moved}
else {mouse wasn't moved} prev_x = x; prev_y = y;}
In my project, function clipsUpdate reads some facts which are set by CLIPS without the interference of my C++ code. Based on the read facts, clipsUpdate calls the needed function.
void updateClips(void)
{
// read clipsAction
switch(clipsAction)
{
case ActMove:
goToPosition (0, 0, clipsActionArg);
break;
}
}
In goToPosition function, a message is sent to the vehicle to move to the specified position and then a while loop is used to wait until the vehicle reaches the position.
void goToPosition(float north, float east, float down)
{
// Prepare and send the message
do
{
// Read new location information.
}while(/*Specified position reached?*/)
}
The problem is that updateClips should be called every 500 ms and when the goToPosition function is called, the execution is blocked until the target location is reached. During this waiting period, something may happen that requires the vehicle to stop. Therefore, updateClips should be called every 500 ms no matter what, and it should be able to stop executing goToPosition if it's running.
I tried using threads as following, but it didn't work successfully with me and it was difficult for me to debug. I think it can be done with a simpler and cleaner way.
case ActMove:
std::thread t1(goToPosition, 0, 0, clipsActionArg);
t1.detach();
break;
My question is, how can I check if the target location is reached without blocking the execution, i.e., without using while?
You probably want an event-driven model.
In an event-driven model, your main engine is a tight loop that reads events, updates state, then waits for more events.
Some events are time based, others are input based.
The only code that is permitted to block your main thread is the main loop, where it blocks until a timer hits or a new event arrives.
It might very roughly look like this:
using namespace std::literals::chrono_literals;
void main_loop( engine_state* state ) {
bool bContinue = true;
while(bContinue) {
update_ui(state);
while(bContinue && process_message(state, 10ms)) {
bContinue = update_state(state);
}
bContinue = update_state(state);
}
}
update_ui provides feedback to the user, if required.
process_message(state, duration) looks for a message to process, or for 10ms to occur. If it sees a message (like goToPosition), it modifies state to reflect that message (for example, it might store the desired destionation). It does not block, nor does it take lots of time.
If no message is recived in duration time, it returns anyhow without modifying state (I'm assuming you want things to happen even if no new input/messages occur).
update_state takes the state and evolves it. state might have a last updated time stamp; update_state would then make the "physics" reflect the time since last one. Or do any other updates.
The point is that process_message doesn't do work on the state (it encodes desires), while update_state advances "reality".
It returns false if the main loop should exit.
update_state is called once for every process_message call.
updateClips being called every 500ms can be encoded as a repeated automatic event in the queue of messages process_message reads.
void process_message( engine_state* state, std::chrono::milliseconds ms ) {
auto start = std::chrono::high_resolution_clock::now();
while (start + ms > std::chrono::high_resolution_clock::now()) {
// engine_state::delayed is a priority_queue of timestamp/action
// ordered by timestamp:
while (!state->delayed.empty()) {
auto stamp = state->delayed.front().stamp;
if (stamp >= std::chrono::high_resolution_clock::now()) {
auto f = state->queue.front().action;
state->queue.pop();
f(stamp, state);
} else {
break;
}
}
//engine_state.queue is std::queue<std::function<void(engine_state*)>>
if (!state->queue.empty()) {
auto f = state->queue.front();
state->queue.pop();
f(state);
}
}
}
The repeated polling is implemented as a delayed action that, as its first operation, inserts a new delayed action due 500ms after this one. We pass in the time the action was due to run.
"Normal" events can be instead pushed into the normal action queue, which is a sequence of std::function<void(engine_state*)> and executed in order.
If there is nothing to do, the above function busy-waits for ms time and then returns. In some cases, we might want to go to sleep instead.
This is just a sketch of an event loop. There are many, many on the internet.
I'm working on a game engine project (for learning purposes) and I've run into an issue with my audio system. I currently have a static PlaySound() function within my AudioSystem class that's defined like so:
void AudioSystem::PlaySound(uint16 soundID)
{
pendingSoundRequests[numSoundsPending].id = soundID;
numSoundsPending++;
}
Keeping in mind things are simplified here for ease of understanding. PendingSoundRequests is an array of soundEffect objects which only contain an id which is tied to a certain sound file. This function is called from other systems like my input system that plays a sound upon a certain key press:
void UpdateInput()
{
//....other code
if (keypress == spaceBar)
PlaySound(1)
}
This stores a soundID of 1 which plays a certain audio file. The AudioSystem will then loop over and play all sounds in it's update loop like so:
void AudioSystem::Update()
{
for (int i = 0; i < numSoundsPending; i++)
{
StartAudio(pendingSoundRequests[i].id);
//Reset all sounds id's to 0 meaning no sound should be played
//unless id is passed another number through PlaySound function
pendingSoundRequests[i].id = 0;
}
numSoundsPending = 0;
}
This works fine if the spacebar key is pressed only once, but if I hold down the key then since the update loop is called every frame, each individual sound keeps restarting itself and only playing the first millisecond of it's sound before being cut off by the same sound having to be played again on the next loop.
How would I go about creating some logic to prevent sounds from playing multiple times when I only want them to play once on the first press of the key?
Keep a list of what is currently playing, and remove it when it is done. When you go to start a sound you should check to see if the sound is already playing. If it is don't start the sound again. That way you avoid the issue.
You could put a sleep after the sound is played as long as the sound takes to play which would make it not play the next sound until after one sound is played. Are you using a separate thread for your audio system?
void AudioSystem::Update()
{
for (int i = 0; i < numSoundsPending; i++)
{
StartAudio(pendingSoundRequests[i].id);
//sleep here as long as the sound takes
//Reset all sounds id's to 0 meaning no sound should be played
//unless id is passed another number through PlaySound function
pendingSoundRequests[i].id = 0;
}
numSoundsPending = 0;
}
That might make a queue of sounds.
So you could do something like this:
//get current number of sounds pending
x = numSoundsPending
//sleep
//get new current after sleep
y = numSoundsPending
//get difference
z = y - x
//skip the difference
i = i + z
As far as I know, there are three types of key event:
Keydown: returns true only once per key press.
Keyup: returns true only once per key press.
Keypress: remains true when key is pressed.
you need Keydown event here.
I know this question has been asked several times on the net, but I could not find any of those answers helpful.
I want to keep running a loop and break it once the user press a key (e.g. enter or esc). I don't want it to ask user any input during the process.
I have a while loop.
I am new to C++, so please answer simply.
My system is Mac OS X.
There you go. I hope this helps.
#include <iostream>
#include <thread>
#include <atomic>
// A flag to indicate whether a key had been pressed.
atomic_bool keyIsPressed(false);
// The function that has the loop.
void loopFunction()
{
while (!keyIsPressed) {
// Do whatever
}
}
// main
int main(int argc, const char * argv[])
{
// Create a thread for the loop.
thread loopThread = thread(loopFunction);
// Wait for user input (single character). This is OS dependent.
#ifdef _WIN32 || _WIN64
system("pause");
#else
system("read -n1");
#endif
// Set the flag with true to break the loop.
keyIsPressed = true;
// Wait for the thread to finish.
loopThread.join();
// Done.
return 0;
}
Update: Since the flag keyIsPressed is shared between threads, I added atomic for that. Thanks to #hyde.
This is indeed OS dependent, but probabilities are that you use Windows.
First, you'll need to include :
#include <Windows.h>
It gives you access to the function GetAsyncKeyState, and to Windows' key macros (list of Windows' key macros).
You'll also need the Most Significant Bit to evaluate key press ; just initialize it as a const in your code :
const unsigned short MSB = 0x8000;
Finally, let's put all together in a function :
bool listenKeyPress(short p_key)
{
//if p_key is pushed, the MSB will be set at 1
if (GetAsyncKeyState(p_key) & MSB)
{
return true;
}
else return false;
}
//Example of a call to this function to check if up enter is pressed :
listenKeyPress(VK_RETURN)
Then your while loop can be typed either :
while (!listenKeyPress(VK_ENTER))
{
}
or
bool quit = false;
while (!quit)
{
if (listenKeyPress(VK_ENTER) || listenKeyPress(VK_ESCAPE)
quit = true;
}
There you go!
Was curious myself how to do this when started... turns out never really used it was better to just getch() but if you need this and using windows include Windows.h and the following code should point you in the right direction (hopefully)
bool f = true;
while (f)
{
if (GetAsyncKeyState(VK_UP)){
//Enter code for when a button is pushed here
f = false;
}
else{
//Code to run until the button is pushed
}
}
If you want to use a different button VK_UP can be changed to any key or mouse button you have, just scroll through the list(assuming you are probably a student using visual studio) if you have no list look up what key applies for the button you wish to press.
EDIT: Also if you want it to run forever remove the f = false and it will work while button is pressed and while not pressed to do whatever you like (Not great coding practice to leave no exit of a while loop though so probably best to test for a key being pressed in another while loop to exit)
I'm trying to handle the keypress event of the console in Windows 7.
When I'm press a left ctrl key i'm expecting to get code 0x0008 (0b00001000 - LEFT_CTRL_PRESSED), but instead of this i'm getting 0x0028 (0b00101000).
...
DWORD n;
INPUT_RECORD ir;
HANDLE hin;
hin = GetStdHandler(STD_INPUT_HANDLE);
...
ReadConsoleInput(hin, &ir, 1, &n)...
...
if(ir.Event.KeyEvent.dwControlKeyState == LEFT_CTRL_PRESSED) {
// some code..
}
if using xor 32 all works fine:
if((ir.Event.KeyEvent.dwControlKeyState ^ 32) == LEFT_CTRL_PRESSED) {
// some code..
}
Where did the extra bits?
p.s.: project in unicode
dwControlKeyState is a bitmap.
The single bits of the dwControlKeyState describe the states of certain keys at the same time.
The 3rd (0-indexed) bit equals 0x008 and indicates left-ctrl-key pressed.
To test for it do like so:
if (ir.Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) {
// some code..
}
For a full description of this bitmap you might like to read here under dwControlKeyState: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684166%28v=vs.85%29.aspx
If you want to check if LEFT_CTRL_PRESSED is active, you should use
if (ir.Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED)
as dwControlKeyState contains several bits indicating different things. Your ^ 32 will invert the value of the NUMLOCK_ON bit, so if you press num-lock, your code will suddenly change behaviour - which is probably not what you want to do.