How to prevent multiple sound calls in update loop of game engine? - c++

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.

Related

When received key input, output should stop streaming with a delay and put it all out at once

The famous text scrolling effect has been used in many games, and I mean many console-based-RPG games.
I'm somewhat trying to make my own as a novice project to sharpen my C++ skills, however, I got stuck somewhere.
You see, while a stream of text is scrolling, the player eventually gets bored and wants to skip those texts.
What happens is, that when the player presses a certain key, the text stops scrolling(and by scrolling I mean spitting out characters of a string with increasing index i with a slight delay) and it spits out everything at once.
This is quite the effect which I am trying to replicate.
This is the I currently use (without the skip-through effect):
for(int i = 0; i<text.length();i++)
{
std::cout << text[i];
Sleep(200);//WINAPI function for timeout. DWORD Milliseconds as argument
}
And the one that I want:
for(int i = 0; i<text.length();i++)
{
std::cout << text[i];
if(GetAsyncState(VK_RETURN)
{
continue;
}
else{
Sleep(200);//WINAPI function for timeout. DWORD Milliseconds as argument
}
}
This is very novice code, so please don't criticize me.
So I end this shtick with my question:
How to stop text from streaming with a delay, and to make it output it all at once.
Have a nice day!

Function gets called multiple times

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

C++, detecting if mouse is idle-ing (short-time, 20ms)

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

Run two delays at once C++

I want to make a program in which there are two dots blinking (with a break of 10ms) simultaneously, but one with delay 200ms and other with delay of 300ms. How can I play these two dots simultaneously from beginning? Is there a better way to that from following:
for(int i=1;i<100;i++)
{
if (i%2==0)
circle(10,10,2);
if (i%3==0)
circle(20,10,2);
delay(10);
cleardevice();
delay(100);
}
I would do something like this instead:
int t0=0,t1=0,t=0,s0=0,s1=0,render=1;
for (;;)
{
if (some stop condition like keyboard hit ...) break;
// update time, state
if (t>=t0) { render=1; s0=!s0; if (s0) t0+=10; else t0+=200; }
if (t>=t1) { render=1; s1=!s1; if (s1) t1+=10; else t1+=300; }
// render
if (render)
{
render=0;
cleardevice();
if (s0) circle(10,10,2);
if (s1) circle(20,10,2);
}
// update main time
delay(10); // Sleep(10) would be better but I am not sure it is present in TC++
t+=10;
if (t>10000) // make sure overflow is not an issue
{
t -=10000;
t0-=10000;
t1-=10000;
}
}
Beware the code is untested as I wrote it directly in here (so there might be syntax errors or typos).
The basic idea is having one global time t with small enough granularity (10ms). And for each object have time of event (t0,t1) state of object (s0,s1) and periods (10/200 , 10/300).
If main time reach the event time swap the state on/off and update event time to next state swap time.
This way you can have any number of objects just make sure your main time step is small enough.
The render flag just ensures that the scene is rendered on change only.
To improve timing you can use RDTSC instead of t+=10 and actually measure how much time has passed with CPU frequency accuracy.
To display the two circles simultaneously in the first round, you have to satisfy both conditions i%2==0 and i%3==0 at once. You can achieve it by simply changing
for(int i=1;i<100;i++)
to
for(int i=0;i<100;i++)
// ↑ zero here

How can I wait to see how many times the light flashes with arduino?

I know this may seem like a random question, basically I have a photo resistor set up in a circuit so that it detects light . I have a laser that will flash for different amounts of time to signal something, lets say a flash of 1/2 a second followed by a flash of 1 second = a.
How can I wait and detect this, sorry if this doesn't make sense...
This function will return the amount of time a laser module was shot at a photo resistor in milliseconds:
int photo_resistor_time()
{
int i = 0;
while (photo_resistor_value > 100)
{
i++;
Delay(1);
}
return i;
}