3
\$\begingroup\$

I'm having a few problems with collision detection in my game (written in C# with SDL.Net). Detecting the floor and roof is fine, as does detecting sides of tiles when not jumping/falling. My problem comes when the player jumps and hits one of the sides of a tile.

Sometimes the player (blue) enters the tile, like this: https://i.sstatic.net/SSjtR.png At first I thought this was because it was checking for a collision then moving the player then drawing, but changing it has no effect.

Other times it will randomly move from the overlapping position above to here: https://i.sstatic.net/0esSw.png

    public void PlayerCollision2 (ref Player player)
    {
        Rectangle rectLeft = new Rectangle (new Point ((int)player.x, (int)player.y), new Size (1, Player.HEIGHT));
        Rectangle rectRight = new Rectangle (new Point ((int)(player.x + Player.WIDTH), (int)player.y), new Size (1, Player.HEIGHT));
        Rectangle rectTop = new Rectangle (new Point ((int)player.x, (int)player.y), new Size (Player.WIDTH, 1));
        Rectangle rectBot = new Rectangle (new Point ((int)player.x, (int)(player.y + Player.HEIGHT + 1)), new Size (Player.WIDTH, 1));

        List<TileDirectionRelPlayer > lst = new List<TileDirectionRelPlayer> ();            
        foreach (List<Tile> r in map) {
            foreach (Tile c in r) {
                if (c.tileType == TileType.Air)
                    continue;
                TileDirectionRelPlayer t = new TileDirectionRelPlayer ();
                t.tile = c;
                if (c.rect.IntersectsWith (rectBot)) {
                    t.below = true;
                    lst.Add (t);
                } if (c.rect.IntersectsWith (rectTop)) {
                    t.above = true;
                    lst.Add (t);
                } if (c.rect.IntersectsWith (rectLeft)) {
                    t.left = true;
                    lst.Add (t);
                } if (c.rect.IntersectsWith (rectRight)) {
                    t.right = true;
                    lst.Add (t);
                }
            }
        }

        if (lst.Count == 0 && !player.jumping) {
            player.falling = true;
        } else {
            foreach (TileDirectionRelPlayer t in lst) {
                MovePlayer (ref player, t, new Rectangle[] {rectLeft, rectRight, rectTop, rectBot});
            }
        }
    }

    private void MovePlayer (ref Player player, TileDirectionRelPlayer tile, Rectangle[] rectangles)
    {
        if (tile.above && rectangles[2].IntersectsWith(new Rectangle(new Point((int)tile.tile.x,(int)tile.tile.y+Tile.HEIGHT), new Size(Tile.WIDTH,7)))) {
            player.falling = true;
            player.jumping = false;
            player.ySpeed = 0;
            player.y = tile.tile.y + Tile.HEIGHT + 1;
        }
        if (tile.left && tile.tile.y < player.y) {
            player.x = tile.tile.x + Tile.WIDTH;
        }
        if (tile.below && !player.jumping && rectangles[3].IntersectsWith(new Rectangle(new Point((int)tile.tile.x,(int)tile.tile.y), new Size(Tile.WIDTH,7)))) {
            player.y = tile.tile.y - Player.HEIGHT - 1;
            player.falling = false;
            player.ySpeed = 0;
        }
        if (tile.right && tile.tile.y < player.y) {
            player.x = tile.tile.x - Player.WIDTH - 1;
        }
    }

I have no idea why this is happening or how to fix it, can someone point me in the right direction please?

EDIT: There is a video here if it helps

\$\endgroup\$
1
  • \$\begingroup\$ Firstly, don't look at the 'current' position for collision - look at the 'next' and correct that (read up on RK4 and Verlet integration - they work with 'next') - make absolutely sure the same collision does not happen in the next frame. Secondly look into SAT to correct the collisions. \$\endgroup\$ Commented Dec 19, 2011 at 22:39

1 Answer 1

2
\$\begingroup\$

One major problem seems that you are adding t several times to lst.

            if (c.rect.IntersectsWith (rectBot)) {
                t.below = true;
                lst.Add (t);
            } if (c.rect.IntersectsWith (rectTop)) {
                t.above = true;
                lst.Add (t);
            } if (c.rect.IntersectsWith (rectLeft)) {
                t.left = true;
                lst.Add (t);
            } if (c.rect.IntersectsWith (rectRight)) {
                t.right = true;
                lst.Add (t);
            }

Try this instead:

            t.below = c.rect.IntersectsWith (rectBot);
            t.above = c.rect.IntersectsWith (rectTop);
            t.left = c.rect.IntersectsWith (rectLeft);
            t.right = c.rect.IntersectsWith (rectRight);
            if (t.below || t.above || t.left || t.right)
                lst.Add (t);
\$\endgroup\$
4
  • \$\begingroup\$ Thanks, I hadn't even noticed. This doesn't seem to help with the strange "jumping" behaviour though. \$\endgroup\$ Commented Dec 19, 2011 at 16:33
  • \$\begingroup\$ @matio2matio: If the answer solved your problem then you should mark it as an accepted answer. Just click on the green check mark below the upvote/downvote buttons of the answer. \$\endgroup\$ Commented Dec 20, 2011 at 0:50
  • \$\begingroup\$ @JesseEmond it didn't solve the question of why the player sprite was having the weird behaviour, but it seems it has put me on the right path so I will mark it as the answer anyway \$\endgroup\$ Commented Dec 20, 2011 at 8:57
  • \$\begingroup\$ @matio2matio: I do appreciate, but if this didn't solve your problem directly you should write your own answer when you can, and accept it instead of mine. \$\endgroup\$ Commented Dec 20, 2011 at 9:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .