How to make runtime created shapes collide?

Hi!
I have been trying to implement compound shapes in Defold. I want to attach multiple shapes to a single kinematic collision object, so i can create non convex shapes, like an “L”.
The first implementation worked, when i created a separate go for every “block” instead of adding multiple shapes. The problem was that those blocks collided with blocks in the same shape. I filtered those collisions from lua, but they got reported from the engine so it generated a tons of useless contact point messages.
The collision object has a “dummy” 1x1x1 shape added from the editor. The runtime created shape appears on screen with physics debug. It moves with with the go.
The problem: the runtime created shape does not collide with anything. Only the dummy shape collides with the tilemap.
I made a new script which only adds a single collision shape at the center of the go, so i can eliminate every flaw that might be caused by the shape generation from the tile layer.
The create shape code:

local collision_url = Utils.get_fragment_url(msg.url(), C.FRAGMENT_HASHES.collision_obj)
local body = b2d.get_body(collision_url)
    
local box_data = {
    type = b2d.shape.SHAPE_TYPE_BOX,
    hx = C.HALF_TILE_SIZE,
    hy = C.HALF_TILE_SIZE,
    hz = C.HALF_TILE_SIZE,
    center = vmath.vector3(0, 0, 0),
    restitution = 0.5,
    friction = 0.1
}

b2d.body.create_shape(body, box_data)

local shapes = b2d.body.get_shapes(body)
for i = 1, #shapes do
    local s_id = shapes[i].shape_id
    b2d.shape.enable_contact_events(s_id, true)
end

I added some logging to represent the shapes on the collision object:

DEBUG:SCRIPT: body world	Box2D.b2world = 0x7fc78002d9e0
DEBUG:SCRIPT: -----------------------------
DEBUG:SCRIPT: before enable contact_events	false
DEBUG:SCRIPT: after enable contact_events	true
DEBUG:SCRIPT: shape,
{ --[[0x7fc78002dcb0]]
  vertices = { --[[0x7fc78002def0]]
    1 = vmath.vector3(-16, -16, 0),
    2 = vmath.vector3(16, -16, 0),
    3 = vmath.vector3(16, 16, 0),
    4 = vmath.vector3(-16, 16, 0)
  },
  type = 3
}
DEBUG:SCRIPT: shape world	Box2D.b2world = 0x7fc78002e410
DEBUG:SCRIPT: shape data,
{ --[[0x7fc78002d960]]
  child_count = 1,
  is_chain_segment = false,
  restitution = 0.5,
  friction = 0.10000000149012,
  material = 0,
  density = 1,
  sensor = false,
  type = 3,
  shape_id = Box2D.b2shape = 0x7fc78002da20,
  index = 1
}
DEBUG:SCRIPT: ------------------------------
DEBUG:SCRIPT: before enable contact_events	true
DEBUG:SCRIPT: after enable contact_events	true
DEBUG:SCRIPT: shape,
{ --[[0x7fc78002e540]]
  vertices = { --[[0x7fc78002e5d0]]
    1 = vmath.vector3(-0.5, -0.5, 0),
    2 = vmath.vector3(0.5, -0.5, 0),
    3 = vmath.vector3(0.5, 0.5, 0),
    4 = vmath.vector3(-0.5, 0.5, 0)
  },
  type = 3
}
DEBUG:SCRIPT: shape world	Box2D.b2world = 0x7fc78002e8c0
DEBUG:SCRIPT: shape data,
{ --[[0x7fc78002dbe0]]
  child_count = 1,
  is_chain_segment = false,
  restitution = 0.5,
  friction = 0.10000000149012,
  material = 0,
  density = 1,
  sensor = false,
  type = 3,
  shape_id = Box2D.b2shape = 0x7fc78002dc60,
  index = 2
}
DEBUG:SCRIPT: ------------------------------

In game with physics debugging:

The collision resolving code works (it works for other stuff in the game like the player). Based on the image, i think only the 1x1x1 dummy shape at the center of of the go collides with the tilemap.

Thanks for any help!

Hi, i am not sure of what I am saying, but I think that you need to set the filtering data on each shape you create (the group + mask that you see in Defold editor collision object).

In the editor we think that group+mask is attached to the b2d body, but regarding the b2d (v3) API, it is related to shapes. You have to set the filtering attributes of each shape at creation time, I guess.
It is more explicit in the create_chain() API

I think you can set it like that:

b2d.shape.set_filter_data(shape_id, {category_bits = 1, group_index = 0, mask_bits = 6} )

-- or at creation time:
b2d.body.create_shape(body, { ..... shape def.....  , filter={category_bits = 1, group_index = 0, mask_bits = 6} } )

But here is it just numbers, while in the editor it is some names… One thing you can do is get the filter data of a known shapes defined in Editor, then copy it to new shapes to get the good groups and masks.

filter_data = b2d.shape.get_filter_data(shapes[1].shape_id) -- known shape
b2d.body.create_shape(body, { ..... shape def.....  , filter=filter_data } ) -- reuse filter data

I am just guessing, based on examples and this repo: buggy-climb/terrain.lua at main · alfowler1976/buggy-climb · GitHub
(an example for the community challenge)

I am too struggling to understand all the links between the editor and physics old API and the new b2d scripting API.

See here for b2d manual on the subject Box2D: Simulation

1 Like

Thanks for your help!
With adding the filter data to the definition it is working! Even with the compound shapes i originally implemented.

2 Likes

When creating the example, I ran into this issue. There’s no way to convert an editor collision group into a bitmask position for the filter data without copying and pasting from an existing object. The engine must handle this internally, so I requested some functions to be added.https://github.com/defold/defold/issues/12653

2 Likes