Tilemap Collision SFML C++

2019-07-24 10:54发布

问题:

I've spent many frustrating hours and cannot figure this out, i understand collision and have it working until i try to implement gravity, i cant seem to set the player position after it hits the tile map, falling through the ground is my problem, x axis a variation of the following code works fine

if (background.colMap[tiles[i].y][tiles[i].x] == 1)
    {
        playerSpeed.y = -0.f;
        playerSprite.setPosition(playerSprite.getPosition().x, playerSprite.getPosition().y - 1);
        inAir = false;
    }

I though by reducing the speed to 0 and bumping the player back 1 pixel would work, but all it does is the player sprite bounces up and down

回答1:

Given the above information, I assume you're making a side-scrolling game, and your character is colliding with the top of a tile.

That said, the first thing you need to understand is that you're not supposed to adjust the position of the character after it moved but before it moved. The character is never supposed to be in a position that is "illegal" in your game. Even for a fraction of a second.

You have the power to see the future (at least in your own game), use it at will! Always be one step ahead.

How to find the right place?

Basic algebra!

Here's the situation.

The goal here is to find where the green and red dotted line cross the small blue dotted line (which represent the ground).

First, we need to find the equation of our character (black dot) trajectory, which should looks like: y = ax + b.

Where the slope a = (Y2 - Y1)/(X2 - X1) and b = y - ax.

In our example case, the equation is y = -2x + 10. We just need to know what is the value of X when Y = 3, which we can find with x = (y - b) / a and in our case, x = (3 - 10) / (-2) = 3.5.

So we now know that our character will be intersecting with the floor at (3.5, 3) and that's where we will put the character.

Flaws of your current technique

When you collide, you put the character up 1 pixel if I understand correctly your code.

Imagine that your character is going really fast and in one update of his position, he gets from a valid position to an invalid one, 25 pixels below the ground. With your current technique, it will take at least 25 position updates to get back on the ground or maybe just 25 collision detection loops, but still, it's not very efficient.

Another thing, you seem to be looping every possible tiles in the level, so that's probably mostly empty tiles and/or full ground (inaccessible) tiles, which is a big overhead on what you really need.

The best option would be to store the coordinates of collidable tiles and just iterate those tiles.

If you have a screen of, let's say 50 x 50 tiles, and there are only 25 collidable tiles, you're still checking 50 * 50 - 25 = 2475 tiles, and these are 2475 unnecessary checks. But obviously, that's not the reason why you are having trouble, even those 2475 unnecessary checks won't break the logic.

And just to play with the numbers, since our character is 25 pixels below, we'll loop 25 times 2500 tiles, which is 62500 checks, instead of 25 * 25 = 625 with a collidable tile collection, or just 25 checks with the math stuff.