Trying to build a rotating gear (multi-element physic body) : no collisions ?

Hey there !

I’m building a toothed gear shaped :

coronasdk_gear.jpg

It’s made of several sahpes :

  • The gear itself, a circular shape at the center.

  • 4 rectangles, creating the “tooth bar”.

  • 8 circles so that the tooth are rounded-shape.

All those shapes are then joint using several “weld” joints.

I’m also creating a physical square at the center, set as a sensor, in order to “pin” the gear.

I want the gear to turn ot itself when something collides on it. For this exemple, I’ve got a function which is spawning small little cubes at the top of the screen.

It works almost fine : the gear turns on itself. But the tooth of the gear don’t seem to collide with the spawned cubes.

From my previous test, it seems that using a “weld joint” somehow “breaks” the collision detection.

What is weird is that if I don’t specify the density of the small cubes, the collisions seems to work fine.

Here’s the full code (copy/past in a new main.lua file and it will work fine)

physics = require"physics" physics.start() physics.setDrawMode("debug") local gearGroup = display.newGroup(); ---------------------------------------------------------------------------------------------- -- SOME INFO DEFINING THE GEAR PROPERTIES ---------------------------------------------------------------------------------------------- self = {} self.xpos = display.contentWidth\*0.5 self.ypos = display.contentWidth\*0.5 self.size = 256 self.rotation = 0 ---------------------------------------------------------------------------------------------- -- CREATION OF THE GEAR ---------------------------------------------------------------------------------------------- -- CREATING THE CENTER ROUDNED SHAPE OF THE GEAR self.image = display.newCircle(0,0,256) self.image.anchorX = 0.5; self.image.anchorY = 0.5 self.image.health = 1; self.image.x = display.contentWidth\*0.5; self.image.y = display.contentWidth\*0.5; self.image.width = self.size; self.image.height = self.size; self.image.rotation = self.rotation gearGroup:insert(self.image) local physicSize = self.size\*0.5 - 95\*(self.size/512) physics.addBody(self.image, "dynamic", {density= 2, radius=physicSize, friction=10, bounce=0.1}) -- CREATING A PHYSICAL OBJECT, WHICH WILL BE SET AS A SENSOR TO "PIN" THE GEAR self.image.center = display.newCircle(0,0,50) self.image.center.x = self.xpos self.image.center.y = self.ypos gearGroup:insert(self.image.center) -- Pinning the physics.addBody(self.image.center, "static") self.image.center.isSensor = true self.image.center.jointure = physics.newJoint("pivot", self.image.center, self.image, self.xpos, self.ypos) -- Loop, creating 4 "tooth bar" self.image.tooth = {} for i=1, 4 do -- Creating the bar self.image.tooth[i] = {} self.image.tooth[i].image = display.newRect(0,0,100,100) self.image.tooth[i].image.x = self.xpos self.image.tooth[i].image.y = self.ypos self.image.tooth[i].image.width = 68 \* self.size/512 self.image.tooth[i].image.height = 512 \* self.size/512 - (69\*0.5\*self.size/512)\*2 self.image.tooth[i].image:setFillColor(0,1,0) self.image.tooth[i].image.rotation = -45 + i\*45 + self.rotation gearGroup:insert(self.image.tooth[i].image) -- Adding physics physics.addBody(self.image.tooth[i].image, "dynamic"); -- Creating a joint between the tooth bar and the "center" of the gear self.image.tooth[i].jointure = physics.newJoint("weld", self.image, self.image.tooth[i].image, self.image.x, self.image.y) -- Creating the rounded tooth of the "bars" local rayon = self.image.tooth[i].image.height\*0.5 - 3 local angle = -45 + i\*45 + self.rotation self.image.tooth[i].roundA = display.newCircle(0,0,68\*0.5\*self.size/512) self.image.tooth[i].roundA:setFillColor(1,0,0) self.image.tooth[i].roundA.x = self.xpos + rayon\*math.cos(math.rad(angle)) self.image.tooth[i].roundA.y = self.ypos + rayon\*math.sin(math.rad(angle)) self.image.tooth[i].roundB = display.newCircle(0,0,68\*0.5\*self.size/512) self.image.tooth[i].roundB:setFillColor(0,0,1) self.image.tooth[i].roundB.x = self.xpos - rayon\*math.cos(math.rad(angle)) self.image.tooth[i].roundB.y = self.ypos - rayon\*math.sin(math.rad(angle)) -- Adding the rounded tooth to the gear layer gearGroup:insert(self.image.tooth[i].roundA) gearGroup:insert(self.image.tooth[i].roundB) -- Add physics to the rounded tooth physics.addBody(self.image.tooth[i].roundA, "dynamic", {radius=68\*0.5\*self.size/512}) physics.addBody(self.image.tooth[i].roundB, "dynamic", {radius=68\*0.5\*self.size/512}) self.image.tooth[i].roundAJointure = physics.newJoint("weld", self.image.tooth[i].roundA, self.image, self.image.tooth[i].x, self.image.tooth[i].y) self.image.tooth[i].roundBJointure = physics.newJoint("weld", self.image.tooth[i].roundB, self.image, self.image.tooth[i].x, self.image.tooth[i].y) end ---------------------------------------------------------------------------------------------- -- SPAWNING CUBES AT THE TOP OF THE SCREEN ---------------------------------------------------------------------------------------------- spawnItemList = {} spawnItemCount = 0 local function spawnItems() spawnItemCount = spawnItemCount + 1 local xpos = math.random(display.contentWidth) spawnItemList[spawnItemCount] = display.newRect(0,0,50,50) spawnItemList[spawnItemCount].x = xpos spawnItemList[spawnItemCount].y = 0 physics.addBody(spawnItemList[spawnItemCount], "dynamic") end local spawnTimer = timer.performWithDelay(500, spawnItems, 0)

