The answer to this question came to me halfway through writing it and honestly I feel like I should finish what I started and document it since I've been stuck with this bug the whole day and it might come in handy later.
I'm using SFML and I have a number of buttons, and I want to play a blip sound-effect when the mouse cursor hovers over one of them...
This is the method inside the button class that tests for collision between the mouse cursor and a button:
bool menu_button::button_collision() {
if ((cursor.getPosition().x <= (text_box.getPosition().x)+text_box.getSize().x/2)
&& (cursor.getPosition().x >= (text_box.getPosition().x) - text_box.getSize().x / 2)
&&(cursor.getPosition().y <= (text_box.getPosition().y) + text_box.getSize().y / 2)
&& (cursor.getPosition().y >= (text_box.getPosition().y) - text_box.getSize().y / 2)) {
text.setFillColor(sf::Color(sf::Color::Yellow));
coll = true;
}
else { text.setFillColor(sf::Color(sf::Color::White)); coll = false; }
return coll;
}
And this is the code that plays the sound effect when the cursor hovers over a button:
for (int j = init; j < limit; j++) { //This is a loop that tests every button.
collision = buttons[j].button_collision();// 'collision' is a boolean that stores the value returned by the collision function.
if (collision == true) {
m_hover.play();
}
//Other instructions go here...
}
Now this code works just fine, but since it's inside the game loop, which repeats every frame, the sound is going to play an 'x' amount of times per second ('x' being the number of frames per second) which is not what I wanted, so I modified the code to look like this:
for (int j = init; j < limit; j++) {
collision = buttons[j].button_collision();
if (collision == true) {
if (collision2 == false) { // 'collision2' is another boolean, that becomes true AFTER the sound-effect have already played.
m_hover.play();
collision2 = true;
}
}
//Other instructions go here...
}
Now, the sound-effect plays the first time the cursor hovers over a button, but but ONLY the first time, and then it goes completely silent, so clearly we have another problem on our hands...
So I added this line under the parent condition (The one that tests collision
):
else { collision2 = false; }
I thought this would work, but now I was back to the first problem, where the sound-effect would be playing constantly for every frame in which the cursor was hovering over a button...
After a bit of tinkering, I came to realize that collision
resets to false
every frame, which is the reason the sound-effect ends up playing every frame, but I wasn't sure why and where/when this was happening, or how to get around it.
As it turns out, the reason collision
resets to false
every frame, is because I forgot that this whole set of instructions is contained within a for
loop that tests every button, so the collision test happens for every button every single frame, and and every time the returned value is stored inside collision
, meaning that collision
gets it's value reset a 'y' amount of times each frame ('y' being the number of buttons on the screen at that moment), and since the collision value for all the other buttons that don't have the cursor hovering over them is going to be false
, it makes perfect sense for the collision value to reset to false every frame.
Now the solution to this problem was clear, all I had to do was replace the collision2
boolean, with an array of boolean values, with each element of this array corresponding to the collision value of one of the buttons, meaning the size of this array is going to be equal to the total number of buttons I'm working with...
So now the code should look like this:
for (int j = init; j < limit; j++) {
collision = buttons[j].button_collision();
if (collision == true) {
if (collision2[j] == false) {// 'collision2' is an array that stores the collision values for each button.
m_hover.play();
collision2[j] = true;
}
}
else { collision2[j] = false; }
//Other instructions go here...
}
And now it works! I am as relieved as I am frustrated with this whole thing...