Compound Parenting vs Rigid Body Joints?

Hi,

I’m looking for the best way to be able to have a collection of objects move together as one mesh, but be able to split apart if I need them to. Say for instance I had a stack of blocks, each connected to the block below it. if the bottom block is removed, the ones above it fall down, while still connected to each other like a single object. Almost like this:
ezgif-4-2fc06ce05829
Or deleting from the center:

Rigid Body Joints (Which is what I used in the gifs) do pretty much everything I want; but they take up lots of memory in larger groups. The bigger the group, the laggier; and the more the whole thing starts to behave like a softbody - or whatever this is:

Compound parenting succeeds where RBJs fail. As far as the simulated physics is concerned, the collection of objects is a single mesh.

But with parenting, you can’t remove any of the parent constraints, or delete the parent (like in the top two gifs). Trying to do so either freezes the children in place, or removes them.

Is there a way I could make a RBJ-constrained group of objects simulate as one object, or remove parenting without affecting children/grandchildren?

Thanks!

Did you check on the Parent actuator? I think it can do exactly what you want, but potentially with restrictions. Here is a minimal *.blend:

BGE_Physics_Parent.blend (522.1 KB)

On Start-Up, I am parenting the two of the red cubes on the right to the other red one. An event (here: Press SPACE) the parent-child relation is splitted again.

Atterntion: I observed in an earlier experiment, that this does not let the center of gravity move properly. In the above example (two cubes far from parent cube), the combined object should fall over to the two red ones. It does not. If you want to achieve such effect, there seems to be no way around the rigid body joints.

Enjoy!

PS: I have never seen people use the abbreviation RBJs before…I suggest to write the full name if you want people to read what you post.

Thanks! Edited the title.

I have tried the Parent actuator, and while it works perfectly with just child and parent (despite the center of gravity being off), the children-of-children still freeze when un-parented.

Is there a way to separate it again, despite it being parented to another parented object? And have its children still attached?

I can not confirm this (BGE 2.79b, not UPBGE!). To the above example, I have added a green cube, which is parented to one of the red ones, giving us two-levels of hierarchy: grandchilrdren.

BGE_Physics_Parent.blend (545.8 KB)

Splitting either chilrdren (red ones with SPACE) or grandchildren (green one, with A) works as expected for me, regardless of the order.

Edit: When playing around a bit more, I discovered that all objects in hierarchy disappear as well if you end an object, which you also described above. A workaround maybe done with Python, when you unparent all the children before ending the object.

True, but it only works if Compound is not enabled for the grandchild (and everything else). As it stands, both the children and grandchildren are ghosts and cannot collide with anything.

With Compound enabled, splitting the grandchild suspends its physics.

make a single object (empty physics type) in upbge and parent all the cubes to it

on impact decide what breaks off and reparent / add a new compound root object.

here is a bit of a headache though - each empty /compound root added from a hidden layer will have all the physics shapes of all the copies of it currently in the scene -

a work around is to unparent all -> add new root -> reparent all

Solved it!!!
Turns out enabling ‘Compound’ on both the actuator and in the Properties panel were redundant, and were what made the children freeze. Guess they were just redundant.

Thank you @AeroLynx and @BluePrintRandom for your help!

It seems I spoke too soon…
It looks like the parented objects do have collision enabled, but the collisions don’t contribute to the parent’s movement/rotation.
For example:

When the blue cube hits the children, it moves, but the collection does not. this means all the parented objects are doing is just staying relative to the parent, and will likewise move straight through static objects like ghosts.
The only way to prevent this is by enabling ‘Compound’ on the parent and children:

But as I said before, this is exactly what makes the children freeze upon de-parenting.

Not sure where to go from here. Is there any way to make this work properly?

only the root needs marked compound.

the root can be a empty placed at the center of gravity of the collection.

if you spawn another copy though you run into ‘compound ghost shapes’ but I have a work around for that as well
@Thatrius

each frame you can unparent / move / reparent the child shapes for actors with complex collision shapes like actors

What if all the cubes being parented are instances of the same object? Is there a way to mark an individual cube as ‘Compound’ from within bge?

all the cubes are child shapes, only the root object needs to be compound.
this way you can also move the center of gravity as well*

(make the root a empty child shape object marked compound)

it absorbs those child shapes.

do you need a demo?

This almost works, but it looks like children-of-children still can’t be affected by collisions. Only the root’s direct children contribute to the collision bounds.

If I try and parent all the cubes to the root, I won’t be able to automatically split pieces that are disconnected.

yeah you need to use math to do this*

you can get the contact point using the collision callbacks,

What command could I use to get the contact points on collision, and how would I use that information to set the velocity of the root object?

Did some researching on collision callbacks, and found this script:

def on_colliding(other, point, normal):
    print("Colliding with %s at %s with normal %s" % (other, point, normal))

own.collisionCallbacks.append(on_colliding)
print (own.collisionCallbacks)

…I haven’t a clue how it works, though. The whole function just prints variables that didn’t even exist before, and trying them directly - own.collisionCallbacks.append(other, point, normal) - prints an error…