With this line, collision don’t work :

 physics.addBody(spawnItemList[spawnItemCount], "dynamic", {density=10})

With this one, it works fine :

 physics.addBody(spawnItemList[spawnItemCount], "dynamic")

Unfortunately, in my case, I really don’t wanna remove the density of whatever enters in collision with the gear.

Do you have any idea on how I can fix that ? I really need to be able to collide with the tooth gear ! Or maybe I should build my gear in an other way ?

Thanks a lot in advance

Hi @evanspro,

Is there a specific reason why you’re not just constructing this gear as one unified multi-element body? That would be safer than assembling it with a bunch of weld joints and such. The only “tricky” part would be the curved tips on the gear cogs, because you can’t offset circular bodies, but you could safely just contruct 8-sided half-circle polygons and achieve virtually the same thing as a natural circle shape.

Best regards,

Brent

Hi Brent, 

I’m not sure I understand your answer but, by constructing it as one unified multi-element body (just like that ?), that would imply I’d have draw the gear “points by points” which could take some time. And then, because my gears could start at any size and any angle, I’d have to write a function to translates all the coordinates… That’s doable, but it would take me a lot of time.

For now, I’ve tweaked the density numbers of all the different parts of the gear, and it seems to work. It’s still buggy : everything seems to shake and to be unstable, but it may work in the end. My biggest issue is that I really don’t understand why it “doesn’t work” : is there something wrong with the weld joints, or with my logic ?

caveat:  i’ve not run your code, comments based on just a quick glance:

my suspicion, not seeing the word “filter” anywhere, is that your welds are in a constant state of battling collision resolution.   one good hit from one of your projectiles and the weld probably fails and collision resolution probably sends the bits flying around crazy.

try this:  for each body that’s part of the “gear”, add filter={groupIndex=-1} as part of the parameters to the addBody() call.  (you can tweak the collision filter later, this is just a quick test to keep all gear parts from colliding with *each other*)

also, in debug view, look for any “weird” stuff, primarily to make sure your joints are where you think they are

Hi @evanspro,

It’s your option of course, but I still suggest you take the time to construct multi-element gear bodies. It probably wouldn’t be that difficult to write a function that does this automatically, and even takes into account different gear sizes. Ultimately, you will get the best results from unified gears versus gears constructed from welded pieces.

Brent

Evanspro, there was a tutorial some time ago about automatically generating a physics body from an image:  

https://coronalabs.com/blog/2014/01/28/tutorial-create-physics-bodies-from-texture-assets/

Since you may want the gear to have an image eventually, this may be the easiest way to do it.

@davidbollinger :

I thought about the filter collisions and I’ve already tested it. The gear construction does seem to be stable, but then I still have collision problems with all the other objects (it seems that using weld joint causes it).

@Brent Sorrentino : 

Deep in my heart, I do know that is the best solution :slight_smile: But I’m being a little bit lazy and I’d like to find the fastest and easiest solution…

