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

Author Topic: Swept AABB collision  (Read 2120 times)

0 Members and 1 Guest are viewing this topic.

Dinipants

  • Newbie
  • *
  • Posts: 16
    • View Profile
Swept AABB collision
« on: May 20, 2017, 03:49:18 am »
I'm making a platformer and trying to implement swept AABB collision so that an entity's velocity doesn't cause it to skip over something it should collide with from one frame to the next. I'm using this tutorial: https://www.gamedev.net/resources/_/technical/game-programming/swept-aabb-collision-detection-and-response-r3084

I've modified the code from that for SFML usage. It works in the vertical axis, but it doesn't in the horizontal axis. It just doesn't trigger a collision (it doesn't return a value between 0 and 1, which is how a collision is indicated). The code for the function is like so:
float sweptAABB(Character* character, sf::Sprite* world, float& normalx, float& normaly) {
            float xInvEntry, yInvEntry;
            float xInvExit, yInvExit;
                sf::FloatRect worldBox = world->getGlobalBounds();
                sf::FloatRect charBox = character->getSprite()->getGlobalBounds();

            // find the distance between the objects on the near and far sides for both x and y
            if (character->getXVelocity() > 0.0f) {
                xInvEntry = worldBox.left - (charBox.left + charBox.width);
                xInvExit = (worldBox.left + worldBox.width) - charBox.left;
            }
            else {
                xInvEntry = (worldBox.left + worldBox.width) - charBox.left;
                xInvExit = worldBox.left - (charBox.left + charBox.width);
            }
            if (character->getYVelocity() > 0.0f) {
                yInvEntry = worldBox.top - (charBox.top + charBox.height);
                yInvExit = (worldBox.top + worldBox.height) - charBox.top;
            }
            else {
                yInvEntry = (worldBox.top + worldBox.height) - charBox.top;
                yInvExit = worldBox.top - (charBox.top + charBox.height);
            }

            // find time of collision and time of leaving for each axis (if statement is to prevent divide by zero)
            float xEntry, yEntry;
            float xExit, yExit;

            if (character->getXVelocity() == 0.0f) {
                xEntry = -std::numeric_limits<float>::infinity();
                xExit = std::numeric_limits<float>::infinity();
            }
            else  {
                xEntry = xInvEntry / character->getXVelocity();
                xExit = xInvExit / character->getXVelocity();
            }

            if (character->getYVelocity() == 0.0f) {
                yEntry = -std::numeric_limits<float>::infinity();
                yExit = std::numeric_limits<float>::infinity();
            }
            else {
                yEntry = yInvEntry / character->getYVelocity();
                yExit = yInvExit / character->getYVelocity();
            }

            // find the earliest/latest times of collision
            float entryTime = std::max(xEntry, yEntry);
            float exitTime = std::min(xExit, yExit);

            // if there was no collision
            if (entryTime > exitTime || (xEntry < 0.0f && yEntry < 0.0f) || xEntry > 1.0f || yEntry > 1.0f) {
                normalx = 0.0f;
                normaly = 0.0f;
                return 1.0f;
            }
            // if there was a collision
            else{
                // calculate normal of collided surface
                if (xEntry > yEntry) {
                    if (xInvEntry < 0.0f) {
                        normalx = 1.0f;
                        normaly = 0.0f;
                    }
                        else {
                        normalx = -1.0f;
                        normaly = 0.0f;
                    }
                }
                else {
                    if (yInvEntry < 0.0f) {
                        normalx = 0.0f;
                        normaly = 1.0f;
                    }
                        else {
                        normalx = 0.0f;
                                normaly = -1.0f;
                    }
                }

                // return the time of collision
                return entryTime;
            }
        }
 

Originally it was detecting collision on the horizontal axis, but it was doing so even when there was no collision on the y axis (i.e. the block could be well above the character and it would still stop it as if it was in front of the character) but after implementing the broadphase check (in that article tutorial I linked) that fixed that problem, but now it doesn't detect horizontal collision at all.

Been tinkering for past few days and can't figure out why this is  :( if needed I can post code from other sections but I get the feeling that this function is the one not working as it triggers in y axis but not x axis. Any insight would be greatly appreciated!