I have a node that is 128x128 in size, and I want it to cover the entire scene in instances of itself, but it should only generate if a certain distance from the player (so it doesn't lag)
All of these nodes have to end up as a child of a YSort node after generation, so using a Node2D to spread them around got very confusing really quickly, and many solutions ended up spamming signals so much that the game was nearly unplayable.

How can I cover everything with instances of this node, and have them end up children of a YSort without lagging the game too much

  • Well, this is one way you could do that.

    extends Node2D
    # a simple demo node
    
    
    const FAR_AWAY = 500  # far enough from player
    const ROOM_SIZE = 128
    
    
    var player:Node2D
    var rp_timer:Timer
    var win_size:Vector2
    var ysort:YSort
    
    
    func _ready() -> void:
    	randomize()
    
    	# Get the window size.
    	var vp:Viewport = get_node('/root')
    	win_size = vp.size
    
    	# Make a ysort.
    	ysort = YSort.new()
    	add_child(ysort)
    
    	# Make a pseudo-player.
    	player = Node2D.new()
    	var pos = Vector2(randi() % int(win_size.x - ROOM_SIZE), randi() % int(win_size.y - ROOM_SIZE))
    	player.position = pos
    
    	# Show where the player is.
    	var cr := ColorRect.new()
    	cr.rect_position = player.position
    	cr.rect_size = Vector2.ONE * 32
    	cr.color = Color.white
    	add_child(cr)
    
    	# Make a timer.
    	rp_timer = Timer.new()
    	rp_timer.one_shot = false
    	rp_timer.wait_time = 0.1
    	rp_timer.connect('timeout', self, 'rp_timer_timeout')
    	add_child(rp_timer)
    	rp_timer.start()
    
    
    func rp_timer_timeout():
    	# called when the timer times out
    
    	# Get a random location.
    	var pos = Vector2(randi() % int(win_size.x - ROOM_SIZE), randi() % int(win_size.y - ROOM_SIZE))
    
    	if pos.distance_to(player.position) < FAR_AWAY \
    	or (pos + Vector2.ONE * ROOM_SIZE).distance_to(player.position) < FAR_AWAY:
    		# It's too close to the player.
    		return
    
    	# Check that rooms don't overlap.
    	var nrect := Rect2(pos, Vector2.ONE * ROOM_SIZE)
    	var inter := false
    	for c in ysort.get_children():
    		var orect := Rect2(c.rect_position, c.rect_size)
    		if orect.intersects(nrect):
    			inter = true
    
    	# Make a pseudo-room (color rectangle).
    	if not inter:
    		var cr := ColorRect.new()
    		cr.rect_position = pos
    		cr.rect_size = Vector2.ONE * ROOM_SIZE
    		cr.color = Color.red
    		ysort.add_child(cr)

The easiest solution is to add them very slowly, possibly on a timer. However, a lot of sorted nodes, even off-screen, could still slow the game down.

You have to track their position somehow. Node2D's shouldn't be any more confusing than any other way. You might want to give some more information on what you're trying to accomplish, what you've tried already, and how the game slowed down. You might be better off using a tilemap instead of separate objects.

    duane I tried having a YSort Node with a Node2D as a child, the Node2D would duplicate itself so that the new objects could get their positions. The problem is, they all had to be children of the YSort Node, so the code had to be in the YSort, but then it was impossible to tell the distance of the Node2D from the player, as there would be several Node2Ds that would have to share one variable, and all of them would have different distrances, which would mess everything up. I tried putting the code into the Node2Ds and changing the parent, but for whatever reason, it just wouldn't parent itself, I used Node2D.get_parent().add_child(newObject), when var newObject = object.instance()

      flame-cube

      I don't know why several Node2Ds need to share a variable. The defining feature of Node2D is that it tracks its position.

      Are the nodes you're covering with intended to cover existing nodes, or are they placed at regular intervals to maximize coverage, or are they just supposed to appear at random and eventually cover everything? Are they like trees in a forest, where you just want enough to look good? And how many are we talking about? Do they have individual behavior that they have to keep (scripts) or could they just be one big bitmap, theoretically?

        I would also try to make your life easier by keeping a reference to your player in a Globals script so these other nodes can get easy access.

        duane the shared variable is because I was using it to change a variable in the global script, because I couldn't find a way to send a variable (location of the Node2D) to the parent YSort.

        I am making a generation system for rooms that are interconnected, I already have a system for randomising them, I just can't seem to find a way to cover the map with these rooms

        Well, this is one way you could do that.

        extends Node2D
        # a simple demo node
        
        
        const FAR_AWAY = 500  # far enough from player
        const ROOM_SIZE = 128
        
        
        var player:Node2D
        var rp_timer:Timer
        var win_size:Vector2
        var ysort:YSort
        
        
        func _ready() -> void:
        	randomize()
        
        	# Get the window size.
        	var vp:Viewport = get_node('/root')
        	win_size = vp.size
        
        	# Make a ysort.
        	ysort = YSort.new()
        	add_child(ysort)
        
        	# Make a pseudo-player.
        	player = Node2D.new()
        	var pos = Vector2(randi() % int(win_size.x - ROOM_SIZE), randi() % int(win_size.y - ROOM_SIZE))
        	player.position = pos
        
        	# Show where the player is.
        	var cr := ColorRect.new()
        	cr.rect_position = player.position
        	cr.rect_size = Vector2.ONE * 32
        	cr.color = Color.white
        	add_child(cr)
        
        	# Make a timer.
        	rp_timer = Timer.new()
        	rp_timer.one_shot = false
        	rp_timer.wait_time = 0.1
        	rp_timer.connect('timeout', self, 'rp_timer_timeout')
        	add_child(rp_timer)
        	rp_timer.start()
        
        
        func rp_timer_timeout():
        	# called when the timer times out
        
        	# Get a random location.
        	var pos = Vector2(randi() % int(win_size.x - ROOM_SIZE), randi() % int(win_size.y - ROOM_SIZE))
        
        	if pos.distance_to(player.position) < FAR_AWAY \
        	or (pos + Vector2.ONE * ROOM_SIZE).distance_to(player.position) < FAR_AWAY:
        		# It's too close to the player.
        		return
        
        	# Check that rooms don't overlap.
        	var nrect := Rect2(pos, Vector2.ONE * ROOM_SIZE)
        	var inter := false
        	for c in ysort.get_children():
        		var orect := Rect2(c.rect_position, c.rect_size)
        		if orect.intersects(nrect):
        			inter = true
        
        	# Make a pseudo-room (color rectangle).
        	if not inter:
        		var cr := ColorRect.new()
        		cr.rect_position = pos
        		cr.rect_size = Vector2.ONE * ROOM_SIZE
        		cr.color = Color.red
        		ysort.add_child(cr)