@AlanQuizTix :

… and that’s why I eventually did what you suggested. I’m loading an image of a gear, then I resize/rotate it. Then, I’m using the newOutline function to build the physic body. Now, since my gears can be resized,  my biggest issue is that the number of tooth should also change, and their length too. But for now, it seems to be enough.

Thanks a lot !

just an fyi imo - newOutline can be finicky picking the right coarseness – too little and the approximated curves will be choppy, too fine and you’ll get degenerate polys.

multi-fixture is cleaner (from someone with some experience generating algorithmic gears) tho also has quirks - bodies can “slide through” colinear edges of adjacent fixtures and “get stuck” inside that “crack”.  has to do with box2d tolerances.  you can fudge some overlap among fixtures to eliminate that “crack”, but that then will cause other issues.

welds will do it, you just have to set them up meticulously.  (see those “puppet strings” in the pic you posted?  shouldn’t be there)

here’s your weld code tweaked a bit, seems to be working:

physics = require"physics" physics.start() physics.setDrawMode("debug") local gearGroup = display.newGroup(); -- to make tweaking easier below.. local GEAR\_BOUNCE = 0.5 local GEAR\_DENSITY = 1.0 local GEAR\_FRICTION = 0.5 local GEAR\_FILTER = { groupIndex=-1 } local BOX\_BOUNCE = 0.5 local BOX\_DENSITY = 1.0 local BOX\_FRICTION = 0.5 ---------------------------------------------------------------------------------------------- -- SOME INFO DEFINING THE GEAR PROPERTIES ---------------------------------------------------------------------------------------------- self = {} self.xpos = display.contentWidth\*0.5 self.ypos = display.contentWidth\*0.5 self.size = 256 self.rotation = 0 ---------------------------------------------------------------------------------------------- -- CREATION OF THE GEAR ---------------------------------------------------------------------------------------------- -- CREATING THE CENTER ROUDNED SHAPE OF THE GEAR self.image = display.newCircle(0,0,256) self.image.anchorX = 0.5; self.image.anchorY = 0.5 self.image.health = 1; self.image.x = display.contentWidth\*0.5; self.image.y = display.contentWidth\*0.5; self.image.width = self.size; self.image.height = self.size; self.image.rotation = self.rotation gearGroup:insert(self.image) local physicSize = self.size\*0.5 - 95\*(self.size/512) physics.addBody(self.image, "dynamic", {bounce=GEAR\_BOUNCE, density=GEAR\_DENSITY, friction=GEAR\_FRICTION, radius=physicSize, filter=GEAR\_FILTER}) -- CREATING A PHYSICAL OBJECT, WHICH WILL BE SET AS A SENSOR TO "PIN" THE GEAR self.image.center = display.newCircle(0,0,50) self.image.center.x = self.xpos self.image.center.y = self.ypos gearGroup:insert(self.image.center) -- Pinning the physics.addBody(self.image.center, "static") self.image.center.isSensor = true self.image.center.jointure = physics.newJoint("pivot", self.image.center, self.image, self.xpos, self.ypos) -- Loop, creating 4 "tooth bar" self.image.tooth = {} for i=1, 4 do -- Creating the bar self.image.tooth[i] = {} self.image.tooth[i].image = display.newRect(0,0,100,100) self.image.tooth[i].image.x = self.xpos self.image.tooth[i].image.y = self.ypos self.image.tooth[i].image.width = 68 \* self.size/512 self.image.tooth[i].image.height = 512 \* self.size/512 - (69\*0.5\*self.size/512)\*2 self.image.tooth[i].image:setFillColor(0,1,0) self.image.tooth[i].image.rotation = -45 + i\*45 + self.rotation gearGroup:insert(self.image.tooth[i].image) -- Adding physics physics.addBody(self.image.tooth[i].image, "dynamic", {bounce=GEAR\_BOUNCE, density=GEAR\_DENSITY, friction=GEAR\_FRICTION, filter=GEAR\_FILTER }); -- Creating a joint between the tooth bar and the "center" of the gear self.image.tooth[i].jointure = physics.newJoint("weld", self.image, self.image.tooth[i].image, self.image.x, self.image.y) -- Creating the rounded tooth of the "bars" local rayon = self.image.tooth[i].image.height\*0.5 - 3 local angle = -45 + i\*45 + self.rotation self.image.tooth[i].roundA = display.newCircle(0,0,68\*0.5\*self.size/512) self.image.tooth[i].roundA:setFillColor(1,0,0) self.image.tooth[i].roundA.x = self.xpos + rayon\*math.cos(math.rad(angle)) self.image.tooth[i].roundA.y = self.ypos + rayon\*math.sin(math.rad(angle)) self.image.tooth[i].roundB = display.newCircle(0,0,68\*0.5\*self.size/512) self.image.tooth[i].roundB:setFillColor(0,0,1) self.image.tooth[i].roundB.x = self.xpos - rayon\*math.cos(math.rad(angle)) self.image.tooth[i].roundB.y = self.ypos - rayon\*math.sin(math.rad(angle)) -- Adding the rounded tooth to the gear layer gearGroup:insert(self.image.tooth[i].roundA) gearGroup:insert(self.image.tooth[i].roundB) -- Add physics to the rounded tooth physics.addBody(self.image.tooth[i].roundA, "dynamic", {bounce=GEAR\_BOUNCE, density=GEAR\_DENSITY, friction=GEAR\_FRICTION, radius=68\*0.5\*self.size/512, filter=GEAR\_FILTER}) physics.addBody(self.image.tooth[i].roundB, "dynamic", {bounce=GEAR\_BOUNCE, density=GEAR\_DENSITY, friction=GEAR\_FRICTION, radius=68\*0.5\*self.size/512, filter=GEAR\_FILTER}) self.image.tooth[i].roundAJointure = physics.newJoint("weld", self.image.tooth[i].roundA, self.image, self.image.tooth[i].image.x, self.image.tooth[i].image.y) self.image.tooth[i].roundBJointure = physics.newJoint("weld", self.image.tooth[i].roundB, self.image, self.image.tooth[i].image.x, self.image.tooth[i].image.y) end ---------------------------------------------------------------------------------------------- -- SPAWNING CUBES AT THE TOP OF THE SCREEN ---------------------------------------------------------------------------------------------- spawnItemList = {} spawnItemCount = 0 local function spawnItems() spawnItemCount = spawnItemCount + 1 --local xpos = math.random(display.contentWidth) -- i tightened this up just cuz got tired of waiting for a collision, no other reason local xpos = math.random(display.contentWidth/3, display.contentWidth\*2/3) spawnItemList[spawnItemCount] = display.newRect(0,0,50,50) spawnItemList[spawnItemCount].x = xpos spawnItemList[spawnItemCount].y = 0 spawnItemList[spawnItemCount].isBullet = true physics.addBody(spawnItemList[spawnItemCount], "dynamic", {bounce=BOX\_BOUNCE, density=BOX\_DENSITY, friction=BOX\_FRICTION}) end local spawnTimer = timer.performWithDelay(500, spawnItems, 0)

