Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411515 Posts in 69376 Topics- by 58431 Members - Latest Member: Bohdan_Zoshchenko

April 27, 2024, 03:52:29 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Move to contact problem?
Pages: [1] 2
Print
Author Topic: Move to contact problem?  (Read 3615 times)
Ben_Hurr
Level 10
*****


nom nom nom


View Profile
« on: December 19, 2009, 08:07:08 PM »

Hey TIG guys, I'm new to the forums and I was hoping someone could help me with my programming quandary.

At the moment I'm trying to work out a way to get my platform games' objects to slide along and be stopped by solid walls.
The games' walls are tilebased, and I'm using good ol' AABB rects to detect collisions.

I can't seem to find anything about doing this, but surely this problems been solved since the dawn of game programming?  Shrug
Logged
Glaiel-Gamer
Guest
« Reply #1 on: December 19, 2009, 09:27:13 PM »

I can't seem to find anything about doing this, but surely this problems been solved since the dawn of game programming?  Shrug

nope, never. Von Neumann actually proved it to be an unsolvable problem

find the first tile in the direction of the movement vector, just consecutively check tiles till one is solid, them move the block to 1 tile before that one

Logged
David Pittman
Level 2
**


MAEK GAEM


View Profile WWW
« Reply #2 on: December 19, 2009, 11:10:02 PM »

The best* solution is to do a sweep test to avoid "phasing" through geometry at high speeds. Here's some pictures!



So you've got a guy moving with some velocity, and you've got some tiles. If you move the character by this velocity (multiplied by delta time) and test for collision at the end point, you'll end up here:



The guy is not colliding with any tiles here, so the move is considered valid. But look at the actual path of the character:



The lower right corner of his bounding box clearly cuts through the tile on this path. The actual point of collision is shown here:



So how do we test for this? Subdividing the movement vector and testing for collision at smaller intervals isn't a completely terrible choice, but it can't catch every case. Then you have to find an acceptable balance between allowing some edge cases or doing a ridiculous number of tests, and that can get expensive. There's a better way.

The next image is effectively the same initial scenario as the first image I posted, but I've reduced the character to a single point and expanded the world by the guy's dimensions (making a Minkowski sum, or difference, or something, of their geometries).



Now you can just find the exact point of intersection of the movement vector with the expanded world (with ray-triangle or ray-AABB tests). That will eventually locate this point:



And conveniently, that small offset from the starting point to the point of intersection is exactly the same as the distance the guy can move before he collides with that tile; so move him that far and you're done!

*This is the best solution in my experience, anyway. But really, whatever gets the job done efficiently and without bugs is the best for any game.
« Last Edit: December 19, 2009, 11:27:53 PM by David Pittman » Logged

Ben_Hurr
Level 10
*****


nom nom nom


View Profile
« Reply #3 on: December 20, 2009, 08:45:58 AM »

The best* solution is to do a sweep test to avoid "phasing" through geometry at high speeds. Here's some pictures!



So you've got a guy moving with some velocity, and you've got some tiles. If you move the character by this velocity (multiplied by delta time) and test for collision at the end point, you'll end up here:



The guy is not colliding with any tiles here, so the move is considered valid. But look at the actual path of the character:



The lower right corner of his bounding box clearly cuts through the tile on this path. The actual point of collision is shown here:



So how do we test for this? Subdividing the movement vector and testing for collision at smaller intervals isn't a completely terrible choice, but it can't catch every case. Then you have to find an acceptable balance between allowing some edge cases or doing a ridiculous number of tests, and that can get expensive. There's a better way.

The next image is effectively the same initial scenario as the first image I posted, but I've reduced the character to a single point and expanded the world by the guy's dimensions (making a Minkowski sum, or difference, or something, of their geometries).



Now you can just find the exact point of intersection of the movement vector with the expanded world (with ray-triangle or ray-AABB tests). That will eventually locate this point:



And conveniently, that small offset from the starting point to the point of intersection is exactly the same as the distance the guy can move before he collides with that tile; so move him that far and you're done!

