How can I speed up multiple (1000+) instanciation of a scene containing a CollisionShape2D?

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

I got a grid of squares. Each square can be interacted with through an Area2D. An Area2D has a CollisionShape2D (with a Shape2D) as a child.

Problem: Adding children is increasingly slow. Each time I add a child, it takes more time than the preceding added child to complete. You can see the slow down quickly. I was expecting that each use of add_child would take the same amount of time to complete but this is currently not linear.

Question: How can I add a large amount (1000+) of children containing a CollisionShape2D quicker.

As a minimal example, to demonstrate my problem, my project structure is like so:


Main.tscn
Node2D (with Main.gd)


Main.gd

extends Node2D


var added_scene = preload("res://AddedScene.tscn")
var batch_count :int = 0


func _process(delta):
	if batch_count < 30:
		for i in 100:
			var new_added_scene = added_scene.instance()
			add_child(new_added_scene)
		print(batch_count)
		batch_count += 1

AddedScene.tscn
Node2D
----> Area2D
-------->CollisionShape2D


I tried multiple things:

  • Adding children in batch (see example above)
  • Adding all children in _ready()
  • Instead of using a CollisionShape2D node I added the collision through code. I’m not sure if I did it properly but the result is the same:

func _ready():
	var collision_shape :RectangleShape2D = RectangleShape2D.new()
	collision_shape.extents = Vector2(243, 243)
	var shape_owner :Node2D = Node2D.new()
	shape_owner.position = Vector2(243, 243)
	var shape_owner_id = $Area2D.create_shape_owner(shape_owner)
	$Area2D.shape_owner_add_shape(shape_owner_id, collision_shape)
:bust_in_silhouette: Reply From: chesse

Hello lapinchatware,

I can’t tell you exactly why your problem is occurring, but I tried it out and i can see the effect you are decribing . What I also saw is that the memory consumption of the scene grows to over 8GB. I was able to fix the problem by giving every Area2D its own position in space

By adding

new_added_scene.position += Vector2(i*10,batch_count*10)

every node get his own position and doesn’t collide with another.

So i would guess that godot resolve all the collision that are created and with 3000 collision its a little bit to much.

so i changed your script to

extends Node2D


var added_scene = preload("res://AddedScene.tscn")
var batch_count :int = 0


func _process(delta):
	if batch_count < 30:
	    for i in 100:
			var new_added_scene = added_scene.instance()
			new_added_scene.position += Vector2(i*10,batch_count*10)
			add_child(new_added_scene)
		print(batch_count)
		batch_count += 1
		

and it bassicly takes 2 seconds now

I think your guess is spot on! The speed is outstandingly fast (<1s). In my real project, instead of giving a position before adding the instance to the tree, I simply set the property disabled of the CollisionShape2D to true in the original scene and when I’m done processing everything I `CollisionShape2D.set_deferred(“disabled”, false) each instance.

Thank you @chesse. This really helped me.

lapinchatware | 2022-01-05 03:43