Question

I have a sprite class which I am working on making a function for collision. I want the function to return true if two sprites collide. When I call the function I pass the moving objects desired X and Y position along with it's height and width. The invoking sprite is the object I that I would like to check. For example if I wanted to check if player 1's move will intersect player 2's sprite I would say Player2.Collide(p1X, p1Y, p1H, p1W).

bool Sprite::Collides(int x, int y, unsigned short w, unsigned short h) const
{
    if ((x == this->GetWidth() + this->GetLeft()) && 
        (y >= this->GetTop() && y <= this->GetTop() + this->GetHeight()) || 
        ((x + w) == this->GetLeft()) && 
        (y >= this->GetTop() && y <= this->GetTop() + this->GetHeight()))
        return true;
else if ( (y == this->GetHeight() + this->GetTop()) && 
              ((x >= this->GetLeft() && x <= this->GetLeft() + this->GetWidth()) || 
              ((y + h) == this->GetTop() && (x >= this->GetLeft() && x <= this->GetLeft() + this->GetWidth()))))
        return true;
    return false;
}

The sprites are always rectangles. It seems I am forgetting to check some conditions for my collision. If the rectanges collide perfectly then everything works, however if I shift one up then try to butt against the other, it will glide right through. It seems each direction I approach has a similar behavior where it will work only for certain sections. Can you guys help me find what I'm forgetting to check?

Was it helpful?

Solution

I think you need to check the logic of your actual conditions again, shouldn't

(x == this->GetWidth() + this->GetLeft())

just that part of your if statement create a collision? right after that you have an &&. So in this case it needs to be touching on the top AND right, not just the right OR the top???

I also think the above line should really be:

(x <= this->GetWidth() + this->GetLeft())

Also, depending on your actual movement conditions (i.e. velocity, etc...) the above condition could really be

(x <= this->GetWidth() + this->GetLeft() - 1)

Lets explain the minus 1: If you have two objects, one moving directly upward, and another moving directly downward, i.e. vertically and parallel to one another, then GetWidth + GetLeft creates a "went by" each other condition not a collision condition.

Example Sprites each 4 x 4 moving VERTICALLY with respect to each other:

Sprite A @ (0, 2)          Sprite B @ (4, 2)

   0     1     2     3        0     1     2     3
-------------------------  -------------------------
|     |     |     |     |  |     |     |     |     |
-------------------------  -------------------------
|     |     |     |     |  |     |     |     |     |
-------------------------  -------------------------
|     |     |     |     |  |     |     |     |     |
-------------------------  -------------------------
|     |     |     |     |  |     |     |     |     |
-------------------------  -------------------------

Sprite A @ (0, 1)          Sprite B @ (4, 3)

   0     1     2     3   
-------------------------
|     |     |     |     |
-------------------------
|     |     |     |     |     0     1     2     3
-------------------------  -------------------------
|     |     |     |     |  |     |     |     |     |
-------------------------  -------------------------
|     |     |     |     |  |     |     |     |     |
-------------------------  -------------------------
                           |     |     |     |     |
                           -------------------------
                           |     |     |     |     |
                           -------------------------

Sprite A @ (0, 0)          Sprite B @ (4, 4)

   0     1     2     3   
-------------------------
|     |     |     |     |
-------------------------
|     |     |     |     |
-------------------------
|     |     |     |     |
-------------------------
|     |     |     |     |     0     1     2     3
-------------------------  -------------------------
                           |     |     |     |     |
                           -------------------------
                           |     |     |     |     |
                           -------------------------
                           |     |     |     |     |
                           -------------------------
                           |     |     |     |     |
                           -------------------------

When sprite a is at location (0, 0), then GetWidth + GetLeft = (0 + 4) which is RIGHT of the actual end of the sprite. IF another sprite is moving completely vertically downward with x position 4, then you algorithm would flag that as a collision, when in reality they are simply moving VERY CLOSELY by one another. This is where the - 1 comes in.

Also, you really want to make sure to be careful with your screen geometry. What I mean by this is many screens move from top-left being pixel (0, 0) to bottom right being pixel (positive X, positive y). Your second condition:

(y >= this->GetTop() && y <= this->GetTop() + this->GetHeight())

MIGHT need to be:

( (y + h - 1) >= this->GetTop() || y <= (this->GetTop() + this->GetHeight() - 1) )

The first portion needs to change because originally you were testing for the TOP of your input object colliding with the TOP of your object to be tested against. What you really want is the BOTTOM of your input to be tested with the TOP of your object to be tested against.

One thing I have always found extremely useful when trying to perform this type of coding, is to actually draw out very simple sketches with actual pixel based example numerics so that I can visualize it prior to coding it.

I hope all of this helps :-)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top