*This is the best solution in my experience, anyway. But really, whatever gets the job done efficiently and without bugs is the best for any game.
Ooooo, an illustrated example! <3

I can't say I've heard of the method where you shrink the player to a point before, it looks interesting!  Hoho, I'll have to see if I can implement it.
Logged
Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #4 on: December 20, 2009, 12:33:25 PM »

I'm not actually sure he was saying to shrink your character, simply to test moving intersections of points on it, for example it's corners.
Logged
powly
Level 4
****



View Profile WWW
« Reply #5 on: December 20, 2009, 12:57:20 PM »

The way David wrote it it seems he just uses the middle point of the character and works the magic on the tiles (adds character width to tile width), of course you could leave the tile boundaries like they are and check all corners.

I myself just move my objects directly, they won't go through any solid walls (maybe cut corners; not that you'd notice it with that speed) if I have some reasonable limits on their acceleration.
Logged
Ben_Hurr
Level 10
*****


nom nom nom


View Profile
« Reply #6 on: December 20, 2009, 04:40:21 PM »

"I myself just move my objects directly, they won't go through any solid walls..."
Move them directly? Do explain. Concerned

But yes, checking the corners might work as well.
Logged
kometbomb
Level 0
***


View Profile WWW
« Reply #7 on: December 21, 2009, 01:20:09 AM »

I think Super Mario etc. do this simply by moving the guy and checking if the guy rectangle is inside a wall and if so they move it left or right by the depth of the collision. I don't think it's strictly even a bug if you can move diagonally over tile corners (and you could argue a game should allow that in the name of playability).

E.g. if your tiles are 16x16 and the guy can only move at a maximum speed of less than 16 pixels (so it doesn't completely skip over a tile), you will know that if after moving the guy to the left, the rectangle is inside a tile, you need to move the guy to the right by the depth of collision. It is easy to deduce the depth since you know the tile and guy coordinates (and you don't even need the tile coordinate because you know you need to align the guy to 16 pixel tiles).



You can then do the same whenever the guy is falling but for the Y coordinate. If the guy collides, set the feet firmly on the tile under the guy and stop the falling. Now, on every frame or when the guy moves you need to check if there's something under the guy and if not, falling starts again.
Logged

bluescrn
Level 1
*


Unemployed Coder / Full-time Indie :)


View Profile WWW
« Reply #8 on: December 21, 2009, 03:07:22 AM »

I think Super Mario etc. do this simply by moving the guy and checking if the guy rectangle is inside a wall and if so they move it left or right by the depth of the collision.

If all your tiles are square, this works pretty well - to implement it, do the X and Y updates separately - this will help avoid problems when you hit the corners of a tile:

