How to access the shape (or get info about it) in the signal body_enter_shape()

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By cardoso
:warning: Old Version Published before Godot 3 was released.

I am using the body_enter_shape ( int body_id, Object body, int body_shape, int area_shape ) signal to try to know which shapes are overlapping.

But in the function, area_shape or body_shape vars are just integers (which i suppose is the shape order in the parent node of the shape?).

Is there a way to to know the shape name (or other info like the extents)?

:bust_in_silhouette: Reply From: Zylann

In Godot 2, shapes are not nodes when you run the game. CollisionShape nodes are editor-only helpers, even if they are present when you debug it, they are stripped out when exported so you should not rely on them from script.

Instead, the actual shapes are accessed using an API on CollisionObject2D: CollisionObject2D — Godot Engine (2.1) documentation in English
Note that Area2D, RigidBody2D or StaticBody2D inherit CollisionObject2D, so they have these functions too.

As you can see, there are functions to query shapes from their index, which is what you get in your function.

I never used this, but I guess you would have to do do something like:

if body extends Area2D:
	var shape = body.get_shape(area_shape)

Thanks, that was what I was looking for (or I thought so).
Even though I have used node.get_shape().get_extents(), I had no idea get_shape() could accept a shape index as a parameter.

It looked promising!

Unfortunatly it does not to solve my problem. I would need to detect which shapes are overlapping based on the names or something like that - and shape .get_name() is not returning anything (cause I guess like you said the actual shapes are not the editor representation).

So in the end what I need is not the shape itself, but the node “editor-only helper” of it.

cardoso | 2017-05-08 20:47

If you need to identify them, you can probably do it by their index. If the shape is child number X, its index might be equal (“might” because I never tested it).
Another way is to use layers to separate collision detections (but you would have to change your code a bit).
Or, if you really want names, make two Area2D.

Zylann | 2017-05-08 22:26

Yeah, I ll go with two Area2D.
I am currently using the index to identify them. But seems very easy to “break”, if new shapes are created/removed.
Thanks :slight_smile:

cardoso | 2017-05-08 23:47

I noticed that if you get the shape, you also have to account for the parent body’s scale. So it is not enough to get the shape, you might have to multiply something like its radius (for a circle) by the parent’s scale.

Judd Gledhill | 2018-08-24 01:15

Note: this answer was for Godot 2, I edited the post now. In Godot 3 you can access the shape nodes directly.

Zylann | 2018-08-24 18:13

:bust_in_silhouette: Reply From: rredesigns

Just an idea, since I didn’t test this, but what if you do a shape.get_parent().get_name() or get_RID instead of name?

Unfortunatly it does not work, get_parent() and get_RID() are “nonexistant functions” of the shape.

cardoso | 2017-05-09 10:30

Well, all objects have properties, so you can issue a get_property_list() and print it to see if there’s anything useful there that you can use to identify the node. The method returns an array of dictionaries, so it should be easy to read.

rredesigns | 2017-05-10 04:24

:bust_in_silhouette: Reply From: Ratty

I was getting a similar issue using “_integrate_forces” - “state.get_contact_local_shape({contact})” just returns an integer so it was difficult to work out which shape was causing the collision.

Then I found that the integer returned seems to be the index of the shape, which it is possible to get. So, for instance, to test if my circle shape is the cause of a contact I do:

if state.get_contact_local_shape(x) == $Collision_Circle.get_index():
    ...etc

Alternatively, if you have several shapes, you could store a lookup in “func _ready:”.

EDIT: Nope, the number returned from get_contact_local_shape does not appear to be consistent with get_index, it just happened to coincide in my tests (for a while that is, then it broke). Sorry.

Hope this helps :slight_smile:

:bust_in_silhouette: Reply From: Cavernagame

Hi you know I was reading the godot documentation and looking at the answers and this occurred to me.

I use area_shape_entered (int area_id, Area2D area, int area_shape, int self_shape) which is similar to body_enter_shape () but returns me is the shape of the area. In order to get some value from the parent node. Start climbing with get_parent () until you reach the parent node.

Example

var collision_name = area.shape_owner_get_owner(shape_find_owner(area_shape))

var area_name = collision_name.get_parent() #with this I get to the area2d which is the father of the collisionshape

var node_name = area_name.get_parent().get_name() #with this I get the name of the node that is the father of everything.

#and it could get any variable it exports to the node.

espero te sirva.
Desde la caverna me despido

Subir