Xyro
Xyro

Reputation: 227

Collisions detection bugged

I got this problem that whenever I touch the ground my speed is set to 0. It happens because my function that pushes me out pushes me precisely to the edge. So when I then divide by the height of the block it still thinks i'm on that block. This also happens when I jump against the right most wall.

example : there is a block on coordinates 0,720 and my y = 723

723 / 5 = 144(rounded down)

then I get pushed out to 720. but then when I then divide by the block height it still thinks i'm touching the block thats on 720 till lets say 725

720 / 5 = 144

How can I fix this, I mean I know what the problem is but I can't see any way to fix it.

Also when I am not jumping and precisely at the right edge of the level I can go through the wall by walking to the right, but as soon as I jump the collisions detection jumps in.

I have no idea why and how this last problem is occurring could anyone take a look and see what happens.

Code :

void DoCollisions()
{
    onGround = false;
    Position.Y += Velocity.Y;
    Vector2 tileCollision = GetTileCollision();
    if (tileCollision.X != -1 || tileCollision.Y != -1)
    {
        onGround = true;
        Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
            new Rectangle(
                tileCollision.X * World.tileEngine.TileWidth,
                tileCollision.Y * World.tileEngine.TileHeight,
                World.tileEngine.TileWidth,
                World.tileEngine.TileHeight
            )
        );
        Velocity.Y = 0;
        Position.Y += collisionDepth.Y;

    }

    Position.X += Velocity.X;
    tileCollision = GetTileCollision();
    if (tileCollision.X != -1 || tileCollision.Y != -1)
    {
        Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
            new Rectangle(
                tileCollision.X * World.tileEngine.TileWidth,
                tileCollision.Y * World.tileEngine.TileHeight,
                World.tileEngine.TileWidth,
                World.tileEngine.TileHeight
            )
        );
        Velocity.X = 0;
        Position.X += collisionDepth.X;

    }
}

Vector2 GetTileCollision()
{
    int topLeftTileX = (int)(CollisionRectangle.TopLeft.X / World.tileEngine.TileWidth);
    int topLeftTileY = (int)(CollisionRectangle.TopLeft.Y / World.tileEngine.TileHeight);
    int BottomRightTileX = (int)(CollisionRectangle.DownRight.X / World.tileEngine.TileWidth);
    int BottomRightTileY = (int)(CollisionRectangle.DownRight.Y / World.tileEngine.TileHeight);

    for (int i = topLeftTileX; i <= BottomRightTileX; i++)
    {
        for (int j = topLeftTileY; j <= BottomRightTileY; j++)
        {
            if (World.tileEngine.TileIsSolid(i, j))
            {
                return new Vector2(i,j);
            }
        }
    }

    return new Vector2(-1,-1);
}

Upvotes: 2

Views: 191

Answers (3)

Xyro
Xyro

Reputation: 227

For anyone coping with the same problem as me I managed to fix it and thought a pastebin link with my code would be handy : http://pastebin.com/t8PdtDEK

Added this to my code :

        if (previousPos.X == Position.X)
            Velocity.X = 0;
        if (previousPos.Y == Position.Y)
            Velocity.Y = 0;

and added this to my get collision method :

        if (CollisionRectangle.DownRight.Y % World.tileEngine.TileHeight == 0)
            BottomRightTileY -= 1;
        if (CollisionRectangle.DownRight.X % World.tileEngine.TileWidth == 0)
            BottomRightTileX -= 1;

What it does is if its precisely on the edge subtract 1 so it doesn't add that tile.

Also the link on pastebin doesn't contain the interpolation to make sure that the object isn't moving to fast.

Thanks for all the help everyone !

Upvotes: 0

Gareth Rees
Gareth Rees

Reputation: 65854

Your implementation strategy of move all the way, then eject if colliding is pretty much guaranteed to be buggy, because there's no easy way to ensure that the ejection code ejects you back to the point where you should have collided. Often it ejects in some other direction, hence bugs.

It's not just you: professionals encounter this problem too. See tasvideos.org for a collection of collision bugs in the Super Mario Bros games that are caused by this move-then-eject strategy.

So, don't do that. Work out the exact point of collision and move only as far as that. Computers are plenty fast enough these days.


You asked for a recommended method for colliding a character with tiles. Well, start by considering a single step of motion of your character, say (dx, dy):

alt text

I've exaggerated the distance to make the example interesting: normally you'd expect the motion steps to be fairly small compared with the tile size.

The character potentially touches all the tiles that intersect the swept path of the character's hit box, shown shaded below. Use an approach along the lines of Wu's line algorithm to find these tiles.

alt text

Sort the tiles into order by when they are hit:

alt text

The character collides with the lowest-numbered tile that's solid.

Upvotes: 4

Emond
Emond

Reputation: 50672

Have you tried to use an adjusted y coordinate? Move one up for the calculation only.

Upvotes: 0

Related Questions