Hello.

I have a Player scene that is set up like this:

KinematicBody2D

  • AnimatedSprite

  • CollisionShape2D

  • Camera2D

  • CanvasLayer

  • - PopupDialog

  • - - ColorRect

  • - - RichTextLabel

The PopupDialog and ColorRect are set right above my KinematicBody2D and I have some code that runs popup() and displays the PopupDialog box. The thing is, it shows up in the right hand corner ( 0,0 I guess) and stays there. If I click on Enable for Follow Viewport, it shows up where I want it to, but it's glued to the viewport and follows the background.

What I want to happen is the PopupDialog to follow the player around above their head when it displays. Do I have to update its position in code or is there a button or knob I'm missing in the way it's set up? Is this possible with CanvasLayer (as I want dialogue to appear over all elements). Can someone help point me in the right direction?

I've tried updating the position of the popupdialog to match the kinematicbody2d within process(delta) but it still doesn't appear to work.

i usually use the canvas layer for HUD elements, pause game menu, etc. because u want that things stay quiet and visible on the front and dont follow the camera.

For popups, dialogs and that things, u can use a simple node2D like father, because it has transform, z index, visibility and material properties. Just adjust the z index of the dialogs/pops over the scene, but under your hud ie.

The only thing, if your game camera has zoom, and u want it in the pop up, u will have to apply that in other way. In my case i dont need that because zooming the dialogs make them looks weird.

I suppose that could work. I just used Canvas Layer as it auto makes everything appear on top. I did try to take the PopupDialog (and its children) and make it a direct child of KinematicBody2D but the positioning was still weird and my character was able to walk over it (probably due to z-index). I can give that another go or add a node to it but I'm trying to avoid having another script attached here as the script is attached to PopupDialog.

The other question I have about your suggestion is about z index. Is that global? If PopupDialog is a child of KinematicBody2D, can it's z index be higher so that other elements in a parent scene (above KinematicBody2D) show behind PopupDialog but in front of KinematicBody2D?

So I managed to get this working, by having it under a Node2D, but when I attempted to set the z_index, it didn't work. I had: $Node2D.z_index = 0 but it still showed below the AnimatedSprite of KinematicBody2D. Is this because it's a child of it or did I do something wrong?

Keep in mind that I am dynamically changing the z_index of the KinematicBody2D elsewhere in my main scene. Could this be overwriting the z_index?

Hmm... I tried $Node2D.set_z_index(0) and I've tried to comment out the code that sets the dynamic z_index of KinematicBody2D and the dialogbox still shows behind my characters. Here's what I did to get it working:

On func _physics_process (delta): in the KinematicBody2D script, I have the following line:

$Node2D/Dialogue.set_global_position(Vector2(self.position.x,(self.position.y - 160)))

If I rip out Node2D and bring $Dialogue and all its children up a level, it still works. This sets the global position of the popup dialog box relative to the x and y coordinates of KinematicBody2D (with y - 160 so it appears above its head), it does what I want it to do... but that pesky z_index has the dialog falling behind my characters.

If I try any variation of using CanvasLayer, it appears above my characters, but it breaks the global_position and doesn't follow my characters around.

I changed the line to be more of the following: $Node2D/Popup.set_position(Vector2((self.position.x - 3),(self.position.y - 110)))

This is in the KinematicBody2D script so self is the player. It works (again, except for the z_index), but I notice that at random times for a frame or two, the dialog box appears to the far left of the screen before correcting itself and following the player.

I tried to do some prints before and after the popup() is executed (which runs on a timer). This is done with the following code:

print("Player before popup(): ", get_parent().get_parent().position)
print("Dialog before popup(): ", get_position())
popup()
print("Player after popup(): ", get_parent().get_parent().position)
print("Dialog after popup(): ", get_position())```

I see the following in output:

Player before popup(): (-435.355011, 168.688751) Dialog before popup(): (-438.355011, 58.688751) Player after popup(): (-435.355011, 168.688751) Dialog after popup(): (0, 58.688751) Player before popup(): (-925.799622, 292.187164) Dialog before popup(): (-931.240601, 178.810394) Player after popup(): (-925.799622, 292.187164) Dialog after popup(): (0, 178.810394) Player before popup(): (-881.262024, 541.983765) Dialog before popup(): (-880.134033, 431.417542) Player after popup(): (-881.262024, 541.983765) Dialog after popup(): (0, 431.417542) Player before popup(): (-1416.839111, 700.173828) Dialog before popup(): (-1419.839111, 590.173828) Player after popup(): (-1416.839111, 700.173828) Dialog after popup(): (0, 590.173828)

Why is the dialog position.x set to 0 afterwards when I'm doing no additional code to change this?

I think this might be a bug. I removed it from the player script and added the same code to the Popup script. If I set the position in both _process(delta) and after popup(), it works as expected:

func _process(delta):
	set_position(Vector2((get_parent().get_parent().position.x - 3),(get_parent().get_parent().position.y - 110)), true)
#
func update_dialogue(message: String):
	print("Player before popup(): ", get_parent().get_parent().position)
	print("Dialog before popup(): ", get_position())
	popup()
	set_position(Vector2((get_parent().get_parent().position.x - 3),(get_parent().get_parent().position.y - 110)), true)
	print("Player after popup(): ", get_parent().get_parent().position)
	print("Dialog after popup(): ", get_position())

See (output):

Player before popup(): (-582.79187, 170.29187) Dialog before popup(): (-585.79187, 60.29187) Player after popup(): (-582.79187, 170.29187) Dialog after popup(): (-585.79187, 60.29187) Player before popup(): (-1244.332031, -157.914551) Dialog before popup(): (-1247.332031, -267.914551) Player after popup(): (-1244.332031, -157.914551) Dialog after popup(): (-1247.332031, -267.914551) Player before popup(): (-1865.537476, 127.081337) Dialog before popup(): (-1864.507446, 16.023041) Player after popup(): (-1865.537476, 127.081337) Dialog after popup(): (-1868.537476, 17.081337)

It's almost like something in the popup() function for the Popup node is setting Vector2D(x) to 0 when I'm telling it not to, but running the same command afterwards (as seen in line 8) sets it correct again before whatever is affecting it can happen.

Is this a bug?

i dont think its a bug... maybe a wrong use of position and global_position... i think u dont need the process function but maybe i dont undesrtand well what are you trying to do, sorry, im not native english

what i would do is:

·create a node2d with the dialog pop up and adjust its z index in the properties ·add and animation player or tween and create the 'around player movement' of the pop up. with autoplay maybe, or u can play it from the ready func

when u need the dialog, instance the node2d to the player. and when u dont need it, queue free

check this video, in <6 minutes probably you will find the error

13 days later

Hmm.. I thought I responded to this. Thanks for this video. I ended up attaching the dialogue children to a node in my character scene.

KinematicBody2D - DialogueNode2D (Node2D) - - NinePatchRect - - - RichTextLabel

By setting this as a child of the KinematicBody2D, it follows the character. I then set the Z Index of the DialogueNode2D to a high number to ensure it stays on top. I unselect Z As Relative.

The video definitely helped me realize to try this.

2 years later