1
\$\begingroup\$

I am trying to set up the collision detection on a basic 2d game, player clicks a button sprite moves one step int he corresponding direction.

Currently all my sprites have the collision rectange member:

public Rectangle collisionRect
    {
        get
        {
            return new Rectangle(
                (int)position.X + collisionOffset,
                (int)position.Y + collisionOffset,
                frameSize.X - (collisionOffset * 2),
                frameSize.Y - (collisionOffset * 2));
        }//end get
    }//end collisionRect get

this works quite well when I try to check to see if the rectangles for 2 sprites overlap

 public Vector2 CheckCollision()
    {
        for (int i = 0; i < levelWalls.Count; ++i)
        {
            Sprite wall = levelWalls[i];
            //check for collisions
            if (wall.collisionRect.Intersects(player.collisionRect))
            {
                //remove collided sprite
                levelWalls.RemoveAt(i);
                --i; 
            }
        }
    }

however I am running into trouble in the part where I check to see if the player's sprite will run into a wall and stopping it. I know I should be doing something like calculating the players next position and seeing if that position collides with any walls and if it does setting it back to an old position, that seems to be a theory that works in my head, however I am having trouble keeping track of Old Position, Current Position and New Position.

Currently I have my player position updating in it's Update() method:

position += direction;

I then am trying to keep track of old, current and new positions in direction:

public override Vector2 direction
    {
        get
        {
            Vector2 inputDirection = Vector2.Zero;

            keyboardState = Keyboard.GetState();
            if (keyboardState.IsKeyDown(Keys.Left) && prevKeyboardState.IsKeyUp(Keys.Left))
                inputDirection.X -= frameSize.X;
            if (keyboardState.IsKeyDown(Keys.Right) && prevKeyboardState.IsKeyUp(Keys.Right))
                inputDirection.X += frameSize.X;
            if (keyboardState.IsKeyDown(Keys.Up) && prevKeyboardState.IsKeyUp(Keys.Up))
                inputDirection.Y -= frameSize.Y;
            if (keyboardState.IsKeyDown(Keys.Down) && prevKeyboardState.IsKeyUp(Keys.Down))
                inputDirection.Y += frameSize.Y;
            prevKeyboardState = keyboardState;
            oldPOS = position;
            newPOS = position + inputDirection;
            return inputDirection;
        }//end get        
    } //end Direction

My problem is all three: position, OldPOS and NewPOS are always exactly the same. How can I do this better?

EDIT: with some help I have worked it down to an issue now with my "collision detection" function

public Vector2 CheckCollision(Vector2 oldPOS, Vector2 newPOS)
    {
        bool collided = false;

        for (int i = 0; i < levelWalls.Count; ++i)
        {
            Sprite wall = levelWalls[i];
            //check for collisions
            if (wall.collisionRect.Intersects(player.collisionRect))
            {
                //remove collided sprite
                levelWalls.RemoveAt(i);
                --i;
                collided = true;
                playerPOS = oldPOS;
                break;
            }
        }
        if (!collided)
            playerPOS = newPOS;
        return playerPOS;
    }

it always execute the if(!collided) to set the position to the new position, even if i do collide and it removes a wall it never sets my position to the old position.

If I however make (!collided) return the old position I can tell my theory works as my sprite will not move at all.. . .

EDIT: AND SOLVED! I needed to create a new colision rectangle for the spot where the sprite will move to, I was using the collision rectangle for where the sprite is! here are the changes:

 public Vector2 CheckCollision(Vector2 oldPOS, Vector2 newPOS)
    {
        Rectangle playerCollisionRect = new Rectangle((int)newPOS.X, (int)newPOS.Y, spriteSize.X, spriteSize.Y);

        bool collided = false;
        for (int i = 0; i < levelWalls.Count; ++i)
        {

            Sprite wall = levelWalls[i];
            //check for collisions
            if (wall.collisionRect.Intersects(playerCollisionRect))
            {
                collided = true;
                playerPOS = oldPOS;
                break;
            }
        }
        if (!collided)
            playerPOS = newPOS;

        return playerPOS;
    }
\$\endgroup\$
4
  • \$\begingroup\$ I just asked a question regarding the same type of collision but different context - check out my code to see if it helps you at all. It was for a quick prototype so the code could use some refactoring but the concepts are there. gamedev.stackexchange.com/questions/23173/… \$\endgroup\$ Feb 1, 2012 at 16:18
  • \$\begingroup\$ Thanks for the link. I am trying to do exactly the same thing, except I don't care about the diagonal movement. My problem is I am having a hard time keeping track of the old location of my sprite. No matter how I work it it seems to always equal the current location and rectangle. \$\endgroup\$
    – sec_goat
    Feb 1, 2012 at 17:27
  • \$\begingroup\$ You should answer your question and accept the answer if you solved it yourself. \$\endgroup\$ Feb 2, 2012 at 11:29
  • \$\begingroup\$ I would love to but I either lack the knowledge or the reputation to do so. . . maybe a combination of both? Oh wait, there it is! \$\endgroup\$
    – sec_goat
    Feb 2, 2012 at 14:57

1 Answer 1

0
\$\begingroup\$

The problem I was facing was not with the position of the player nor the variables to keep track of positions. It however was a problem in my check collision function

public Vector2 CheckCollision(Vector2 oldPOS, Vector2 newPOS)
{
    bool collided = false;

    for (int i = 0; i < levelWalls.Count; ++i)
    {
        Sprite wall = levelWalls[i];
        //check for collisions
        if (wall.collisionRect.Intersects(player.collisionRect))
        {
            //remove collided sprite
            levelWalls.RemoveAt(i);
            --i;
            collided = true;
            playerPOS = oldPOS;
            break;
        }
    }
    if (!collided)
        playerPOS = newPOS;
    return playerPOS;
}

I was taking a bounding box rectangle for each wall and checking it against the player's sprite bounding box as seen here:

    if (wall.collisionRect.Intersects(player.collisionRect))

However what I needed to do was create a new bounding box based on what would be the player's new position and test that for collision before allowing the move:

public Vector2 CheckCollision(Vector2 oldPOS, Vector2 newPOS)
{
    Rectangle playerCollisionRect = new Rectangle((int)newPOS.X, (int)newPOS.Y, spriteSize.X, spriteSize.Y);

    bool collided = false;
    for (int i = 0; i < levelWalls.Count; ++i)
    {

        Sprite wall = levelWalls[i];
        //check for collisions
        if (wall.collisionRect.Intersects(playerCollisionRect))
        {
            collided = true;
            playerPOS = oldPOS;
            break;
        }
    }
    if (!collided)
        playerPOS = newPOS;

    return playerPOS;
}

I hope that this helps some one else in their endeavors to begin with game programming!

\$\endgroup\$

You must log in to answer this question.

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