Area collisions not detected

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Hanntac

Hi all!

Ok, so my lock-down project is a plant simulator. It grows, all is well except it eventually grows in itself. I was ready to crunch some Quats to avoid this, but the signals I expect from my Areas in case of entering areas are not even fired. I’m obviously doing something wrong but I can’t understand what.

That was confuse. I’m sorry.
I’ll go one step at a time.

Here’s where I connect signals, basically on the plant’s _ready():

$Internode/Area.connect("area_shape_entered", self, "_on_shape_entered")
$Internode/Area.connect("area_shape_exited", self, "_on_shape_exited")
$Leaf/Area.connect("area_shape_entered", self, "_on_shape_entered")
$Leaf/Area.connect("area_shape_exited", self, "_on_shape_exited")

Internode and Leaf meshes are generated, so I get their shape with a:

shape = multimesh.mesh.create_trimesh_shape()

Then I add this shape to the one Area per [Leaf/Internode].
In Leaf.gd:

func add(trans, color, custom):
	var owner = $Area.create_shape_owner(self)
	$Area.shape_owner_add_shape(owner, shape)
	$Area.shape_owner_set_transform(owner, trans)
	pinstances.append([trans, color, custom, owner])
	pmultimesh.set_instance_transform(count, trans)
…

The reason I’m doing this that way is for performance. Each plant element (node, internode, petiole, blade, etc.) is a Multimeshinstance node ; I tried previously to grow a plant with one mesh node per element and it was so slow (I suppose it was the time for each node to enter the tree). Anyway now each one of them is a single Multimeshinstance where I can change the visible_counter and it runs smoothly.
The downside is that I certainly must use only one Area per collidable element. So I digged into the doc and found you can assign multiple shapes per Area (see supra).

So. I’m not even sure leaves can collide between each other but I try that. And it doesn’t work.
I tried overriding shapes with SphereShapes, no luck.
I tried to add shapes using CollisionShapes, not better.
The only thing that worked was to add basic CollisionShapes to each Area in the editor, then the contact was registered. So I guess I’m mis-adding the shapes to the Areas, but an $Area.get_shape_owners() returns filled arrays.

I’m lost.

That was so confuse, here’s my (self-runnable) plant scene for reference: https://files.hanntac.net/s/gkd7Me3f8X3WR3B
Has anybody any idea what’s happening?

Thank you to have read that far!

:bust_in_silhouette: Reply From: Hanntac

I got it working. If anybody reads this, it won’t be short.

So. There was actually three problems:

Shape type

I don’t know why, but my leaves shapes won’t register unless they’re convex ones. Maybe because they’re like millimeters thin, or the way I generate them (I disable back culling, so it may be related to the mesh winding). Anyway, in Leaf.gd, I changed the code to create the shape from

shape = multimesh.mesh.create_trimesh_shape()

to

shape = multimesh.mesh.create_convex_shape()

Shape margin

Because they are so tiny, my leaves won’t trigger any collision with the default shape margin (https://docs.godotengine.org/en/3.2/classes/class_shape.html#class-shape-property-margin). I found a working one by fiddling around.
So right now, just after creating the leaf shape, I define its margin to:

shape.margin = 0.85

Below that, collisions won’t fire. Above, I got false positives. It should probably be a product of the leaves’ thickness or something, but you get the idea.

Signals don’t work

And finally, I don’t know why again, the signals won’t be emitted when shapes intersect. It may or may not work with KinematicBodies instead of Areas, I haven’t tested it yet. But I can ray-trace in the _physics_process(delta) function to retrieve informations about current collisions using:

var space_state = node_leaf.get_world().direct_space_state
var result = space_state.intersect_ray(transform.origin, target, [], 2147483647, true, true)

See the doc (https://docs.godotengine.org/en/3.2/classes/class_physicsdirectspacestate.html#class-physicsdirectspacestate-method-intersect-ray) to set correct arguments. Basically, I currently check everything (physicbodies as well as areas) on every collision layer without excluding anything. It certainly can and will be optimized. Also it may not be the best method to call for my use case, but again, you get the idea:
Signals may not be emitted on Area intersections, you may have to work around this.

Conclusion

That’s all, I hope it will help somebody. Have a nice day!

You are an angel in my life. Thanks for the explanation!

giggio_abeni | 2021-07-13 21:42