When the script is run, it returns this nice, long list that I make even less sense out of…

[<function on_colliding at 0x0000017DC3DDC950>, <function on_colliding at 0x0000017DC3DDCB70>, <function on_colliding at 0x0000017DC3DDCBF8>, <function on_colliding at 0x0000017DC3DDCC80>, <function on_colliding at 0x0000017DC3DDCD08>, <function on_colliding at 0x0000017DC3DDCD90>, <function on_colliding at 0x0000017DC3DDCE18>, <function on_colliding at 0x0000017DC3DDCEA0>, <function on_colliding at 0x0000017DC3DDCF28>, <function on_colliding at 0x0000017DC3DE5048>, <function on_colliding at 0x0000017DC3DE50D0>, <function on_colliding at 0x0000017DC3DE5158>, <function on_colliding at 0x0000017DC3DE51E0>, <function on_colliding at 0x0000017DC3DE5268>, <function on_colliding at 0x0000017DC3DE52F0>, <function on_colliding at 0x0000017DC3DE5378>, <function on_colliding at 0x0000017DC3DE5400>, <function on_colliding at 0x0000017DC3DE5488>, <function on_colliding at 0x0000017DC3DE5510>, <function on_colliding at 0x0000017DC3DE5598>, <function on_colliding at 0x0000017DC3DE5620>, <function on_colliding at 0x0000017DC3DE56A8>, <function on_colliding at 0x0000017DC3DE5730>, <function on_colliding at 0x0000017DC3DE57B8>, <function on_colliding at 0x0000017DC3DE5840>, <function on_colliding at 0x0000017DC3DE58C8>, <function on_colliding at 0x0000017DC3DE5950>, <function on_colliding at 0x0000017DC3DE59D8>, <function on_colliding at 0x0000017DC3DE5A60>, <function on_colliding at 0x0000017DC3DE5AE8>, <function on_colliding at 0x0000017DC3DE5B70>, <function on_colliding at 0x0000017DC3DE5BF8>, <function on_colliding at 0x0000017DC3DE5C80>, <function on_colliding at 0x0000017DC3DE5D08>, <function on_colliding at 0x0000017DC3DE5D90>, <function on_colliding at 0x0000017DC3DE5E18>, <function on_colliding at 0x0000017DC3DDC8C8>, <function on_colliding at 0x0000017DC3DDC840>, <function on_colliding at 0x0000017DC3DDC7B8>, <function on_colliding at 0x0000017DC3DDC730>, <function on_colliding at 0x0000017DC3DDC6A8>, <function on_colliding at 0x0000017DC3DDC620>, <function on_colliding at 0x0000017DC3DDC598>, <function on_colliding at 0x0000017DC3DDC510>, <function on_colliding at 0x0000017DC3DDC488>, <function on_colliding at 0x0000017DC3DDC400>, <function on_colliding at 0x0000017DC3DDC378>, <function on_colliding at 0x0000017DC3DDC2F0>, <function on_colliding at 0x0000017DC3DDC268>, <function on_colliding at 0x0000017DC3DDC1E0>, <function on_colliding at 0x0000017DC3DDC158>, <function on_colliding at 0x0000017DC3DDC0D0>, <function on_colliding at 0x0000017DC3DDC048>, <function on_colliding at 0x0000017DC3DD5F28>, <function on_colliding at 0x0000017DC3DD5EA0>]

…at every logic tick.

Is there some way to implement any of this?
Thanks!

yeah, i do callbacks all the time. but the issue is knowing python data structure to effectively use it.

the callbacks is a list of functions that the engine execute on each detected hitpoint. when the functions are run, it passes the object, point, and normal variables as arguments.

a function is def mything(arg):

to make mything() run on each hit point, you need to append the function name. .append(mything)

running a function means putting () after the name. the arg is a argument, something the inside of a function can see. these are optional.

But where does on_colliding() get the values for ‘other’, ‘point,’ and ‘normal’?
If collisionCallbacks is just an empty list that returns ‘[]’ by default, how does merely appending a function (with no input values, might I add) suddenly return a massive logfile?

From my understanding of Python, one calls a function with parentheses containing however many input values. say, on_colliding(1,2,3).
Then, the function takes those values and uses them to complete - in this case - the following command:

print("Colliding with %s at %s with normal %s" % (other, point, normal))

since other = 1, point = 2, and normal = 3, the function should always return:

Colliding with 1 at 2 with normal 3

-which isn’t very useful, as ‘point’ is the value I’m trying to find in the first place.

But own.collisionCallbacks.append(on_colliding) doesn’t print any of that. And since on_colliding() is drawing on values from collisionCallbacks (which -again - returns ‘[]’ by default), where in the world is it getting all the information it spits out, and why do I need the function in the first place?

And more importantly, how does one possibly derive the collision hitPosition from the output?

the physics engine delivers the values, and the api sends them as arguments.

be sure to only append once, otherwise you will run many of the same function per hit causing a big performance hit.

the function should pass the args to an object property or global variable

But I don’t see “Colliding with %s at %s with normal %s” printed anywhere in the output…

Where might I find the value of ‘point’?