godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.07k stars 69 forks source link

Allow RigidBody to have Colliders that are indirect children, not just direct children #535

Open aaronfranke opened 5 years ago

aaronfranke commented 5 years ago

Describe the project you are working on:

I would like to create a voxel game where the objects' collisions are composed of many cube colliders. I can't use concave mesh colliders because I would like these voxel objects to be able to move.

Describe the problem or limitation you are having in your project:

The problem is that, while I can easily generate cube colliders, I have no good way to remove groups of them whenever I need to regenerate a "chunk".

Describe the feature / enhancement and how it helps to overcome the problem or limitation:

What I would like to do is have several of these cube colliders together as children of a child so that I can easily remove/generate/instance them as needed.

RigidBody
    Collider0
    ColliderGroupA
        Collider1
        Collider2
    ColliderGroupB
        Collider3
        Collider4

In the example above, in the current stable and master branch of Godot, only Collider0 is detected, and without it the RigidBody complains that it has no collider. It seems that colliders are only used if they are direct children.

Ideally, RigidBody should be able to use colliders that are grandchildren etc and not just direct children. This would make it easier for me to instance, generate, and delete groups of colliders. Basically, the RigidBody should recursively search its children for CollisionShape nodes, so that in the example above, it would use all of the colliders (0 through 4).

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:

One issue that would arise from just recursively searching for collider children is that physics objects parented to physics objects would both use the child's colliders. There are many possible implementations that would solve this without that problem:

EDIT: Actually, the way Godot implements these nodes is that CollisionShape3D looks up the tree, so there is no problem. We can simply have the CollisionShape3D search up until it finds a CollisionObject3D node, then stop.

If this enhancement will not be used often, can it be worked around with a few lines of script?:

Possibly, but not nearly as clean. I really don't want to short-circuit the node hierarchy.

Is there a reason why this should be core and not an add-on in the asset library?:

This is a low-level feature that could not be implemented very well by an add-on.

See: https://godotengine.org/qa/31701/possible-rigidbody-have-colliders-that-not-direct-children

Bugsquad edit (keywords for easier searching): subchildren, subchild

Hendrikto commented 5 years ago

A problem I see here is that you may not always want this. Imagine your character is holding some item with its own Collider. If you shoot at the character, you don't want a hit on the item to count as a hit on the character.

How would Godot know which Colliders to consider?

aaronfranke commented 5 years ago

@Hendrikto There are many possible solutions to this:

EDIT: Actually, the way Godot implements these nodes is that CollisionShape3D looks up the tree, so there is no problem. We can simply have the CollisionShape3D search up until it finds a CollisionObject3D node, then stop.

aaronfranke commented 5 years ago

Note: Not the same as https://github.com/godotengine/godot/issues/7793, which proposes a feature called "Collision Groups" related to collision layers and masking, but my issue is about compounding colliders.

ripperdave commented 4 years ago

I have the same problem. I wanted to create damageable wall.

KoBeWi commented 4 years ago

I have complex maps that are StaticBody2Ds with lots of colliders and also children that are objects. Having an ability to group colliders to clean the mess would be very welcome.

CompoundCollider solution sounds nice.

KoBeWi commented 4 years ago

So I was going to make a proper proposal for this feature, but wanted to try one thing first and found a workaround for my use case.

extends Node2D

func _ready() -> void:
    for collider in get_children():
        call_deferred("move_collider", collider)

    queue_free()

func move_collider(collider: Node2D):
    remove_child(collider)
    get_parent().add_child(collider)

Just put your colliders under a node with above script and it will work perfectly. The only downside is warnings in the scene tree and probably a very slightly longer scene loading time.

aaronfranke commented 4 years ago

@KoBeWi In my case I'd like to be able to delete groups of colliders at runtime. I would prefer to not have to store a separate data structure keeping track of what group each collider is a part of.

AndreaCatania commented 4 years ago

Consider that by default we are using compound under the hood, and I prefer to not add a node of this kind to allow recursive search.

A shape may have the possibility to find the physics body owner recursively, even when a physics body contains another one: The shape will stop its search soon it found its owner.

