• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Sloped Tiles using Polygons

badwrong

Member
Project file: https://github.com/badwrongg/gms2stuff/raw/master/sloped_tile_polygon_collision.yyz

Edit2: Added capsule colliders. Probably the best option for platformers with smooth sloped movement.

Edit: Added rotation


I was curious about making a sloped collision system using tilemaps, since they are certainly faster than using objects.
So I came up with the solution of procedurally creating polygons for each tile shape an assigning a translated version of each
polygon to a grid that matches the tilemap.

Been working on it a few days now and here is the result so far:


It supports any convex ngon as a tileshape. And the collision mask of the object colliding with it has its own polygon assigned as well.
That assigned polygon can also be any ngon too, so like a pentagon or hexagon collision mask for the player would work if that's your thing lol.

Anyway, its almost done. I'm still fiddling with how the collision response works. But the core solution is solid and performs very fast.
When I saw how other tile based slope collisions are done I saw that they usually avoid using math at the cost of performance. So this
solution instead uses some good old math in order to not sacrifice performance.

The tile collision check is still just like the standard tile collision check, but then it resolves the collision differently. Currently it has two methods that
can be switched between. One is the separate axis theorem, which is fairly common I think. The other is diagonals of each polygon against edges of the other,
and then vice versa. Still fiddling with which one I prefer I guess.
 
Last edited:

HalRiyami

Member
I was recently thinking about how I could do this exactly same thing! I'm really interested in your methodology.
Do you have any fps comparisons between plain tile based collisions and your method?
 

badwrong

Member
I was recently thinking about how I could do this exactly same thing! I'm really interested in your methodology.
Do you have any fps comparisons between plain tile based collisions and your method?
Well plain tile based are going to be insanely fast if you aren't trying to add slopes. In this same project if I toggle on just normal square based tile collisions that use the standard tile alignment code (bbox_value &~ tile_size_minus_1...) it takes about 200+ objects until it dips below 1000 fps.

If I toggle on my tile slope collisions, about 100 objects that are actively performing collisions and it's about 300 fps. I say actively, since an object touching empty tiles require no checks other than checking they are on empty tiles. Which of course is why tile based collision is so fast. This is still a tile based solution, just the resolution is polygon based. And having it polygon based is much faster than the common methods I've seen with precise collision masks and weird "while loops" for resolution.

I'm not a fan of while loops for collision. But I get that people like them cause they are simple to code. But at the very least I think people who want to use while loops should do binary sweeps instead of pixel by pixel. So if X moves 10, then check 10 ahead for a collision, if there is one, check 5, then 2.5 then 1.25 then etc. and "break" below 1 and floor the value. Even something that simple reduces collision checks by a considerable amount.
 

HalRiyami

Member
I wasn't expecting it to match plain tile based collision but that's still pretty good result in my opinion. I too am not a fan of the while loop solutions so I simply use tile checks.
What's your plan for this once you finish working on it?
 

badwrong

Member
I wasn't expecting it to match plain tile based collision but that's still pretty good result in my opinion. I too am not a fan of the while loop solutions so I simply use tile checks.
What's your plan for this once you finish working on it?
Well the lookup part matches tile based collision. But checking if the object overlaps the tile polygon is of course a lot more calculations than normal tiles. Maybe I worded that wrong before. This is still very fast when compared to the common methods I've seen for slopes.

Plan for this? Well I was mostly doing it as a problem solving exercise after seeing the common ways that tutorials deal with sloped collisions, and for the most part I think those ways are pretty bad. Only pro is they are less code.

Other than obvious stuff like a Rayman style platformer, I have a few ideas for using this. Raycasting light would be a great use for this, since it would be trivial to merge tile vertexes into larger meshes and then use those for the raycasting to calculate where light and shadow go. Since it would retain the tile based lookup, the amount of rays needed would be drastically reduced and each one would be very fast I think.
 

HalRiyami

Member
Sorry, I wasn't clear. By plan, I meant, do you intend to sell the code in the market place, share it, make a tutorial, or something else? Like I said, I'm interested in how you did it and would love to adopt a similar method for my slope collisions but I haven't yet started looking into it.

