Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: If bug? SFML 1.6  (Read 2913 times)

0 Members and 1 Guest are viewing this topic.

natchos

  • Jr. Member
  • **
  • Posts: 97
    • View Profile
    • Email
If bug? SFML 1.6
« on: July 21, 2012, 03:32:20 am »
Hey so I've got this really weird expression that just flatout refuses to evaluate to true.

Here comes the function dump, which I will explain.

bool ADVBoxCollision(sf::gEntity& player, sf::gEntity& sprite2, bool& pTop,bool& pLSide, bool& pRSide, bool& pBottom)
{
        float YVel = player.GetYVelocity();
        float HSLS = 0;
        if((YVel > -3.0f) && (YVel < 3.0f)) HSLS = 7;
        else if((YVel > -9.0f) && (YVel < 9.0f)) HSLS = 30;
        else HSLS = 50;
        /* HSLS stands for HighSpeed-LowSpeed. If the speed of one of the objects is high it is generally preferable to use a larger hitbox (to more accurately
        detect hits. However, at low speeds this results in alot of jitter as the sprites get pushed around the whole time. Therefore we modify the HSLS
        variable depending on the Velocity given to us */

        bool Firsttotheleft = false;
        bool Firsttotheright = false;
        bool Firstabove = false;
        bool Firstbelow = false;
        sf::FloatRect FirstRect = sf::FloatRect(player.GetPosition().x - player.GetSize().x/2 - HSLS, player.GetPosition().y - player.GetSize().y/2 - HSLS,player.GetPosition().x + player.GetSize().x/2 + HSLS,player.GetPosition().y+player.GetSize().y/2+HSLS);
        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 - 30) <= (SecondRect.Right - (FirstRect.GetWidth() - HSLS*2)) &&  (FirstRect.Left + 10 >= (SecondRect.Right - FirstRect.GetWidth())))
                        Firsttotheleft = true;
                if((FirstRect.Right + 30) >= (SecondRect.Left + (FirstRect.GetWidth() - HSLS*2)))
                        Firsttotheright = true;
                if((FirstRect.Top - 30) <= (SecondRect.Bottom - (FirstRect.GetHeight() - HSLS*2)))
                        Firstabove = true;
                if((FirstRect.Bottom + 30) >= (SecondRect.Top + (FirstRect.GetHeight() - HSLS*2)))
                        Firstbelow = true;
                if(Firstbelow) pBottom = true;
                if(Firstabove) pTop = true;
                if(Firsttotheright) pRSide = true;
                if(Firsttotheleft) pLSide = true;
                return BoxCollision(FirstRect, SecondRect);
        }
        else return false;
}

Most of it is fairly straightforward. I construct two rectangles from the sprite and then collide them.
The problem comes when I need to find a distinction between the sides( the
if((FirstRect.Left - 30) <= (SecondRect.Right - (FirstRect.GetWidth() - HSLS*2)) &&  (FirstRect.Left + 10 >= (SecondRect.Right - FirstRect.GetWidth())))
                        Firsttotheleft = true;
                if((FirstRect.Right + 30) >= (SecondRect.Left + (FirstRect.GetWidth() - HSLS*2)))
                        Firsttotheright = true;
                if((FirstRect.Top - 30) <= (SecondRect.Bottom - (FirstRect.GetHeight() - HSLS*2)))
                        Firstabove = true;
                if((FirstRect.Bottom + 30) >= (SecondRect.Top + (FirstRect.GetHeight() - HSLS*2)))
                        Firstbelow = true;
part)