Physics body
|--Node
|    |- Shape
|
| -- PhysicsBody 2
|       |--Node
|            |- Shape
jcarlosrc commented 4 years ago

So, in current implementation a kinematicBody basically disables all collision shapes below, (indirect children) true? Is there a way we can enable them in code?

madmiraal commented 3 years ago

What I would like to do is have several of these cube colliders together as children of a child so that I can easily remove/generate/instance them as needed.

RigidBody
Collider0
ColliderGroupA
Collider1
Collider2
ColliderGroupB
Collider3
Collider4

This is how a CollisionPolygon currently works. It is a CollisionObject that contains multiple shapes (whereas a CollisionShape is a CollisionObject that just holds one shape). Instead of the above layout, what you actually currently have is:

RigidBody
Collider0
Shape0
Collider1
Shape0
Shape1
Collider2
Shape0
Shape1

You can create your own using the CollisionObject API API. Create a shape_owner using create_shape_owner(), then add multiple shapes to it using shape_owner_add_shape().

AndreaCatania commented 3 years ago

In a recent project, one of the most common behaviors was adding a lot of shapes per single Physics Body; this was causing some performance issues, since the broad phase was not able to properly do its job.

Add 1 shape per Physics Body should be the way to go (unless you want to decompose a complex body shape to multiple convex shapes). This proposal would encourage put more shapes per body even more.

While initially I supported this feature, I think we should reconsider it, so to better guide the user.

KevinTriplett commented 3 years ago

@AndreaCatania so if best practice for performance is one shape and one CollisionObject, then when @aaronfranke wants to add a group of shapes (shapes from a group of new children) then iterate through the children and add each child's shape using shape_owner_add_shape with the owner_id created from each child?

Then, to remove a group of shapes (removing a group of children) use the shape_owner_remove_shape with each child's owner_id?

This would mean storing both the owner_id and shape_id (which I assume is the int returned by shape_owner_add_shape)?

Is that the process you would recommend?

AndreaCatania commented 3 years ago

Yes, thats sounds ok. Bullet is really performant, though I doubt that its architecture allows you to achieve what you want.

A voxel game should have million little boxes, colliding each other, if thats the case You should consider optimizing at least its memory model (I can expand this more if you want) though other solutions may be more effective.

KevinTriplett commented 3 years ago

Thanks for the quick reply -- maybe not for Andrea but in my use case it may work out: I want a KinematicBody (doer) to grab another KinematicBody (victim) and start whirling it around, smashing it into things. If the victim is a child of doer, it's automatically transformed by doer's rotations which is what I want. The problem was that victim collisions weren't happening.

memphis88 commented 3 years ago

You can create your own using the CollisionObject API API. Create a shape_owner using create_shape_owner(), then add multiple shapes to it using shape_owner_add_shape().

Thanks @madmiraal, that helped my use case which I couldn't find a solution for and I have a feeling it is somewhat common (I'm mostly referring to the limitation of shapes requiring to be direct children of PhysicsBody). To elaborate, I wanted to have my collision shape attached to a bone so that it follows the animation of my player in jumps etc, (see screenshot). image

Wokarol commented 1 year ago

While creating my own issue, I failed to search for this one. Sorry for that.

Is there any information as of recently about possibility of this feature being added as that really is a problematic limitation for any complex character or actor?

Shadowblitz16 commented 1 year ago

Can we get this for CollisionObject2D and CollisionObject3D? instead of RigidyBodys?

aaronfranke commented 1 year ago

@Shadowblitz16 Yes. That's what the PR I made does: https://github.com/godotengine/godot/pull/77937

ctrlraul commented 3 months ago

I have an use case where the amount of shapes is dynamic, they also need to be re-ordered, added, removed... Having a node to group for them would be extremely helpful as to not conflict with the other nodes in the rigid body (Like sprite, etc...)

StoqnS14 commented 2 months ago

PLEASE ADD THIS PLEASE PLEASE PLEASE PLEASE I WANT THIS I NEED THIS