godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Expose Collision Shape Nodes' owner_id for scripting #6179

Open iiMidknightii opened 1 year ago

iiMidknightii commented 1 year ago

Describe the project you are working on

A city building game that needs to create collision shapes on the fly. This includes adding/removing shapes programmatically, then testing which shape in an Area3D was hit by a ray intersection.

Describe the problem or limitation you are having in your project

Currently, when doing a ray intersection (or any intersection test), the resulting dictionary (or input event signal) provides a shape index for the shape that was hit. That can be used with CollisionObject's shape_find_owner to get the owner ID for the hit shape. As of right now, there isn't any easy way to convert that owner ID into which CollisionShape or CollisionPolygon node has the node. For example, say I have an array of 3 shapes added with IDs [0, 1, 2]. At first, it's trivial to find the node that was intersected, since the owner ID returned matches the array index. But if I free shapes[0] and add another new shape to the array, the IDs will be [1, 2, 3]. It gets more difficult to keep track of if a node is freed in the middle of the array, which for example would be [1, 3, 4] after adding a new shape.

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

Both those classes (in 2D and 3D) have a protected member called owner_id, which would be helpful to find the correct node. If owner_id was exposed to scripting, it would be as simple as calling

var owner_id = shape_find_owner(shape_idx) 
var hit_node
for n in shape_nodes:
    if (owner_id == n.get_owner_id()):
        hit_node = n
        break

where shape_nodes is the array of programmatically constructed CollisionShapes.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Not sure what the process for exposing a property of a node to scripting looks like. I would imagine it would be a read-only property. Or it could be added as a method called get_owner_id.

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

I am aware that the shapes could be created, owned, transformed, etc. using the methods in CollisionObject, but I'm attempting to extend CollisionShape3D into a new class that can keep track of sprites, meshes, etc. for editing curves, object positions, etc. It's just way simpler to have an extended class to handle all that than have one giant CollisionObject class keeping track of many different shape transforms, sprites, etc. all at once.

I also know that it is possible to keep an array of owner_ids in the CollisionObject and try to manually sync it up whenever a shape is added or removed. The problem with that is anytime a shape may be added/removed (even temporarily) without updating the array (e.g. from outside the class), it throws that array out of sync permanently.

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

This is a core feature of the physics shape manipulation process.

berarma commented 1 month ago

This part of the API is really confusing. The editor and the GDScript API seem to have very different opinions on how it should be done. I don't know if there's any solid reason for the differences. A new API that matched owners to CollisionShape objects would really help. In this way, CollisionShape could be more than just a container and hold many of the methods in CollisionObject2D providing a more understandable API that it's easier to use.