@davidbollinger Hey, this is working perfectly ! Thanks a lot, now I’ll be able to do everything I wanted (change the gear / teeth size)

But I’d like to be sure to understand : my welds joints were wrong as I didn’t attach them to the right bodies (“weird puppet strings”) ? Is that what was preventing the teeth to collide correctly with other objects ?

Hi @evanspro,

Is there a specific reason why you’re not just constructing this gear as one unified multi-element body? That would be safer than assembling it with a bunch of weld joints and such. The only “tricky” part would be the curved tips on the gear cogs, because you can’t offset circular bodies, but you could safely just contruct 8-sided half-circle polygons and achieve virtually the same thing as a natural circle shape.

Best regards,

Brent

Hi Brent, 

I’m not sure I understand your answer but, by constructing it as one unified multi-element body (just like that ?), that would imply I’d have draw the gear “points by points” which could take some time. And then, because my gears could start at any size and any angle, I’d have to write a function to translates all the coordinates… That’s doable, but it would take me a lot of time.

For now, I’ve tweaked the density numbers of all the different parts of the gear, and it seems to work. It’s still buggy : everything seems to shake and to be unstable, but it may work in the end. My biggest issue is that I really don’t understand why it “doesn’t work” : is there something wrong with the weld joints, or with my logic ?

caveat:  i’ve not run your code, comments based on just a quick glance:

my suspicion, not seeing the word “filter” anywhere, is that your welds are in a constant state of battling collision resolution.   one good hit from one of your projectiles and the weld probably fails and collision resolution probably sends the bits flying around crazy.

