Page 1 of 1

Edit

Posted: Fri Oct 14, 2011 12:15 pm
by SideQz
Edit

Re: Detecting collision: tiles + pixels

Posted: Fri Oct 14, 2011 4:11 pm
by kelocube
Hello and welcome (not exactly my thing to say hello as I'm a newb myself... but w/e)

First of all, having even a simple Vector class will save you a ton of trouble when working with coordinate systems of any any dimensions.
If (as I understand) you're trying to check if a sprite's pixels hit the pixels of a tilemap, it's not very efficient to go trough the whole tilemap tile by tile even when modern systems might be able to handle that np. Also when you start adding simple physics to the character, pixel collision might become quite complicated; I'd suggest sticking with the bounding box. If you want to do it this way though you'll want to get the 4 tiles (assuming your hero is no larger than a tile of the tilemap) that are hitting the hero's bounding box and then comparing their pixels with the ones of your hero's.

-->
Vector2 topLeftCorner = hero->GetPosition() / 32; // Don't use floats here... only integers
Vector2 pixelOffset = hero->GetPosition() % 32; // This represents the topLeft pixel of the hero in relation to the topLeft tile of the hero... so if the hero is exactly in the center of 4 tiles this will become (16, 16).


Sorry I have no time for an example but you can always try to visualize a situation with a pen and a piece of paper. Try drawing your hero on squared paper and imagine each square being a tile of the tilemap.

Edit

Posted: Fri Oct 14, 2011 8:09 pm
by SideQz
Edit

Re: Detecting collision: tiles + pixels

Posted: Fri Oct 14, 2011 9:21 pm
by XianForce
First off, I only read through the topic post, and after skimming the rest, it didn't seem like your question was answered. Anyways, when dealing with a tile map with pixel based movement, you should have a sort of collision layer. At the very bare minimum, I'd say you should have a container of rectangles which describe what in the map is collidable. Then you would simply loop through the map and test those rectangles against any of your moving entities in the vicinity.

Hope that helps.

Re: Detecting collision: tiles + pixels

Posted: Sat Oct 15, 2011 3:03 am
by kelocube
Ah... so you're having problems testing collision of your sprites against the tilemap?
What I was trying to say was that it's totally innecessary to loop trough each and every tile in the tilemap when doing collision for a sprite: instead just get the top left corner of the sprite:

Vector2 topLeft = floor(hero->GetPosition() / 32.0f);

And then the bottom right corner of your hero, in tiles:

Vector2 bottomRight = floor((hero->GetPosition() + hero->GetSize()) / 32.0f);

So you end up with a tile-based bounding box for the sprite.
And of course if you have 1 unit of movement defined as 1 tile, not 1 pixel, just leave out the /32.0f (but remember to include the floor()).

Then you just loop trough these tiles defined by the top left - top right tile bounding box:

Code: Select all

for (int tileY = topLeft.y; tileY <= bottomRight.y; tiley++)
    for (int tileX = topLeft.x; tileX <= bottomRight.x; tilex++)
        // You could have a collision layer consisting of booleans, but for simplicity, let's say you want to collide with every other tile than 0:
        if (map[y][x] != 0)
            // Then just compare the tile and the sprite as you would with a sprite and a sprite:
            // Assuming 'Collides' is your collision-testing function that takes the positions and sizes of both sprites and returns a bool indicating whether or not there is a collision
            if (Collides(hero->GetPosition(), hero->GetSize(), Vector2(tileX * 32, tileY * 32), Vector2(32, 32))) // Again, change 32 to 1 if needed
                return true; // Return true if a collision was found

return false; // Or finally false once all tiles are looped but the function hasn't yet returned.
I have no idea if this will help you but I certainly hope so. :)

Edit

Posted: Wed Oct 19, 2011 12:43 pm
by SideQz
Edit

Re: Detecting collision: tiles + pixels

Posted: Wed Oct 19, 2011 3:39 pm
by superLED
SideQz wrote:I have no way of determining which side is colliding, so that is quite a big problem.
is that needed? Find out which way is the shortest way out of the object, and go that way.

Image

There may be a better way of doing this. This is something I figured out by my self, while making the "Sprinkling Blood" game.
I had monsters moving in random directions, and had no track of which direction they were moving. So I had to use a different method than I had been using.
And this one was the solution.

Edit

Posted: Wed Oct 19, 2011 7:16 pm
by SideQz
Edit

Re: Detecting collision: tiles + pixels

Posted: Thu Oct 20, 2011 5:31 am
by superLED
Let's say we are checking the blue square's collision.

