Oh blimey, that’s good to know too! I can consistently replicate the issue with both kinematic and dynamic bodies.
In my case dynamic bodies are more important, because I want to save time by not coding the collision responses myself.
Oh blimey, that’s good to know too! I can consistently replicate the issue with both kinematic and dynamic bodies.
In my case dynamic bodies are more important, because I want to save time by not coding the collision responses myself.
Just to be clear, this is not a “bug”! Box2D is working exactly the way it should be.
Because Defold treats each tile as a separate shape (for good reasons), life is a bit more difficult than you might expect, but it’s not all Defold’s fault either. Nor is this just a problem with tilemaps. Any time you want to build a continuous surface out of multiple pieces you’ll run into this. Unfortunately, no physics engine can read your mind.
Given two overlapping bodies, the physics engine will calculate the shortest distance and direction necessary to move those bodies so they won’t overlap anymore. It doesn’t really ‘prevent’ overlaps, it just moves them apart before things are rendered. With two rectangles, the normal of the contact will be vertical or horizontal depending on the amount of overlap in each direction.
In most cases, gravity is going to cause a vertical overlap every frame that something is ‘resting’ on the ground. As your body moves across a seam in the ground, this vertical overlap will be larger than the horizontal overlap from the seam for possibly a frame or two, giving you a horizontal contact normal.
The deeper the vertical overlap (because of low framerate or something), the worse it is.
Of course it happens with regular objects too (no tilemap)
For most games it’s not really possible to simply avoid this issue by making every floor a single continuous shape. It’s pretty much guaranteed in any infinite runner or any other platformer where the levels are made in separate pieces. And for example what if you want a one-way platform sticking off the end of a solid platform? Those two bodies must have different properties, there’s no way for them to be a single shape.
Any robust platformer (with any engine) is going to have to deal with this issue. A specialized ‘physics engine’ like Bump might help—meaning that someone else solved the problem for you.
I think you will find that using a dynamic body for your player will be much more work in the long run, especially considering the limited subset of Box2D’s features that Defold gives you access to. With a dynamic body you will have to deal with forces and friction, you can’t just move the player where you want, you can’t change collision groups at runtime so I’m not sure how you would do one-way platforms, etc. Kinematic bodies let you skip all that stuff. You can control them just like any other game object, but they give you detailed collision information (which you can use or ignore as you like).
@ross.grams: That is an amazing writeup and summary of platformer physics! Thank you for taking the time to put this together!
As a side-note: I’ve had a module for simplifying platformer logic lying around in my toolbelt lib for quite some time. I’ve been meaning to move it to a separate repo and share it as a Defold library project. Maybe it could be useful for someone who quickly wants to get the physics for a platformer game up and running: https://github.com/britzl/platypus
Thanks for this amazing info. I never really considered it a bug Because I knew it was something to do with the tiles acting as seperate static objects. I was more looking for some sort of workaround. But It could be fixed by the Defold team if they ever decide to rewrite how tilemaps are converted to box2d static objects such as treating adjacent tiles as a single object at run time.
I was using libGDX before and a programmer that I follow on youtube (Dermetfan) created a Box2d assist library that did just that. It converted tilemaps (That were made in Tiled) to Triangulate d box2d objects. But I never got around to using it outside of the tutorial because I was avoiding Box2d at the time.
Kudos for a fantastic writeup @ross.grams, beautifully explained. I always did consider it a bug, because I thought it strange that a dynamic object can get stuck between two static fixtures even though there is (literally) no gap between them. Bug or not, would be good to figure out a nice fix to make it work better in a platform game.
@britzl, I had a quick look at your solution. It seems to fire only four ray casts, which means there is still no way of knowing when the player leaves a platform? I would have thought you need eight rays to accurately determine this. But would be very happy to be wrong in this case!
You could have a trigger shape at the feet of the character to determine if the player is standing on a platform or not.
The problem I have is that the dynamic body sometimes gets stuck between tiles. I managed to figure out all collisions with ray casts. It works really well, so if I was able to solve the getting stuck problem the prototype would be finished.
I could use a kinematic object instead and try to hack a way to avoid the collision responses that causes the issue. I’d rather not, though, because in my game I am actively using friction, forces and all the other stuff Box2D does so well.
As a side note, I noticed that triggers appear to lag a bit behind the main game object for some reason. See this thread: Determining all collision directions for player
I use a combination of physics shapes and ray casts. Physics shapes for resolving/separating kinematic collisions. The ray cast is used for detection of “state”, ie wall and or ground contact. Now that I think of it I probably need two downward facing rays to detect when standing really at the edge of a ledge.
Yeah, that’s what I meant. I think a generic solution could be eight ray casts, like the illustration with Link above.
I’ve updated Platypus to use two ray casts down to detect the edge of ledges. It works a lot better. I’ll continue working on the lib and add examples of directional platforms, climbing ladders and so on.
Actually, Erin Catto says it’s a bug, and who am I to argue?
Haha! If it actually mattered at all, I would definitely argue with that issue tag.
It seems interesting. It seems like he’s focused on the “skin” interactions, which I don’t think would help at all with higher gravity or lower frame rate, but I haven’t managed to muddle through his whole explanation yet.
He he he! I think what’s important is how it’s solved. Would love to have a solid fix for this, rather than a complicated workaround.
It looks like newer versions of Box2D avoid this problem by using edge/chain shapes rather than polygon shapes. This and other possible fixes are discussed here.
Which version of Box2D does Defold use?
We use a very old and slightly modified version of Box2D 2.1 (hides)
Oh no! I guess there is a reason for not using a later version? 2.1 doesn’t appear to have edge/chain shapes.
I believe 2.1 was the version available when 2D physics was added to the engine.
That’s a good reason.
Would be great to use a newer version that supports edge and chain shapes, in case there is ever an opportunity to support those!
Would it be possible to update Box2D? It may be that the tunneling issues happen because of the older version of Box2D? And it would allow for chain shapes to be supported.
It would not be trivial. We have modified Box2D so it’s not like we’d only have to update some source and header files or link against a new pre built lib.
And I have a long list of things with higher priority than a Box2D update I’m afraid… BUT if there’s anyone out there with plenty of experience working with the C version of Box2D I’d like to get in touch. I would be willing to discuss a collaboration around an upgrade somehow.