try this:  for each body that’s part of the “gear”, add filter={groupIndex=-1} as part of the parameters to the addBody() call.  (you can tweak the collision filter later, this is just a quick test to keep all gear parts from colliding with *each other*)

also, in debug view, look for any “weird” stuff, primarily to make sure your joints are where you think they are

Hi @evanspro,

It’s your option of course, but I still suggest you take the time to construct multi-element gear bodies. It probably wouldn’t be that difficult to write a function that does this automatically, and even takes into account different gear sizes. Ultimately, you will get the best results from unified gears versus gears constructed from welded pieces.

Brent

Evanspro, there was a tutorial some time ago about automatically generating a physics body from an image:  

https://coronalabs.com/blog/2014/01/28/tutorial-create-physics-bodies-from-texture-assets/

Since you may want the gear to have an image eventually, this may be the easiest way to do it.

@davidbollinger :

I thought about the filter collisions and I’ve already tested it. The gear construction does seem to be stable, but then I still have collision problems with all the other objects (it seems that using weld joint causes it).

@Brent Sorrentino : 

Deep in my heart, I do know that is the best solution :slight_smile: But I’m being a little bit lazy and I’d like to find the fastest and easiest solution…

@AlanQuizTix :

… and that’s why I eventually did what you suggested. I’m loading an image of a gear, then I resize/rotate it. Then, I’m using the newOutline function to build the physic body. Now, since my gears can be resized,  my biggest issue is that the number of tooth should also change, and their length too. But for now, it seems to be enough.

Thanks a lot !

just an fyi imo - newOutline can be finicky picking the right coarseness – too little and the approximated curves will be choppy, too fine and you’ll get degenerate polys.

multi-fixture is cleaner (from someone with some experience generating algorithmic gears) tho also has quirks - bodies can “slide through” colinear edges of adjacent fixtures and “get stuck” inside that “crack”.  has to do with box2d tolerances.  you can fudge some overlap among fixtures to eliminate that “crack”, but that then will cause other issues.

welds will do it, you just have to set them up meticulously.  (see those “puppet strings” in the pic you posted?  shouldn’t be there)

here’s your weld code tweaked a bit, seems to be working:

physics = require"physics" physics.start() physics.setDrawMode("debug") local gearGroup = display.newGroup(); -- to make tweaking easier below.. local GEAR\_BOUNCE = 0.5 local GEAR\_DENSITY = 1.0 local GEAR\_FRICTION = 0.5 local GEAR\_FILTER = { groupIndex=-1 } local BOX\_BOUNCE = 0.5 local BOX\_DENSITY = 1.0 local BOX\_FRICTION = 0.5 ---------------------------------------------------------------------------------------------- -- SOME INFO DEFINING THE GEAR PROPERTIES ---------------------------------------------------------------------------------------------- self = {} self.xpos = display.contentWidth\*0.5 self.ypos = display.contentWidth\*0.5 self.size = 256 self.rotation = 0 ---------------------------------------------------------------------------------------------- -- CREATION OF THE GEAR ---------------------------------------------------------------------------------------------- -- CREATING THE CENTER ROUDNED SHAPE OF THE GEAR self.image = display.newCircle(0,0,256) self.image.anchorX = 0.5; self.image.anchorY = 0.5 self.image.health = 1; self.image.x = display.contentWidth\*0.5; self.image.y = display.contentWidth\*0.5; self.image.width = self.size; self.image.height = self.size; self.image.rotation = self.rotation gearGroup:insert(self.image) local physicSize = self.size\*0.5 - 95\*(self.size/512) physics.addBody(self.image, "dynamic", {bounce=GEAR\_BOUNCE, density=GEAR\_DENSITY, friction=GEAR\_FRICTION, radius=physicSize, filter=GEAR\_FILTER}) -- CREATING A PHYSICAL OBJECT, WHICH WILL BE SET AS A SENSOR TO "PIN" THE GEAR self.image.center = display.newCircle(0,0,50) self.image.center.x = self.xpos self.image.center.y = self.ypos gearGroup:insert(self.image.center) -- Pinning the physics.addBody(self.image.center, "static") self.image.center.isSensor = true self.image.center.jointure = physics.newJoint("pivot", self.image.center, self.image, self.xpos, self.ypos) -- Loop, creating 4 "tooth bar" self.image.tooth = {} for i=1, 4 do -- Creating the bar self.image.tooth[i] = {} self.image.tooth[i].image = display.newRect(0,0,100,100) self.image.tooth[i].image.x = self.xpos self.image.tooth[i].image.y = self.ypos self.image.tooth[i].image.width = 68 \* self.size/512 self.image.tooth[i].image.height = 512 \* self.size/512 - (69\*0.5\*self.size/512)\*2 self.image.tooth[i].image:setFillColor(0,1,0) self.image.tooth[i].image.rotation = -45 + i\*45 + self.rotation gearGroup:insert(self.image.tooth[i].image) -- Adding physics physics.addBody(self.image.tooth[i].image, "dynamic", {bounce=GEAR\_BOUNCE, density=GEAR\_DENSITY, friction=GEAR\_FRICTION, filter=GEAR\_FILTER }); -- Creating a joint between the tooth bar and the "center" of the gear self.image.tooth[i].jointure = physics.newJoint("weld", self.image, self.image.tooth[i].image, self.image.x, self.image.y) -- Creating the rounded tooth of the "bars" local rayon = self.image.tooth[i].image.height\*0.5 - 3 local angle = -45 + i\*45 + self.rotation self.image.tooth[i].roundA = display.newCircle(0,0,68\*0.5\*self.size/512) self.image.tooth[i].roundA:setFillColor(1,0,0) self.image.tooth[i].roundA.x = self.xpos + rayon\*math.cos(math.rad(angle)) self.image.tooth[i].roundA.y = self.ypos + rayon\*math.sin(math.rad(angle)) self.image.tooth[i].roundB = display.newCircle(0,0,68\*0.5\*self.size/512) self.image.tooth[i].roundB:setFillColor(0,0,1) self.image.tooth[i].roundB.x = self.xpos - rayon\*math.cos(math.rad(angle)) self.image.tooth[i].roundB.y = self.ypos - rayon\*math.sin(math.rad(angle)) -- Adding the rounded tooth to the gear layer gearGroup:insert(self.image.tooth[i].roundA) gearGroup:insert(self.image.tooth[i].roundB) -- Add physics to the rounded tooth physics.addBody(self.image.tooth[i].roundA, "dynamic", {bounce=GEAR\_BOUNCE, density=GEAR\_DENSITY, friction=GEAR\_FRICTION, radius=68\*0.5\*self.size/512, filter=GEAR\_FILTER}) physics.addBody(self.image.tooth[i].roundB, "dynamic", {bounce=GEAR\_BOUNCE, density=GEAR\_DENSITY, friction=GEAR\_FRICTION, radius=68\*0.5\*self.size/512, filter=GEAR\_FILTER}) self.image.tooth[i].roundAJointure = physics.newJoint("weld", self.image.tooth[i].roundA, self.image, self.image.tooth[i].image.x, self.image.tooth[i].image.y) self.image.tooth[i].roundBJointure = physics.newJoint("weld", self.image.tooth[i].roundB, self.image, self.image.tooth[i].image.x, self.image.tooth[i].image.y) end ---------------------------------------------------------------------------------------------- -- SPAWNING CUBES AT THE TOP OF THE SCREEN ---------------------------------------------------------------------------------------------- spawnItemList = {} spawnItemCount = 0 local function spawnItems() spawnItemCount = spawnItemCount + 1 --local xpos = math.random(display.contentWidth) -- i tightened this up just cuz got tired of waiting for a collision, no other reason local xpos = math.random(display.contentWidth/3, display.contentWidth\*2/3) spawnItemList[spawnItemCount] = display.newRect(0,0,50,50) spawnItemList[spawnItemCount].x = xpos spawnItemList[spawnItemCount].y = 0 spawnItemList[spawnItemCount].isBullet = true physics.addBody(spawnItemList[spawnItemCount], "dynamic", {bounce=BOX\_BOUNCE, density=BOX\_DENSITY, friction=BOX\_FRICTION}) end local spawnTimer = timer.performWithDelay(500, spawnItems, 0)

@davidbollinger Hey, this is working perfectly ! Thanks a lot, now I’ll be able to do everything I wanted (change the gear / teeth size)

But I’d like to be sure to understand : my welds joints were wrong as I didn’t attach them to the right bodies (“weird puppet strings”) ? Is that what was preventing the teeth to collide correctly with other objects ?