When you have found an object that collides with the blue square, you shall work with the bounding boxes (as seen on the image. One is blue, one is green).
Then, make an "imaginary" square, which is the part where the objects are colliding (as seen on the image. The square that's made by the two objects colliding).
Use some math to find out the length of the width and height of this square.

If the width is, let's say, 10 pixels, and the height is 5 pixels, you know the shortest way out of the object is in a vertical direction.
Then, use the center point of each object to find out if the blue square is abow or below the green square. If the blue square is higher than the green, you know you shall move it up, and not down.
So just move the blue's Y position to "greenSquare.Y - blueSquare.Height"

--

An other way of doing this, is to always track the objects previous position. If there's a collision, just move back to the previous position.
But the downside of this is, if an object suddenly spawns in the middle of an object, and it is the object's first position, there is no previous position.
That's why I use the first solution. Because no matter where the object is coming from, or when it arrives to that point, it will always move the shortest way out (which seems logical).

Edit

Posted: Thu Oct 20, 2011 10:45 am
by SideQz
Edit

Re: Detecting collision: tiles + pixels

Posted: Thu Oct 20, 2011 11:19 am
by szdarkhack
First of all, no need to despair. Take a break for a couple of days, let your mind rest from working on it and then get back to it. Sometimes a fresh perspective get's you a long way.

Second, i don't see why you're having that much trouble with it, given that you already have working code for sprite collisions. Why don't you just use the same code? What i mean is, just like your sprites have bounding boxes, your tiles can have them too. In my experience, unless you really know what you're doing, there's no need to write new code for something when you already have it working. Collision is collision, regardless of whether it's a tile or a sprite you're talking about. If you make sure that the code that handles it is not sprite-specific (for example, by just passing rectangles as arguments, not sprites) then you can reuse it quite easily. The only reason you should rewrite code is if you can somehow substantially optimize it for a special case, or if you want a different technique for each case.

As a separate note, pixel perfect collision is quite tricky. Your character could easily get "stuck" when colliding with a diagonal edge. If your bounding box is sized correctly, simple rectangle collision works just as fine or better (for character control) and is much simpler to implement too (which, if i understand correctly, you have already achieved between sprites).

I hope this helps :) Again, if you get frustrated, take a breather and come back to the problem a bit later with a clear head.

Edit

Posted: Thu Oct 20, 2011 11:42 am
by SideQz
Edit

Re: Detecting collision: tiles + pixels

Posted: Fri Oct 21, 2011 9:36 am
by Falco Girgis
superLED wrote:
SideQz wrote:I have no way of determining which side is colliding, so that is quite a big problem.
is that needed? Find out which way is the shortest way out of the object, and go that way.

Image

There may be a better way of doing this. This is something I figured out by my self, while making the "Sprinkling Blood" game.
I had monsters moving in random directions, and had no track of which direction they were moving. So I had to use a different method than I had been using.
And this one was the solution.
That "short" segment is your separating axis. You're essentially doing the SAT with AABBs with that method. It's a very good way of handling that.

Do that with OBBs, and you've implemented the full separating axis theorem.

Re: Detecting collision: tiles + pixels

Posted: Fri Oct 28, 2011 5:31 am
by Van-B
One method I often use, is to pass an X and Y coordinate and a radius, then do a check on 4 corners against the map array. So stepping through 45, 135, 225, and 315 angles at the specified radius, each time checking that location against the map array. Sliding collision is easy to implement with a function like that.

I wouldn't advise using pixel collision though, it leads to so many potential bugs and is slow. Perhaps using something like Box2D for collision would be better, polygon shapes stored in an array, then cross reference your tile to a shape. I guess it depends how complex or square your map has to be.

Re: Detecting collision: tiles + pixels

Posted: Mon Nov 21, 2011 9:54 pm
by Nasus
Here's a way to check for collision.
Using this function you are able to create a "collision box" for the player's x and y by setting it's position (x and y) and the collision box's width and height (width and height).
Notice how each if statement is a collision check for each side of our "box".

Code: Select all

void placeCollisionBox(int x, int y, int width, int height){
	     if( playerX >= x &&
            playerX <= x + width &&
            playerY >= y &&
            playerY <= y + height){
            setPreviousLocation(); /*Or any other function you'd like to trigger when the player is colliding*/
        }

        if( playerX + playerWidth >= x &&
            playerX <= x + width &&
            playerY >= y &&
            playerY <= y + height){
            setPreviousLocation();
        }

        if( playerY + playerHeight >= y &&
            playerY <= y + height &&
            playerX >= x &&
            playerX <= x + width){
            setPreviousLocation();
        }

        if( playerY + playerHeight >= y &&
            playerY <= y + height &&
            playerX + playerWidth >= x &&
            playerX <= x + width){
            setPreviousLocation();
        }

        if( playerX + playerWidth >= x &&
            playerX <= x + width &&
            playerY + playerHeight >= y &&
            playerY <= y + height){
            setPreviousLocation();
        }
}