Update player X position
If we're overlapping a tile
   - Correct our X position (and set the player's X velocity to 0?)

Update player Y position
If we're overlapping a tile
   - Correct our Y position (and cancel any jump that may be in progress?)

Then you won't have the case where it's overlapping, and you don't know whether you should be correcting X, Y, or both to resolve it.

(If you want slopes, things can get rather more complex, and you may end up dealing with line segment intersections, normal vectors, etc - and your may find it easier to treat the player as a circle, or a pair of circles, rather than a box?)
« Last Edit: December 21, 2009, 03:12:03 AM by bluescrn » Logged

kometbomb
Level 0
***


View Profile WWW
« Reply #9 on: December 21, 2009, 04:17:39 AM »

do the X and Y updates separately

Yes, I didn't stress this enough. The problem becomes extremely simple when you reduce it to two easy 90-degree movements.

I don't think slopes complicate stuff very much since the slope can be thought simply as a change in the floor height according to the X coordinate. Unless you're making a Sonic clone, it's just an extra few lines of code in the "has our falling guy hit the ground" check and adding an extra movement up or down when the guy runs left or right on a slope. Very steep slopes can then be though just as a vertical wall that can't be walked on (unless you're Sonic).
Logged

Draknek
Level 6
*


"Alan Hazelden" for short


View Profile WWW
« Reply #10 on: December 21, 2009, 05:02:41 AM »

Yes, definitely do x and y movement separately.

My problem with slopes is that you need to use the x-centre to determine the height of a slope at any point, but what happens when that centre point isn't touching the ground but part of the bounding box still is? You don't want to let the player fall straight down because then he'll be overlapping the wall, but you also can't just move him magically from one position to the other.

Reusing old diagram:


I have yet to implement a good solution to this.
Logged

Tycho Brahe
Level 10
*****

λx.x


View Profile
« Reply #11 on: December 21, 2009, 06:18:54 AM »

I've started using circles a lot more in collision detection and you'll probably find that you'll want this here. You could try having a circle based collision shape, as detection and resolution for this is still relatively simple.
Logged
powly
Level 4
****



View Profile WWW
« Reply #12 on: December 21, 2009, 06:36:16 AM »

"I myself just move my objects directly, they won't go through any solid walls..."
Move them directly? Do explain. Concerned

But yes, checking the corners might work as well.

Just as others said, x and y separately, move the object along the axis -> check for collisions -> if collides, move back and set velocity to 0 (or multiply it by, say, -.7 to get a cool bounce effect if you want it)
Logged
kometbomb
Level 0
***


View Profile WWW
« Reply #13 on: December 21, 2009, 11:09:42 AM »

Yes, definitely do x and y movement separately.

My problem with slopes is that you need to use the x-centre to determine the height of a slope at any point, but what happens when that centre point isn't touching the ground but part of the bounding box still is?

Make the sideways test completely skip slopes. In any case the slopes are not sideways blocking tiles (unless falling down) because, well, they are floors and not walls.
Logged

Ben_Hurr
Level 10
*****


nom nom nom


View Profile
« Reply #14 on: December 21, 2009, 02:35:24 PM »

"I myself just move my objects directly, they won't go through any solid walls..."
Move them directly? Do explain. Concerned

But yes, checking the corners might work as well.

Just as others said, x and y separately, move the object along the axis -> check for collisions -> if collides, move back and set velocity to 0 (or multiply it by, say, -.7 to get a cool bounce effect if you want it)

The only problem I see with that is moving diagonally very fast will screw you up. :X


But that's like, if the distance you're covering in one step is bigger than an entire tile;
and that would be ridiculously fast in a 2D game anyway.
Logged
powly
Level 4
****



View Profile WWW
« Reply #15 on: December 21, 2009, 02:39:50 PM »

Well, I haven't actually done any calculations about this but my guess is I'll never move over a tenth of a tile per frame. Of course with great speeds this is a problem.
Logged
Ben_Hurr
Level 10
*****


nom nom nom


View Profile
« Reply #16 on: December 21, 2009, 03:10:30 PM »

Yeah, it'll probably be good enough for what I'm doing.
But the inaccuracy haunts me so.  Cry
Logged
kometbomb
Level 0
***


View Profile WWW
« Reply #17 on: December 21, 2009, 04:26:41 PM »

Yeah, it'll probably be good enough for what I'm doing.
But the inaccuracy haunts me so.  Cry

At least to me, it's a thrill to create something really simple to achieve something relatively complex. I would even go as far as saying a complex solution with slightly better results is a much worse solution when you think about the cost of the code (not necessarily money but amount of work, debug time, frustration).

All the best games usually got to be the best games because they faked something. Otherwise they would never have been completed. Anyone can make plans but not everyone can execute the said plans etc.

(I'm not a great programmer but I'm a certified Zen master)
Logged

powly
Level 4
****



View Profile WWW
« Reply #18 on: December 21, 2009, 04:41:25 PM »

Also a little cheaty approach is almost always a lot faster. (Euler approx. vs proper integration, anyone? Smiley )
Logged
bluescrn
Level 1
*


Unemployed Coder / Full-time Indie :)


View Profile WWW
« Reply #19 on: December 21, 2009, 04:54:06 PM »

Yeah, it'll probably be good enough for what I'm doing.
But the inaccuracy haunts me so.  Cry

If you're moving fast (more than a few pixels in one update), just subdivide the move into several steps.  Even pixel-sized steps if you want.
Logged

Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic