Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Help with rectangle collision into walls while going diagonal  (Read 2441 times)

0 Members and 1 Guest are viewing this topic.

Ganado

  • Newbie
  • *
  • Posts: 34
  • Moo, I say.
    • View Profile
    • FOnline Engine, check it out.
Help with rectangle collision into walls while going diagonal
« on: December 27, 2013, 09:43:38 pm »
Hello, been a while since I've been able to use SFML for stuff, feels good to use it again, anyway:

The program I started working on yesterday basically makes 100 random rectangles that act as "rooms", creating random passages between the rooms each time the program is run. The player can navigate through these paths.

I have basic object collision set up, but my problem is determining the best way to go about letting the player move after hitting a vertical or horizontal wall.

The important code is here:
        ...
            case sf::Event::KeyPressed:
                if      (event.key.code == sf::Keyboard::W)
                    up    = true;
                else if (event.key.code == sf::Keyboard::A)
                    left  = true;
                else if (event.key.code == sf::Keyboard::S)
                    down  = true;
                else if (event.key.code == sf::Keyboard::D)
                    right = true;
                break;
 
            case sf::Event::KeyReleased:
                if      (event.key.code == sf::Keyboard::W)
                    up = false;
                else if (event.key.code == sf::Keyboard::A)
                    left = false;
                else if (event.key.code == sf::Keyboard::S)
                    down = false;
                else if (event.key.code == sf::Keyboard::D)
                    right = false;
                break;
            }
        }
 
        //////////////////
        ///  Movement  ///
        //////////////////
        last_x = player.getPosition().x;
        last_y = player.getPosition().y;
 
        if (right == true && left == false) // D
            player.move(SPEED, 0);
        else if (right == false && left == true) // A
            player.move(-SPEED, 0);
        if (up == true && down == false) // W
            player.move(0, -SPEED);
        else if (up == false && down == true) // S
            player.move(0, SPEED);
 
        for (int i = 0; i < NUM_ROOMS; i++)
        {
            if (player.getGlobalBounds().intersects(rooms[i].rectangle.getGlobalBounds()))
            {
                player.setPosition(last_x, last_y);
                break;
            }
        }
    ...


The problem I have right now is that if the player uses keys to go diagonal (ex:, the W+D keys, WASD keys) while against a vertical wall, it prevents the player from moving up/down. Same situation with horizontal walls, it prevents the player from moving left/right while pressing (S+D) or (A+S). The method I'm currently using it keeps track of the last position of the player before hitting the wall, and if it collides, the player goes back to the position it was at before.

Most other basic games I've played allow the player to still move even if they are technically going diagonal while against a wall; it simply makes the player go down instead. I hope that makes sense, please tell me if it doesn't.

Here is a link to the program I made:
http://www.sendspace.com/file/od07v5
If you don't trust opening that file, please feel free to compile the code yourself:
http://pastebin.com/fK0QePp7

You are the red square. Uses WASD keys by default to move.

If you play it and try to move diagonally inward to a wall, you'll see you can't move at all. I would appreiciate it very much if someone could guide me on how to fix this.

EDIT:
I got it to work as I wanted it to by splitting it into two For loops between x and y movement, although I doubt this is the most efficient method, probably quite inefficient, but "it works".
        last_x = player.getPosition().x;
        last_y = player.getPosition().y;

        if (right == true && left == false) // D
            player.move(SPEED, 0); //make it an elapsed time "time-step"?
        else if (right == false && left == true) // A
            player.move(-SPEED, 0);

        for (int i = 0; i < NUM_ROOMS; i++)
        {
            if (player.getGlobalBounds().intersects(rooms[i].rectangle.getGlobalBounds()))
            {
                player.setPosition(last_x, player.getPosition().y);
                break;
            }
        }

        if (up == true && down == false) // W
                player.move(0, -SPEED);
        else if (up == false && down == true) // S
                player.move(0, SPEED);

        for (int i = 0; i < NUM_ROOMS; i++)
        {
            if (player.getGlobalBounds().intersects(rooms[i].rectangle.getGlobalBounds()))
            {
                player.setPosition(player.getPosition().x, last_y);
                break;
            }
        }

So, I guess this is solved as far as I can tell, but if you have a suggestion as to a better way to let you "slide" against the wall while going diagonal (or movement in general), please reply!
« Last Edit: December 28, 2013, 05:12:00 am by Ganado »

fallahn

  • Hero Member
  • *****
  • Posts: 505
  • Buns.
    • View Profile
    • Trederia
Re: Help with rectangle collision into walls while going diagonal
« Reply #1 on: December 29, 2013, 11:25:53 am »
Usually it's sufficient to find the normal vector (that is a vector of length one, perpendicular to the surface) of the collision, then reflect your velocity vector about it. This should be quite easy with AABB as all of the collision faces are at 90 degrees to each other.



For instance if your player was moving along vector V and collides with the grey line, then you would take vector N as your normal and reflect V about it, returning R. Moving the player by R will move him/her out of the collision, but also along the wall.

Google will help you find a function for calculating the reflection, although it's not too hard to work out with pen and paper :) Cases where you need to obtain the normal vector for edges which aren't square are a bit more complicated, but there are plenty of interesting articles about it such as this one.