Help with crash in physics_2d, tilemaps

I’m used the Tiled map editor, and I’m in the process of reworking how I structure my tilemaps. I switched from exporting a single tilemap to exporting a collection (mainly because it lets me split up and use multiple tilesets on a single map).

I’ve had to refactor a fair bit of the code, and I’m sure there are bugs in it, but unfortunately I’m hitting a hard crash (crashdump attached) and there’s no lua stacktrace, so I’m really not sure what exactly is going wrong or how to fix it. And my C++ knowledge is nonexistent, so I’m not sure what purpose this assert serves.

Assertion failed: (fixture != 0x0), function GetFixture, file ../src/physics/physics_2d.cpp, line 650.
dmengine_2021-12-02-232056_dantalion.crash.txt (79.3 KB)

I can certainly include a snippet of my garbage code where I think the error’s happening, but at the moment I’m really just looking for help understanding what this error means.

The crash shows the following stack trace:

Thread 0 Crashed:: engine_main  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	0x00007fff2030192e __pthread_kill + 10
1   libsystem_pthread.dylib       	0x00007fff203305bd pthread_kill + 263
2   libsystem_c.dylib             	0x00007fff202854a0 __abort + 139
3   libsystem_c.dylib             	0x00007fff20285415 abort + 140
4   libsystem_c.dylib             	0x00007fff202847d8 __assert_rtn + 314
5   dmengine                      	0x000000010cae3043 dmPhysics::SetGridShapeEnable(void*, unsigned int, unsigned int) (.cold.1) + 35 (physics_2d.cpp:650)
6   dmengine                      	0x000000010c848830 dmPhysics::GetFixture(b2Body*, unsigned int) + 5 (physics_2d.cpp:650) [inlined]
7   dmengine                      	0x000000010c848830 dmPhysics::SetGridShapeEnable(void*, unsigned int, unsigned int) + 96 (physics_2d.cpp:674)
8   dmengine                      	0x000000010c7f28e6 dmGameSystem::CompCollisionObjectOnMessage(dmGameObject::ComponentOnMessageParams const&) + 694 (comp_collision_object.cpp:1134)
9   dmengine                      	0x000000010c7cc1ab dmGameObject::DispatchMessagesFunction(dmMessage::Message*, void*) + 955 (gameobject.cpp:2264)
10  dmengine                      	0x000000010c9b17cc dmMessage::InternalDispatch(unsigned long long, void (*)(dmMessage::Message*, void*), void*, bool) + 652 (message.cpp:541)
11  dmengine                      	0x000000010c7d22bb dmGameObject::DispatchMessages(dmGameObject::Collection*, unsigned long long*, unsigned int) + 203 (gameobject.cpp:2303)
12  dmengine                      	0x000000010c7cec98 dmGameObject::Update(dmGameObject::Collection*, dmGameObject::UpdateContext const*) + 640 (gameobject.cpp:2449) [inlined]
13  dmengine                      	0x000000010c7cec98 dmGameObject::Update(dmGameObject::CollectionHandle*, dmGameObject::UpdateContext const*) + 664 (gameobject.cpp:2463)
14  dmengine                      	0x000000010c7efdcb dmGameSystem::CompCollectionProxyUpdate(dmGameObject::ComponentsUpdateParams const&, dmGameObject::ComponentsUpdateResult&) + 507 (comp_collection_proxy.cpp:281)
15  dmengine                      	0x000000010c7cec48 dmGameObject::Update(dmGameObject::Collection*, dmGameObject::UpdateContext const*) + 560 (gameobject.cpp:2440) [inlined]
16  dmengine                      	0x000000010c7cec48 dmGameObject::Update(dmGameObject::CollectionHandle*, dmGameObject::UpdateContext const*) + 584 (gameobject.cpp:2463)
17  dmengine                      	0x000000010c778d7c dmEngine::Step(dmEngine::Engine*) + 988 (engine.cpp:1520)
18  dmengine                      	0x000000010c77a02a dmEngineUpdate(dmEngine::Engine*) + 26 (engine.cpp:1983)
19  dmengine                      	0x000000010c77a26d dmEngine::RunLoop(dmEngine::RunLoopParams const*) + 109 (engine_loop.cpp:69)
20  dmengine                      	0x000000010c77a1d2 EngineMain(int, char**) + 90 (engine_main.cpp:49) [inlined]
21  dmengine                      	0x000000010c77a1d2 engine_main(int, char**) + 98 (engine_main.cpp:131)
22  dmengine                      	0x000000010c771e34 start + 52

And the line is this (not exactly matching the version of the engine you are using) (Which version of Defold are you using?):

My guess is that you have a game object with a collision component without a collision shape.

Check that your tilesource has a collision image set (usually same as the tile image). Also check that any collision component references the tilemap as its shape.

(Which version of Defold are you using?)

1.2.189

My guess is that you have a game object with a collision component without a collision shape.

Check that your tilesource has a collision image set (usually same as the tile image). Also check that any collision component references the tilemap as its shape.

Ahhh. Hrm. No, as far as I can tell, it looks to be set up correctly. It’s a little weird now since it’s 1 gameobject with multiple tilemap children. It has a collision object set to the correct tilemap.

I tried changing it so that all the tilesources in the scene had collisions set, as well as adding collision objects for the other tilemaps in the collection, but I still get the same crash. :man_shrugging:

Feel free to zip your project and share it here

Here it is

topdown.zip (8.0 MB)

It crashes if you move anywhere and then press space to interact.