Do you create the polygons at the start of the room or on collision? From your first post, it sounds like you do at room start.
While I'm not sure how long it takes to create a polygon based on the tile and assign it to the correct grid I'd imagine that you could cut down on the initial setup if you were to only create a polygon when a collision is detected, though that might make the collision resolution slower. Just a thought :).
 

badwrong

Member
Sorry, I wasn't clear. By plan, I meant, do you intend to sell the code in the market place, share it, make a tutorial, or something else? Like I said, I'm interested in how you did it and would love to adopt a similar method for my slope collisions but I haven't yet started looking into it.

Do you create the polygons at the start of the room or on collision? From your first post, it sounds like you do at room start.
While I'm not sure how long it takes to create a polygon based on the tile and assign it to the correct grid I'd imagine that you could cut down on the initial setup if you were to only create a polygon when a collision is detected, though that might make the collision resolution slower. Just a thought :).
Ah, the polygons are created on room start.
There is a room where an object using the tilemap sprite has some vertex objects placed on it. It then creates a "key" list of polygons that pair up with each index of the tilemap. Then when other rooms load it creates a grid and adds a polygon using "key" list polygon for that tile index and translates it to the correct tile position.

It is setup so adding new tiles to the tilemap takes just a few minutes. Draw the tile, place 3 or 4 vert objects and the rest is fully automated by code.

Once I have the collision resolution worked out with a few different options that are smooth I'll just shared the project with a github link.

For the most part though each polygon key is made with instance_place_list() to get the verts, then put them in an array of structs like "new Vec2(_vertX, _vertY)".
That array then goes into a polygon struct "new Polygon(_originX, _originY, _vertArray)" The polygon struct itself has all the features to move, rotate, copy, etc. that one would do with a polygon.
 
Last edited:

HalRiyami

Member
Ok I see now why these are created on room start.
I'm looking forward to the project. I guess once I see it I'll get a better understanding of how the whole thing works.
 

badwrong

Member
Ok I see now why these are created on room start.
I'm looking forward to the project. I guess once I see it I'll get a better understanding of how the whole thing works.
The creation is extremely light weight. So if it were a huge room of like 100,000x100,000 the most you would have to do is do a small amount where the player spawns, then spread out a loop over multiple steps for the rest. I've done something similar with an mp_grid in a huge multi-layered room and if you draw the grid and watch it fill in, its still stupidly fast.
 

HalRiyami

Member
@badwrong Excellent! I don't have 2.3 yet so I can't run the project but I'm looking at the files to see how you did it.
You weren't lying, that capsule collider looks super smooth šŸ¤©

@Pixelated_Pope I saw your tech blog and I liked the approach but I don't think you did any collision resolution, just detection.
 

badwrong

Member
I wrote a tech blog recently on something similar.
Ya I've seen it.
It's neat, but really isn't practical in a real game I think. I think for beginners, your method is nice because it basically does a brute force collision sweep to get a result. Personally I think the various while loop methods for collision detection are something I would never touch. Or at the very least if I needed a brute force method I would do a binary sweep instead of pixel by pixel, and certainly I would use math to resolve the collision instead of precise collisions in a nested loop.

My solution is far less expensive and yields good collision response. Especially the capsule collider if someone were to want a smooth sloped platformer.
 
Last edited:

badwrong

Member
@badwrong Excellent! I don't have 2.3 yet so I can't run the project but I'm looking at the files to see how you did it.
You weren't lying, that capsule collider looks super smooth šŸ¤©

@Pixelated_Pope I saw your tech blog and I liked the approach but I don't think you did any collision resolution, just detection.
Thanks! The capsule basically works like a 3D capsule collider with a plane intersect test, minus the Z. It uses that result to pick a spot to position a sphere for a simple sphere > line collision test.

I do need to add a check for when it gets inside any geometry, because it will crash if it tries to resolve when the sphere is on a polygon edge exactly since the distance throws a NaN error. Only really happens if you scale the object so high that it won't fit lol. Just wasn't worth checking for in a demo project I think.
 
Last edited:
Top