How to arrange the sequence of GUI and Dialogue that are canvas layer and Node2D

Godot Version

Godot 4.2.2

Question

  • The dialogue runs on canvas layer#1
  • The GUI that contains settings and save/load runs on layer#3
  • The node2d that runs on layer#0
    My purpose is to be able to load the node2d scene from the GUI interface and the dialogue must also show as well. Therefore, I would like to ask the suggestion or advises to arrange the sequence of layers.
    What I expect after the load

    The problem is when I load the slot, the Node2D scene does not show. Do I have to change the Z-index or move the Node2D to be
    ParallaxBackground
    – ParallaxLayer
    ------Node2D and set the higher layer to show the scene and dialogue after loading ?

Hi, I don’t understand what you mean.

you are using a Node as parent of other nodes. a Node does not have transform information, it should not be used as parent of a Node2D or Control or Node3D, which do have transforms.
Then you have a Control as parent of a bunch of CanvasLayers, and that’s wrong too. CanvasLayer should be parent of a Control or Node2D, not the other way around, because they are used to overlay different canvasItem nodes (Control and Node2D).

Rules:
1 - In 2D, nodes are drawn in the order they appear in the tree. the last item is drawn above the previous one.

background |
middle     |
foreground V

2 - placing a Node2D or Control as children of a Node (or other node without transforms), resets the position of the node. The global_position and position of the node becomes the same.
3 - Controls are not to be mixed with other nodes. Controls rely on inheritance of the parent node to obtain things like themes, anchoring, colors and process behaviour. So Control nodes should only be parents of other Control nodes.
4 - Controls should not be mixed with 2D nodes, while both are 2D, they inherit from CanvasItem, Controls are designed to adapt to the area of their parent, which includes windows for fitting within different resolutions. 2D nodes on the other hand are designed to move around and go outside the screen any distance. nesting Node2D and Controls also resets position of one another.

So a scene should look like this:

Node2D(background)
    |->Stuff
Node2D(middle)
    |->Characters
Node2D(foreground)
    |->trees?
Control(menues)
    |->Controls
Node (with script)
Node (with script)

then, CanvasLayers. these can arbitrarily set their position independently of tree order:

but even the docs say this is not necesary, as most things can be done without them and just controlling the order of nodes in the tree:

CanvasLayers aren’t necessary to control the drawing order of nodes. The standard way to ensuring that a node is correctly drawn ‘in front’ or ‘behind’ others is to manipulate the order of the nodes in the scene panel. Perhaps counterintuitively, the topmost nodes in the scene panel are drawn on behind lower ones in the viewport. 2D nodes also have the CanvasItem.z_index property for controlling their drawing order.

to spawn something at a particular order, keep a reference to your first nodes and add_child on them.


@export var foreground : Node2D
@export var background : Node2D

func spawn_node() -> void:
	var tmp : Node2D = my_packed_scene.instantiate()
	foreground.add_child(tmp)#add the node to the foreground
	background.add_child(tmp)#add the node to the background

2 - placing a Node2D or Control as children of a Node (or other node without transforms), resets the position of the node. The global_position and position of the node becomes the same.

What are you saying here?
A Node2D’s position/global_position isn’t changed as child of a Node.

and that’s the problem.

lets say you have a character, and it has a node2D

CharacterBody2D
    |->Node2D

the position of character is (40, 40), the position of Node2D is (20, 20).
then, the global_position of character is (40, 40), and the global_position of Node2D would be (60, 60)

but if there’s a Node there:

CharacterBody2D
    |->Node
        |->Node2D

the global_position of character would be (40, 40), but the global_position of Node2D would be (20, 20).

in other words, moving the character does not move the Node2D.

Well I was sure I tried it last night. And so I tried it again.
Here is the result:

extends CharacterBody2D
#@onready var node_2d: Node2D = $Node2D
@onready var node_2d: Node2D = $Node/Node2D

func _ready() -> void:
	print(node_2d.position, node_2d.global_position)

The CharacterBody2D is at 40,40. The Node2D is at 20,20

Output:
(60.0, 60.0)(60.0, 60.0)

So as you can see. Your own example does not move the child node.

you are printing the position of Node2D and not the global_position which is what matters.
Maybe I phrased it wrong, I meant the position of the Node2D on screen, not the position as in the property.

Sprite2D is child of Node2D, dragging the node2d moves the sprite


Node between Node2D and Sprite, dragging the node2d does not move the sprite.


Look again. I am printing both.