-
Hello I'm currently working on a program in which I have a ball which moves and collides with a square. What I need to determine is whether to flip the Xvelocity or the Yvelocity. The function looks like this
bool ADVBoxCollision(sf::gEntity* sprite1, sf::gEntity* sprite2, bool* pTop, bool* pSide)
{
sf::Rect<float> FirstRect = sf::Rect<float>(sprite1->GetPosition().x - sprite1->GetCenter().x ,sprite1->GetPosition().y - sprite1->GetCenter().y,sprite1->GetPosition().x+sprite1->GetSize().x - sprite1->GetCenter().x,sprite1->GetPosition().y+sprite1->GetSize().y - sprite1->GetCenter().y);
sf::Rect<float> SecondRect = sf::Rect<float>(sprite2->GetPosition().x - sprite2->GetCenter().x ,sprite2->GetPosition().y - sprite2->GetCenter().y,sprite2->GetPosition().x+sprite2->GetSize().x - sprite2->GetCenter().x,sprite2->GetPosition().y+sprite2->GetSize().y - sprite2->GetCenter().y);
//ToS stands for Top or side. It tells whether the sprite collided with the top/bottom part or the side part. 0 = top/bottom, 1 = sides
if(BoxCollision(FirstRect, SecondRect))
{
if((FirstRect.Left <= SecondRect.Right) && (FirstRect.Right >= SecondRect.Left))
{
if(!*pSide) *pSide = 1;
else *pSide = 0; //If RECT1 is to the left of RECT2
}
if((FirstRect.Top <= SecondRect.Bottom) && (FirstRect.Bottom >= SecondRect.Top))
{
if (*pTop) *pTop = 0; //If RECT1 is over RECT2
else *pTop = 1;
}
return BoxCollision(FirstRect, SecondRect);
}
else return false;
}
The pTop and the pSide variables points to a bool value which is use to conditionally reverse the Y or Xvelocity at a detected collision.
The problem is that the side collision always flips, no matter on what side the ball collides with the square and the top bool never flips at all.
Any help?
Also sorry for posting this here, wasn't sure if this fitted anywhere at all.
-
We can't really tell where what the problem is, since we have no idea what BoxCollision does.
Additionally I'd advice you to use references instead of pointers and since you're not gonna change anything about the sprites, use const references.
Also bool can work with 0 and 1 but it's actually meant to work with false and true.
And as a side note SFML provides typedef Rect<float> FloatRect;, so you don't need to write sf::Rect<float>.
So the code should more look like this:
bool ADVBoxCollision(const sf::gEntity& sprite1, const sf::gEntity& sprite2, bool& pTop, bool& pSide)
{
sf::FloatRect FirstRect(sprite1.GetPosition().x - sprite1.GetCenter().x ,sprite1.GetPosition().y - sprite1.GetCenter().y,sprite1.GetPosition().x+sprite1.GetSize().x - sprite1.GetCenter().x,sprite1.GetPosition().y+sprite1.GetSize().y - sprite1.GetCenter().y);
sf::FloatRect SecondRect(sprite2.GetPosition().x - sprite2.GetCenter().x ,sprite2.GetPosition().y - sprite2.GetCenter().y,sprite2.GetPosition().x+sprite2.GetSize().x - sprite2.GetCenter().x,sprite2.GetPosition().y+sprite2.GetSize().y - sprite2.GetCenter().y);
//ToS stands for Top or side. It tells whether the sprite collided with the top/bottom part or the side part. 0 = top/bottom, 1 = sides
if(BoxCollision(FirstRect, SecondRect))
{
if((FirstRect.Left <= SecondRect.Right) && (FirstRect.Right >= SecondRect.Left))
{
if(!pSide) pSide = true;
else pSide = false; //If RECT1 is to the left of RECT2
}
if((FirstRect.Top <= SecondRect.Bottom) && (FirstRect.Bottom >= SecondRect.Top))
{
if(pTop) pTop = false; //If RECT1 is over RECT2
else pTop = true;
}
return BoxCollision(FirstRect, SecondRect);
}
else
return false;
}
Regarding your problem, it's quite hard for us to spot the problem, since we'd need to go though everything by hand and asume stuuff, since we don't really see with what data you're working.
It's way easier on your side to check. Just start up the debugger, set breakpoints at the if-statements, check why the one if-statement never evaluates to true and trace back from there what happens before.
And since SFML 2 RC got (finally) released yesterday, you may consider switching over to SFML 2. ;)
-
Ty for the help. I rewrote the program to use references instead, and I had to change some other functions, so I haven't been able/ found it neccesary to write again ^^
Also BoxCollision is a simple call to a function which checks if the two rects sent as parameters intersect.
The problem is I think, that if the rects collide then both the if statements evaluate to true.
What I would be looking for then would be something that would only evaluate to true if it was to the side or only evaluate to true if it was top.
Using a if/else if could work, buuuut I think that the first statement would always go to true. Anyhow I'll go back to coding and see if I find anything.
-
So, if anyone happens to through their eye over here I'll just keeping detailing what I'm doing.
I decided to reset the bool at the start of every frame, instead pf at every collision. Furthermore I'm making the sprites borders "bigger" by adding +4 or something like that in the if call, so that the intended switch opportunity is detected better.
-
After about a week of tweaking the function I finally found something which works in 99.9% of all collisions. The only time that this code doesnt work is at veeeeeeery high speeds. Anyhow here is the code. If anyone would like to use it feel free to do so.
bool ADVBoxCollision(sf::gEntity& player, sf::gEntity& sprite2, bool& pTop, bool& pSide)
{
bool Firsttotheleft = false;
bool Firsttotheright = false;
bool Firstabove = false;
bool Firstbelow = false;
sf::FloatRect FirstRect = sf::FloatRect(player.GetPosition().x - (player.GetSize().x/2), player.GetPosition().y - (player.GetSize().y/2),player.GetPosition().x + (player.GetSize().x/2),player.GetPosition().y+(player.GetSize().y/2));
sf::FloatRect SecondRect = sf::FloatRect(sprite2.GetPosition().x - (sprite2.GetSize().x/2), sprite2.GetPosition().y - (sprite2.GetSize().y/2),sprite2.GetPosition().x + (sprite2.GetSize().x/2),sprite2.GetPosition().y+(sprite2.GetSize().y/2));
//ToS stands for Top or side. It tells whether the sprite collided with the top/bottom part or the side part. 0 = top/bottom, 1 = sides
if(BoxCollision(FirstRect, SecondRect))
{
if((FirstRect.Left - 20) <= (SecondRect.Left - FirstRect.GetWidth()))
Firsttotheleft = true;
if((FirstRect.Right + 20) >= (SecondRect.Right + FirstRect.GetWidth()))
Firsttotheright = true;
if((FirstRect.Top - 20) <= (SecondRect.Top - FirstRect.GetHeight()))
Firstabove = true;
if((FirstRect.Bottom + 20) >= (SecondRect.Bottom + FirstRect.GetHeight()))
Firstbelow = true;
if(Firstbelow || Firstabove)
pTop = true;
if(Firsttotheright || Firsttotheleft)
pSide = true;
return BoxCollision(FirstRect, SecondRect);
}
else return false;
}
bool ADVBoxCollision(sf::FloatRect FirstRect, sf::FloatRect SecondRect, bool& pTop, bool& pSide)
{
bool Firsttotheleft = false;
bool Firsttotheright = false;
bool Firstabove = false;
bool Firstbelow = false;
this->RECT1 = FirstRect;
this->RECT2 = SecondRect;
//ToS stands for Top or side. It tells whether the sprite collided with the top/bottom part or the side part. 0 = top/bottom, 1 = sides
if(BoxCollision(FirstRect, SecondRect))
{
if((FirstRect.Left - 20) <= (SecondRect.Left - FirstRect.GetWidth()))
Firsttotheleft = true;
if((FirstRect.Right + 20) >= (SecondRect.Right + FirstRect.GetWidth()))
Firsttotheright = true;
if((FirstRect.Top - 20) <= (SecondRect.Top - FirstRect.GetHeight()))
Firstabove = true;
if((FirstRect.Bottom + 20) >= (SecondRect.Bottom + FirstRect.GetHeight()))
Firstbelow = true;
if(Firstbelow || Firstabove)
pTop = true;
if(Firsttotheright || Firsttotheleft)
pSide = true;
return BoxCollision(FirstRect, SecondRect);
}
else return false;
}
(the RECT1 and RECT2 are members of the physics manager which I've created, so ignore/delete those calls if you feel like it)
Anyhow, tyvm for the help I got and for the tip to use references instead of pointers.
-
The only time that this code doesnt work is at veeeeeeery high speeds. Anyhow here is the code.
The effect is called tunneling. If you want to prevent this, you'll have to google a bit, there many solutions floating around.
If anyone would like to use it feel free to do so.
I just might use this, thanks. ;)
-
Ah ok, well I will check around on the internet about this mysterious "tunneling" then ^^. Thank you for the information.
Cool, if you run into any weird problems with this function feel free to send me a pm :)
-
By the way, if you dig deeper into complex collision detection and response, you could take a look at physics libraries like Box2D. The latter also has an option to handle tunneling ("bullet" flag).