godot
godot copied to clipboard
Problem with Area2D, body_entered signal and Tilemap in a .NET version
Godot version
v4.0.stable.mono.official [92bee43ad]
System information
Windows 10, Vulkan API 1.3.224, Forward+, NVIDIA GeForce GTX 1660 SUPER
Issue description
Problem with Area2D signal and Tilemap. Can be reproduced in the C# version.
When the signal body_entered of the Area2D attached to code and being fired by colliding Tilemap, this error appears:
System.Object System.Runtime.CompilerServices.CastHelpers.ChkCastAny(System.Void* , System.Object ): System.InvalidCastException: Unable to cast object of type 'Godot.TileMap' to type 'Godot.PhysicsBody2D'.
<Error C++> System.InvalidCastException
<Source code C++>:0 @ System.Object System.Runtime.CompilerServices.CastHelpers.ChkCastAny(System.Void* , System.Object )
<Stacktrace>:0 @ System.Object System.Runtime.CompilerServices.CastHelpers.ChkCastAny(System.Void* , System.Object )
VariantUtils.generic.cs:385 @ T Godot.NativeInterop.VariantUtils.ConvertTo<T >(Godot.NativeInterop.godot_variant& )
Projectile_ScriptMethods.generated.cs:34 @ Boolean Projectile.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.NativeVariantPtrArgs , Godot.NativeInterop.godot_variant& )
CSharpInstanceBridge.cs:24 @ Godot.NativeInterop.godot_bool Godot.Bridge.CSharpInstanceBridge.Call(IntPtr , Godot.NativeInterop.godot_string_name* , Godot.NativeInterop.godot_variant** , Int32 , Godot.NativeInterop.godot_variant_call_error* , Godot.NativeInterop.godot_variant* )
Can be stable reproduced even in a new empty project. Maybe I get something wrong, but looks like a bug.
Steps to reproduce
- Create Tilemap on the scene, fill it with premade Tileset resource
- Add new Physics layer, setup physics for any tile, paint this tile on the scene.
- Create C# script, derive it from the Area2D. Add a new method to receive body_entered signal.
- Attach script to the Area2D node.
- Attach body_entered signal to the receive method.
- Place this area near painted tilemap on scene.
- Hit play and you will receive error after signal will be fired.
Minimal reproduction project
This is expected behavior. The signal body_entered
takes a Node2D
parameter:
https://github.com/godotengine/godot/blob/5dccc940e73d39a1ac4f3d64ccc92373e6609add/doc/classes/Area2D.xml#L157-L162
But your method is declared as follows:
public void OnSomeBodyEntered(PhysicsBody2D body);
When the signal is emitted with a body of a different Node2D
type, as is the case with TileMap, the parameter can't be converted so an exception is thrown. This is how OOP works.
graph TD;
Node-->CanvasItem-->Node2D-->CollisionObject2D-->PhysicsBody2D;
Node2D-->TileMap;
As you can see in the diagram there's no way to go from the TileMap
type to the PhysicsBody2D
type. Note how the signal's description says (emphasis mine):
Emitted when the received
body
enters this area.body
can be aPhysicsBody2D
or aTileMap
.TileMap
s are detected if theirTileSet
has collision shapes configured. Requiresmonitoring
to be set totrue
.
This means, in order for the method to work with both, it needs to use a common ancestor. That's why the signal is defined taking a body parameter of type Node2D
.
Yeah, I should've paid more attention to it, missed thing. Sorry for wasting your time.