Godot version:
Godot_v3.0.3-rc3_mono_win64
OS/device including version:
Windows 10
Issue description:
Scene containing CollisionShape2D throws errors when added to SceneTree asynchronically.
0:00:06:0396 - Index p_index=0 out of size (shapes.size()=0)
----------
Type:Error
Description:
Time: 0:00:06:0396
C Error: Index p_index=0 out of size (shapes.size()=0)
C Source: servers/physics_2d/collision_object_2d_sw.cpp:68
C Function: set_shape_transform
0:00:06:0403 - Index p_shape_idx=0 out of size (body->get_shape_count()=0)
----------
Type:Error
Description:
Time: 0:00:06:0403
C Error: Index p_shape_idx=0 out of size (body->get_shape_count()=0)
C Source: servers/physics_2d/physics_2d_server_sw.cpp:701
C Function: body_set_shape_disabled
0:00:06:0411 - Index p_shape_idx=0 out of size (body->get_shape_count()=0)
----------
Type:Error
Description:
Time: 0:00:06:0411
C Error: Index p_shape_idx=0 out of size (body->get_shape_count()=0)
C Source: servers/physics_2d/physics_2d_server_sw.cpp:710
C Function: body_set_shape_as_one_way_collision
When added synchronically or when added asycnchronically, but without CollisionShape2D node, everything works as expected.
Steps to reproduce:
Create a Loader scene with with single node containing the following code:
using System;
using System.Threading.Tasks;
using Godot;
public class Loader : Node
{
public override void _Ready()
{
// Doesn't work
this.LoadSceneAsync();
// Works
//this.LoadScene();
}
private async void LoadSceneAsync()
{
await Task.Run((Action)this.LoadScene);
}
private void LoadScene()
{
var scene = (PackedScene)GD.Load("res://Hero.tscn");
var node = scene.Instance();
this.CallDeferred(nameof(this.AddNode), node);
}
private void AddNode(Node node)
{
this.GetTree().GetRoot().AddChild(node);
}
}
Create another scene res://Hero.tscn with KinematicBody2D as a root node and two child nodes Sprite and CollisionShape2D.
Minimal reproduction project:
Test.zip
Adding nodes to the tree needs to be done on the main thread.
Looks like a duplicate of #17674.
Had the same issue today
extends Node2D
var loader_thread
func testcol(data):
for x in range(10):
var a = Area2D.new()
var cs = CollisionShape2D.new()
var rect = RectangleShape2D.new()
var m = MeshInstance2D.new()
rect.extents = Vector2(100,100)
cs.shape = rect
a.add_child(m)
a.set_process(true)
a.add_child(cs)
#add_child(a)
call_deferred("add_child",a)
func _ready():
loader_thread = Thread.new()
loader_thread.start(self,"testcol")
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass
Isn't call_deferred supposed to queue the function on the main thread?
The strange thing is that it works fine if I call it FROM the thread and it throws errors if I defer it
Workaround: You can export the collision shapes you want to use and assign them in the _ready function of the node you are trying to add with the deferred add_child.
I think this should be documented as a known limitation, I don't think this is supported.
I have the same issue with my zone loading system, and I have the same question as @puthre, I use call_deferred to add the child nodes, so it should add it in the main thread.
What is weird is that I have this issue only if the zone is loaded at startup, it works without error if the zone is loaded afterwards. Also in 3D I don't have this issue at all.
I fixed the issue using a workaround:
get_tree().create_timer(0.0).connect("timeout", self, "attach_zone", [zone_id, instance])
creating a timer in the tree to trigger the zone attachment in the main thread, I don't know if there is a better way to solve this issue, weirdly call_deferred doesn't seem to work.