Well it’s a bit of a mystery why exactly it’s crashing, but I think it will be easy enough to work around it to get your project working again.

It seems to have a problem with this bit (in /main/map.lua, line 5):

pcall(tilemap.set_visible, map_id, layer, true)

Though it doesn’t crash when you call that, it crashes during then next frame update, as far as I can tell.

If you replace it with

pcall(tilemap.get_tile, map_id, layer, 0, 0)

Then it doesn’t crash, though it does spit out thousands of errors, so that’s still kind of a problem. I guess pcall isn’t protecting things as much as you’d like.


The solution I’m thinking of is to write your code in a different way (super helpful, I know! :P). From what I understand, when the player presses the ‘interact’ button, you are calling a function on every tile in every layer, on every map, which includes doing the pcall trick to check for a couple dozen tile layers that don’t exist…

That’s pretty darn inefficient and a bit questionable to call a Defold function with arguments that you know would normally crash the engine. I think it was only a matter of time before it caused you some sort of trouble. Why don’t you just have a short list somewhere of objects that can be interacted with? Or even simpler, use a separate collision group for interactible tiles/objects and a trigger on the player and let the physics engine do everything for you?

To sum up: I don’t think this weird crash will get fixed immediately, but I think you can get help improving your code so it doesn’t matter anyway.

It seems to have a problem with this bit (in /main/map.lua, line 5):

pcall(tilemap.set_visible, map_id, layer, true)

Though it doesn’t crash when you call that, it crashes during then next frame update, as far as I can tell.

If you replace it with

pcall(tilemap.get_tile, map_id, layer, 0, 0)

Then it doesn’t crash, though it does spit out thousands of errors, so that’s still kind of a problem. I guess pcall isn’t protecting things as much as you’d like.

Hmm, ok. Funnily enough, I did have something like that earlier, but it didn’t work – it will never return false, so the method it’s in (layer_exists) doesn’t actually serve its purpose. Seems get_tile logs an error, but doesn’t actually return one (or however pcall decides to return false).

Since it does look like that’s what’s causing the crash, though… Looks like I’ll need some other way to achieve my goals here.

The solution I’m thinking of is to write your code in a different way (super helpful, I know! :P). From what I understand, when the player presses the ‘interact’ button, you are calling a function on every tile in every layer, on every map, which includes doing the pcall trick to check for a couple dozen tile layers that don’t exist…

That’s pretty darn inefficient and a bit questionable to call a Defold function with arguments that you know would normally crash the engine. I think it was only a matter of time before it caused you some sort of trouble. Why don’t you just have a short list somewhere of objects that can be interacted with? Or even simpler, use a separate collision group for interactible tiles/objects and a trigger on the player and let the physics engine do everything for you?

To sum up: I don’t think this weird crash will get fixed immediately, but I think you can get help improving your code so it doesn’t matter anyway.

Yeahhhh… :grimacing: This is all prototype code, and I am planning on reworking pretty much all of it before it’s anywhere near ready to ship. The main design goal I’m trying to solve here is I want the Tiled tilemap to be the canonical source of game data. So the short list of objects that can be interacted with would need to live there.

You’re definitely right that it’s insanely innefficient. One smart refactor would be to just loop through all the tiles once, and build that list of objects then.

I still want a way to programmatically query whether or not a layer exists on a tilemap, since I don’t think that all my maps are going to have exactly the same structure, and I can’t figure out a way to do this with Defold :frowning:

Seems I still have quite a ways to go, but I’m getting closer.

2 Likes

How are you exporting from Tiled? Are you using the Defold collection exporter? My first thought would be to find a way to export the list of layers and any other extra data, from Tiled. Bypass Defold’s limitations entirely.

I haven’t used them myself, but I’m guessing the Defold exporters for Tiled don’t let you include any extra data…(correct me if I’m wrong)…but you could set up a script for Tiled that exports a Lua module with the list of layers and whatever other data you would like to have (as a separate file alongside the collection/tilemap).

1 Like

This is what I’m going to look into next.

My first pass was using the Defold tilemap exporter, but that required some manual fixing each time I exported (resetting the z values, mostly). Since I wanted to be able to break up the tilesets into multiple sheets for better organization, I switched to the collection exporter.

… and after a little bit of research, Tiled actually does also have a pure lua export as well! I don’t exactly what it will look like, if I can build the tilemaps at runtime using the data, or just modify my runtime post-processing using the data from the lua export, but I think this’ll get me where I want to be.

Using (only) the lua export will give you the freedom to do whatever you want…and of course the responsibility to do everything that you want. You’ll have to deal with the “static-ness” of Defold a bit more—you can’t use tilemap.set_tile outside of existing tilemap bounds, and you can’t dynamically add layers. So you’ll have to set up a tilemap with corner tiles set to allocate the bounds, and with all the layers you will use (not a big deal, really).

But you’re right, you could just export as both, that’s a pretty good idea. You’ll have redundant info, but it would be less work on your end. The only other drawback is it would be a bit more tedious to manually export as two separate files & formats each time, I don’t know that there’s a way to automate that.

Here’s an example of what I was thinking about exporting the layer list as a separate file:

tiled-test.zip (172.4 KB)

There’s a custom action in the file menu to export the layers list (only works if you have a map open). By default it writes a file next to the tmx file, but it also checks for an “export filepath” property on the tilemap to use instead. I just used JSON since it’s already built into javascript, but you could write/find a lua serializer instead. You could expand on the idea to include other custom properties, object layer data, etc.