It just flat out refuses to evaluate to true,
I've tried changing the if expressions to every goddamn combination possible.
At one point I simply wrote it as
if((FirstRect.Left > 0)
                        Firsttotheleft = true;
                if((FirstRect.Right > 0)
                        Firsttotheright = true;
                if((FirstRect.Top > 0)
                        Firstabove = true;
                if((FirstRect.Bottom > 0)
                        Firstbelow = true;
Not even then did the ifs evaluate to true (and before you ask, yes I put in breakpoints to find if FirstRect was null or set to zero. It was not).

I'm just wondering whether anyone else has encountered something similar.

Canvas

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: If bug? SFML 1.6
« Reply #1 on: July 21, 2012, 05:18:28 am »
I've looked at your code and I cant really seem to see problem, but your collision check code is quite hard to understand, the way I do my collision detection is using a point in a rectangle method. so for example I have this has my method
bool pointInRect(int point_x, int point_y, int rect_x, int rect_y, int rect_w, int rect_h)
        {
        if ( (point_x >= rect_x) && (point_x <= rect_x + rect_w-1) )
        {
                if ( (point_y >= rect_y) && (point_y <= rect_y + rect_h-1) )
                {return true;}
        }
        return false;
        }
 
this code will just check a point is inside a rectangle. Hope this helps

thePyro_13

  • Full Member
  • ***
  • Posts: 156
    • View Profile
Re: If bug? SFML 1.6
« Reply #2 on: July 21, 2012, 06:24:49 am »
EDIT: this code if from SFML2, but the functions all still exist in 1.6, just with a different capitalisation, ie. sf::Rect<T>::Intersects().

So why aren't you just using Rect1.intersects(Rect2)?

You can compare the positions or origins of the two rects to find out which side was responsible  for the collision.

Here's one of the collision functions from my project. I do the x movement and y movement separately(for a different reason).

We use the built in intersection function to detect the collision. And pass the collision area into another rect called gap using this version of the intersect function(which turns out to be one of my favorite functions).

Then we can deduct the gap rect from our position in order to undo the move, until we are pushed right up against the object we collided with, but not overlapping.

The goal of this function was to remove the jitter associated with movement collision, it resulted in a really smooth movement, where objects can push against and slide along other objects, without going through or without any noticeable jitter.
sf::Vector2f Area::TryMoveY(sf::Vector2f move, sf::FloatRect rect)
{
        for(std::list<Tile*>::iterator iter = MapData.begin(); iter != MapData.end(); iter++)
        {
                sf::FloatRect gap, collider = (*iter)->GetRect();
                if(rect.intersects(collider, gap))
                {
                        if(rect.top < collider.top) //we are above collider
                        {
                                move.y -= gap.height; //right on the money
                                rect.top -= gap.height; //update our collision rect to represent out new pos.
                        }
                        else // we are beneath the collider
                        {
                                move.y += gap.height;
                                rect.top += gap.height;
                        }
                        //rect.top += move.y;
                }
        }
        return move;
}

With a little modification we can create this psudocode function, which would easily replace your "if(BoxCollision(FirstRect, SecondRect))" code. You would have to modify the rects with your HSLS variable before reaching this code however.

This code is much simpler, and easier to step through if there turns out to be a bug.
Direction FindColDir(sf::FloatRect rect, sf::FloatRect collider)
{
        sf::FloatRect gap;
        if(rect.intersects(collider, gap))
        {
                sf::Vector2f dir = collider.GetPosition() - gap.GetPosition(); // we use the gap to ensure that the position is around the same row and column as our object
                 float x = abs(dir.x), y = abs(dir.y);

                 if(x > y)
                 {
                       if(dir.x < 0) return WEST; else return EAST;
                 }
                 else
                 {
                        if(dir.y < 0) return NORTH; else return SOUTH;
                  }
        }
        return NOCOLLIDE;
}

I generally avoid writing the rect collision code myself, because it's ugly and can easily hide errors. I prefer to refractor my code so that I can rely on the functions in the rect class. It make my code easier to read, and generally has less annoying bugs.

Hope this helps!
« Last Edit: July 21, 2012, 06:32:44 am by thePyro_13 »

natchos

  • Jr. Member
  • **
  • Posts: 97
    • View Profile
    • Email
Re: If bug? SFML 1.6
« Reply #3 on: July 21, 2012, 01:39:33 pm »
Tyvm for the replies guys! I'll read them through more carefully and see what I can learn/use from them.

To thePyro_13: BoxCollision is just a call to Rect::Intersect.

However I use collision between two different classes and also in the same classes.
This mean I have 3 ADVBoxcollision and 3 BoxCollision functions.

bool BoxCollision(sf::gEntity sprite1, sf::gEntity sprite2)
{
        this->RECT1 = sf::FloatRect(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::gEntity* localpointerrect2 = &sprite2;
        return BoxCollision(localpointerrect1,localpointerrect2);
}

bool BoxCollision(sf::FloatRect FirstRect, sf::FloatRect SecondRect)
{
        this->RECT1 = FirstRect;
        this->RECT2 = SecondRect;
        return this->RECT1.Intersects(this->RECT2);
}

bool BoxCollision(sf::gEntity* sprite1, sf::FloatRect SecRect)
{
        this->RECT1 = sf::FloatRect(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);
        return this->RECT1.Intersects(SecRect);
}
 

EDIT: Just to clarify.
My function is built in such a way that the 4 if statements does not even get checked if the two rects are not intersecting (which is checked using the built in Rect::Intersects)
EDIT2: Pyro, from where did you get the GetPosition function? From what I know it is not part of the sf::Rect implementation.
« Last Edit: July 21, 2012, 01:49:37 pm by natchos »

natchos

  • Jr. Member
  • **
  • Posts: 97
    • View Profile
    • Email
Re: If bug? SFML 1.6
« Reply #4 on: July 21, 2012, 02:03:22 pm »
So I jumbled the code around a bit and simplified it.

Here is how the new functions look:

        bool BoxCollision(sf::FloatRect FirstRect, sf::FloatRect SecondRect, sf::FloatRect& gap)
{
        this->RECT1 = FirstRect;
        this->RECT2 = SecondRect;
        return this->RECT1.Intersects(this->RECT2,gap);
}


bool ADVBoxCollision(sf::gEntity& player, sf::gEntity& sprite2, bool& pTop,bool& pLSide, bool& pRSide, bool& pBottom)
{
        float YVel = player.GetYVelocity();
        float HSLS = 0;
        if((YVel > -3.0f) && (YVel < 3.0f)) HSLS = 7;
        else if((YVel > -9.0f) && (YVel < 9.0f)) HSLS = 30;
        else HSLS = 50;
        /* HSLS stands for HighSpeed-LowSpeed. If the speed of one of the objects is high it is generally preferable to use a larger hitbox (to more accurately
        detect hits. However, at low speeds this results in alot of jitter as the sprites get pushed around the whole time. Therefore we modify the HSLS
        variable depending on the Velocity given to us */

        bool Firsttotheleft = false;
        bool Firsttotheright = false;
        bool Firstabove = false;
        bool Firstbelow = false;
        sf::FloatRect gap;
        sf::FloatRect FirstRect = sf::FloatRect(player.GetPosition().x - player.GetSize().x/2 - HSLS, player.GetPosition().y - player.GetSize().y/2 - HSLS,player.GetPosition().x + player.GetSize().x/2 + HSLS,player.GetPosition().y+player.GetSize().y/2+HSLS);
        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, gap))
        {
                if((FirstRect.Right - gap.GetWidth) - SecondRect.Left > 0) Firsttotheright = true;
                if((FirstRect.Left + gap.GetWidth) - SecondRect.Right > 0) Firsttotheleft = true;
                if((FirstRect.Top + gap.GetHeight) - SecondRect.Bottom > 0) Firstbelow = true;
                if((FirstRect.Bottom - gap.GetWidth) - SecondRect.Top > 0) Firsttotheright = true;
                if(Firstbelow) pBottom = true;
                if(Firstabove) pTop = true;
                if(Firsttotheright) pRSide = true;
                if(Firsttotheleft) pLSide = true;
                return true;
        }
        else return false;
}

thePyro_13

  • Full Member
  • ***
  • Posts: 156
    • View Profile
Re: If bug? SFML 1.6
« Reply #5 on: July 22, 2012, 07:55:08 am »
EDIT2: Pyro, from where did you get the GetPosition function? From what I know it is not part of the sf::Rect implementation.

You're right, It should be replaced in my code snippet with:
sf::Vector2f dir = sf::Vector2f(collider.left, collider.top) - sf::Vector2f(gap.left, gap.top);