play sound while condition is true - c++

I have two images, when the ball image touches the other image I want a sound to be played. This is my code:
while (((dstX + 31) > wallRect.x) && ((dstX + 31) < (wallRect.x+30)) && (dstY < (wallRect.y + wallRect.h)) && ((dstY + 31) > wallRect.y)) //31 = ball dimension.
{
Mix_PlayMusic(soundEffect, -1);
}
When the first image leaves the second image the sound still plays. How can I do this?

Your code can't possibly work. Why do you even have a while loop there? This is just going to call Mix_PlayMusic() over and over again, regardless of whether the music is already playing or not. As a side effect, this loop will consume all your CPU, regardless of whether its condition evaluates to true or false.
The way this is normally done, is to have a check somewhere inside your central event loop, and check there whether the images intersect, and whether they were intersecting in the previous iteration of the event loop. This is how you decide whether to start of stop the music.

Use if instead of while, or at least check if the music is playing before calling play function.

Related

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.

How do I make your program increment repeatedly until another key is pressed in a switch statement

I have been working on one of those snake games and I have a switch statement that says if a key is pressed to move the snake in a direction by incrementing/decrementing, but it will only do that if I hold it. I am looking for a way to have the snakes location keep incrementing without the user holding that key. I put one case below
if(_kbhit()) {
switch(_getch()) {
case 'a' :
dir = LEFT;
x--;
I am looking for a way to have ... keep incrementing without the user
holding that key."
IMHO, you should consider the "select()" function (if it is available in your OS)
Long ago I used "select()" in vxWorks. I see from a man page this function is also available to Ubuntu Linux. (maybe it is available to your system?)
With the select statement, a thread or program can "monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g. input possible). A file descriptor is considered ready if it is possible to perform a corresponding operation (e.g., read() without blocking, or a sufficiently small write())." (from man page)
In practice, the system I worked on had a user interface thread (one of several) issue reads and monitor the input fd (via select) for user input. Our select used a 1/2 second time out (you choose rate). Thus, every half second, if no user input occurred at that port (i.e. device), the time out would release the program to check the bits in the fd_sets.
Nothing prevents the code from doing additional activites in a timeout.
I would guess you will only need to work on readfds, and can leave the other fds empty.
In other words, with select, your code 'monitors' for some user input with a time out, and takes action on either the user input (key stroke) or because of the time out.
This sounds like what you are looking for - action without pressing a key.
Your current design sounds like it moves the snake on press event.
I think you're looking to modify the design such that press events update some current-direction flag, while some background timer thread moves the snake at some regular frame rate.
Your code only moves the snake on key press. You need to implement some kind of game loop which moves the snake at a regular interval based on a direction variable. You can then refactor your key press code to simply update the direction.
Pseudo code:
while: # loop forever
# below could be your switch statement
if direction == 0: # north
y--
if direction == 1: # east
x++
if direction == 2: # south
y++
if direction == 4: # west
x--
if _kbhit():
if _getch() == 'a':
direction == 4 # west
# etc...

Bullet intersecting with enemy too many times (running through the update loop too often)

for (int i = 0; i < playerBullets.size(); i++)
{
// Ship projectile hit enemy
if (IntersectsWith(playerBullets[i].ReturnBoundingBox()) || IntersectsWith(playerBulletsTwo[i].ReturnBoundingBox()))
{
//Deal with enemies response to collision
//Do damage
Damage();
if (ReturnHealth() <= 0)
{
this->mobsKilledCounter++;
SetCurrentTexture(currentTextureKey);
}
}
}
What happens is that the bullet hits the enemy and it runs the code and does damage (which is what I want), but then it runs through the code continuously after for the same bullet (like 1000 times a second), killing the enemy instantly. This code is in my Update loop which is why it's continuously going through it.
Anyone know how I can stop this? I tried booleans but it wasn't working too well because I am using a vector and multiple bullets/enemies.
I would need to see how you are handing your "bullet" objects, and maybe see the "Update loop", but I will throw some suggestions out there:
1 - Are these "bullets" destroyed on collision? If the loop keeps running, and the bullets are still there, then they will be detected and deal damage every time your loop runs until they "exit" the object they are colliding with!
2 - Have you thought about putting a cool-down timer on how much damage a player can take per second? Or a "bool has_dealt_damage_to_player" flag for your bullets?
Also, I have no idea what this is doing:
this->mobsKilledCounter++;
Best of luck. Maybe try a decent debugger? What IDE are you working in?

how to use time in C++

I am a beginner in programming and I started to create a game in C++ where the player disappears from the screen(he dies) when a rock hits it.
What can i do to put the player back on the screen after 2 seconds?
I have number of lifes(LifeNb) a function which delete the player from the screen(removePlayer) and a function that add the player on the screen(addPlayer).
How can i do this using ?
int time = std::clock()/1000;
if(the rock hit) {
number of lives --;
remove player;
if(time == 2)
add player;
}
It's something like this?
One way to do it: When your player dies, store the current time (plus two seconds) to a variable. On each iteration of the game's event loop, check to see if the current time is greater than or equal to the time in the variable. If it is, restore the player, and set the variable's value to (a very large value that the clock will never reach).
clock_t timer = clock();
if ((clock()/CLOCKS_PER_SEC)-(timer/CLOCKS_PER_SEC) >= 2)
player.add();
If you just want to wait two seconds, however, you could also use the system library function sleep() for two seconds.
The sleep() function will delay for a specified number of seconds before continuing execution. It seems to be what you are looking for.
See here: http://pubs.opengroup.org/onlinepubs/009604599/functions/sleep.html

Multiple functions simultaneously in Arduino

I'm working on an Arduino sketch where I created two traffic lights, one for normal traffic and one for pedestrians. I created a function for each of these two lights, which loops it through it's cycle (for example: turn yellow, wait 20 seconds, then turn red and wait again). These are called aTrafficlight() and pTrafficlight, where a is the normal light and p the one for the pedestrians. In my loop() function I set a digitalRead for a button. When this button is pressed the traffic lights should cycle through their loops one at a time (so the normal light turns red, pTrafficlight waits a bit, then turns green, blinks a few times, turns red, waits and ends the loop, so it goes to it's original state.)
This all works. But now I want to add a buzzer. This buzzer must beep once a second while the pTrafficlight is red, once a tenth second while it's green and twice per two seconds while it's flashing green.
Here I encountered a few problems:
- When waiting in original state (button's not pressed) it seems I can sometimes press the button without reaction because the loop is still going. I need to figure out how to avoid waiting in the loop when buttonState == LOW. (There's a function wait(int sec))
- When the button is pressed, it loops through the cycles. I could just write some kind of loop implementing the traffic light being red and beeping at the same time, but I'd rather keep these seperated.
- Same for the double beeps. I do not want the beeping and flashing of the light to be in the same for loop, as it's confusing and difficult to read and understand the code.
Here's my loop():
int buttonState = 0;
void loop(){
buttonState = digitalRead(pButton);
if(buttonState == LOW){
vSet("red");
pSet("green");
// This is where I tried to create the sound.
digitalWrite(pSound, HIGH);
delay(10);
digitalWrite(pSound, LOW);
wait(1);
} else {
aTrafficlight();
pTrafficlight();
}
}
Is there a way to solve my problems with multithreading? I tried to look it up at arduino.cc and google, but I can't find a way I understand enough to use it in my existing code.
If not, do you have any better suggestions?
You don't need multi-threading. You need to use timers, whether via interrupts (as Pawel wrote) or via another mechanism, such as the Metro library, that lets the code continue to loop through while the timer is running. See this question and answer: How Can I Create Interrupts in C for Arduino
Coincidentally, I recently posted some material both on state machines and the Arduino, as Hans Passant mentioned, and on alternatives to delay(), both with additional references you might find useful.
You could use a time-slice design. Let me just outline this in very general terms.
First code loop so that it always issues a delay(1) and set a mod 10 counter as:
int stopWhen = -1; // at startup
// etc.
x = (x+1)%10; // every time loop execs
Then when buttonState == LOW
if (stopwWhen = -1)
{
stopWhen = x;
// beep etc.
}
But on every loop:
// always exec this:
if (stopWhen == x)
{
stopWhen = -1;
// stop beeping.
}