Pushing outside of a tile collision.
DaGamesta

So, in my game I have a 16x16 grid and collisions via rectangles to simplify things. However, the player is not locked to a grid and therefore can have a vertical and horizontal speed. Because it's on a 16x16 grid, it's easy to move the player's x/y position so as to move outside of whatever collision the player is currently in. (with a wall, for example)

However, I can't seem to figure out how to determine, in the case of there being both a vertical and horizontal shift in position that leads to a collision, whether to shift the player vertically or horizontally to move outside of the collision.

Any ideas?

AMCerasoli

Edit... hahahaha my bad... I was going to create a new thread... Sorry.

J-Gamer

I don't know if you can generalize this, but here's an approach if he's going NW:

Check whether his upper-left corner is going to hit the bottom of the tile he's colliding with, and if he does, you can set his y coordinate to something where he doesn't collide anymore(player.y = tile.y + tile.h) and set his y speed to 0, so he won't collide with it anymore(or make him bounce, whatever). The same goes for the tiles right side, but switch y with x and h with w.

Now, to know which side he's going to hit, you can solve that with a pretty easy equation:

int x_0 = -(player.x_speed*player.y)/player.y_speed + player.x;
if(x_0 > tile.x && x_0 < tile.x + tile.w) {
//Player collides with bottom
} else {
//Player collides with right side
}

DaGamesta

Ah, yes, determining whether or not there was a horizontal or vertical collision beforehand... Personally it's easier to simply record a prevX and prevY before calculating movement and use that instead of the equation you showed. The issue with that is that it's possible to be colliding neither vertically or horizontally with an object the moment before you collide with it.

That would be the case that I'm having issues with, what to do in such cases, I mean. I'm not sure I just wanna default to being pushed horizontally or vertically out of the collision in such cases since it may look kind of strange.

J-Gamer

You might let the player bounce instead: invert the colliding speed and multiply it with a certain factor(because there will always be some energy loss in a collision)

DaGamesta

That would have the same issues, regarding whether I should be inverting horizontally or vertically, as that is how it would really bounce off of a flat surface. In other words, either vspeed *= -1 or hspeed *= -1, not both.

That, and this is an action rpg overhead adventure game, having the player bounce would be ridiculous, vspeed and hspeed was just a method of getting my point across, I don't actually assign a speed to my character, I just move him.

weapon_S

{"name":"605399","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/0\/60c90f9ec480f0cd21958995504d392a.png","w":631,"h":340,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/6\/0\/60c90f9ec480f0cd21958995504d392a"}
What is wrong with the third step in this picture ("All better now!")?

DaGamesta

The picture you show is in the case of a wall, I'm talking about determining whether the x or the y position should be appended in the case of a collision between one rectangle and another. The actual appending of the position is easy after that. At any rate, in the meantime I've just defaulted to appending the x position by default, and it doesn't seem to look as horrible as I thought, though I'd still be interested in this topic in case I made some more complicated game in the future.

J-Gamer

You need to determine which side it's going to hit. You can work that out with the technique I showed you before. If it hits the x-aligned side, you want to change the y value, else change the x value.

weapon_S

I felt really 'educational' last night. The solution showed in the picture is actually 'wrong'. I suspect you use the same solution...

J-Gamer said:

You need to determine which side it's going to hit.

Wrong.

'Right':

Treat the speed as a two dimensional vector/variable. You shouldn't 'add a value based on what kind of collision'. You should 'roll back the object on it's trajectory'; thus you always handle vertical and horizontal speed: in some cases one of them will be zero.
The proper way of thinking of the collision is actually that it could hit both the vertical and horizontal part. Calculate both collisions and use the first one to roll back. Pseudo code:

1//Time is relative to beginning of timestep i.e. not absolute; time * speed = distance traveled in this timestep. 2float ct1 = one_timestep; //first time of collision 3 4//Find minimum time of collision 5for(all horizontal){ 6 float found_horizontal_collision_time; 7 if( found_horizontal_collision_time < ct1 ) 8 ct1 = found_horizontal_collision_time 9} 10 11for(all vertical){ 12 float found_vertical_collision_time; 13 if( found_vertical_collision_time < ct1 ) 14 ct1 = found_vertical_collision_time 15} 16 17x_pos = (int) floor(x_speed * ct1); 18y_pos = (int) floor(y_speed * ct1); 19//You can also 'roll back' using negative speed... but it will get the same result.

If you want (real) bounce, you'll have to really use (simple) vector math.

Gabriel Campos

In other post reynaldo said...

"Make a rectangle class. Make a RectanglesOverlap function. Give your blocks and your player a rectangle. Use the RectanglesOverlap function. Test the future position. If it won't overlap anything, then it is safe to move there. If it will overlap something, reduce it's velocity in that direction until it would no longer overlap. Continue to check against all remaining objects.

And try not to put everything on one line."

I use this and think that is the best way to check collion in tile maps... any doubt ask..

DaGamesta

I'd like to point out that I considered that option, but it doesn't seem efficient enough.

Edgar Reynaldo

Computers can do millions of calculations per second. It'll be efficient enough for most purposes. If it actually gets to the point where it is not, you have other methods to reduce the number of checks performed.