Cyber-Wasp
Cyber-Wasp

Reputation: 49

Proper collision in SFML (C++)

So, I had a test going on to see how collision operates in SFML. I have made this snippet of code:

if (floor.getGlobalBounds().intersects(SuperMario.getGlobalBounds())) // Floor
    {
        SuperMario.setPosition(SuperMario.getPosition().x, floor.getPosition().y - SuperMario.getOrigin().y);
        IsTouching = true;
    }

As the code suggests, Mario will change his position when he touches the floor object and will teleport above the floor.

However, this has the following side-effect, illustrated by the pictures below. 2nd image

enter image description here

Note that the "green box" is the floor object I mentioned earlier. Also, ignore the word "left" in picture 1, I mean "right".

Of course, this behaviour is intended (i.e. is not a bug), but it is unwanted.

So my question is: How can I eliminate this "side-effect"? I mean, how can I modify my code, so Mario will not teleport above the floor, when he touches its sides(making platforming work like a proper platforming)? I want Mario to be stopped by the box, not to be teleported.

UPDATE: So now, I have this:

for (unsigned int i = 0; i <= solidObjects.size() - 1; i++)
    {
        if (solidObjects[i].getGlobalBounds().intersects(SuperMario.getGlobalBounds()))
        {
            if (SuperMario.getPosition().x - solidObjects[i].getPosition().x  < SuperMario.getPosition().y - solidObjects[i].getPosition().y)
            {
                SuperMario.setPosition(solidObjects[i].getPosition().x - SuperMario.getOrigin().x, SuperMario.getPosition().y);
                IsTouching = false;
            }
            else if (SuperMario.getPosition().y - solidObjects[i].getPosition().y < SuperMario.getPosition().x - solidObjects[i].getPosition().x)
            {
                SuperMario.setPosition(SuperMario.getPosition().x, solidObjects[i].getPosition().y - SuperMario.getOrigin().y);
                IsTouching = true;
            }
            else if (SuperMario.getPosition().x - solidObjects[i].getTextureRect().width < SuperMario.getPosition().y - solidObjects[i].getPosition().y)
            {
                SuperMario.setPosition(solidObjects[i].getTextureRect().width + SuperMario.getOrigin().x, SuperMario.getPosition().y);
                IsTouching = false;
            }
        }
        else
        {
            IsTouching = false;
        }
    }

However, there is one problem. When Mario touches the sides of the floor, he sticks on them meaning he is unable to move right.

If I am not clear enough, please specify what i should add or clarify more.

Upvotes: 1

Views: 946

Answers (1)

Mario
Mario

Reputation: 36567

This feels really weird, because you'd typically define solid areas rather than those the player can walk inside. You'll want your player to jump after all, rather than having them glued to the ground.

The rest is pretty straightforward:

  • Iterate over all solid objects and determine whether the player and the solid rectangle overlap.
  • If they do, determine which distance is smaller (x or y). This lets you determine which axis to move the player.
  • Determine which direction the player leaves the solid area quicker, i.e. which direction to push the player.
  • Push the player in the calculated direction and repeat the checks.

Depending on your map complexity this can become rather complex, so you'll most likely want some sorting/spatialisation to reduce the number of comparisons (e.g. skip checking impossible/far away shapes).

Upvotes: 2

Related Questions