Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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: http://i.stack.imgur.com/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: http://i.stack.imgur.com/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

share|improve this question
    
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. –  Jonathan Dickinson Dec 19 '11 at 22:39
add comment

1 Answer

up vote 2 down vote accepted

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);
share|improve this answer
    
Thanks, I hadn't even noticed. This doesn't seem to help with the strange "jumping" behaviour though. –  matio2matio Dec 19 '11 at 16:33
    
@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. –  Jesse Emond Dec 20 '11 at 0:50
    
@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 –  matio2matio Dec 20 '11 at 8:57
    
@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. –  Sam Hocevar Dec 20 '11 at 9:49
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.