Hi! I'm trying to create my own Dialogue manager to help me with my game, and it's going great. But I can't find an solution to the issue of my dialogue boxes overlapping each other.

I want to be able to create multiple instances of dialogue boxes that I can edit in real time. For this I would like to make it so the boxes can't touch nor overlap each other. But I can't find how. I tried making them StaticBody2D with really weird results since they seem to follow each other when touching.

I would appreciate any advice about a better way to do it!

Here is a screenshot of two boxes overlapping. I want to make it so it's impossible for that to happen.

  • Toxe replied to this.

    Godoten Could you make a screenshot and show us what you have or trying to do? Because if you talk about dialogue then my first thought would be more along the lines of Control and not StaticBody2D.

      Toxe I just updated the post with a screenshot of the dialog boxes overlapping each other. They are control nodes, I'm trying to make it so it's impossible for them to touch or overlap another box!

      • Toxe replied to this.

        Godoten Could you add a container control that for example sits at the center of the screen per default and that automatically layouts your dialogs? Maybe arrange them next to each other in at most two columns and then if you add a third dialog it adds a new row and shows the new dialog below the other two.

        Edit: Or maybe just a tab container. Add a tab for every new dialog. After all, do you really need to show more than one or two on the screen at once?

          Toxe It's not what I wanted but i might be enough. I will try it, thank you!

          I'm vomiting ideas here:

          • draw() signal fires everytime a control node is redrawn, for example, when appearing, moving or resizing.
          • a rect's position should be located at its top left corner by default, so:
            anywhere between rect.position and rect.position + rect.size would be occupied by rect.

          you could use that draw() signal with the vector2 math above to convince your control nodes to behave how I think you're wanting them to behave.
          if you're clever.
          i am a lot more familiar with gdscript than most of godot's builtin functions, so please someone speak up if what i'm suggesting is unnecessarily hacky.

            Toxe I tried it with containers and it kind of works but It's not really what I was looking for. This way I can't move them around and connect them as I had planned.

            If someone knows a better way, I would appreciate it!

            Oh, you wanted to connect them? I thought they were more like dialog boxes.

              packrat Those are great ideas too! I will test them and get back to you!

              Toxe Oh no this is more like my dialog manager so this is where I will be making the narrative in the back end. At the end I should be able to export the whole tree of conversation to a json file that I will use with my actual dialogue box. That's why I want to be able to move them around and connect them but without them overlapping/touching

              • xyz replied to this.

                Godoten It's not worth the effort if this is just for backend. Let them overlap. Almost every node editor in existence overlaps its nodes.

                  I agree it isn't necessary or worth it, but why not do it anyway for fun? 😛

                  @Godoten Do you already have figured out how you're doing click & drag? You should implement that first, then at the point in code where you release after dragging you can worry about making the boxes not overlap.

                    xyz True but it's a good opportunity to challenge myself so I can learn more about the engine (and do more things in the actual game). So my goal is that they can't won't touch.

                    • xyz replied to this.

                      award Yeah, it's more like a challenge to improve. In fact I could use GraphNodes and GraphEdit to have them directly but I'm traying to make them myself so I can learn and play with the logic.

                      I haven't figured out the connection yet, but I guess I will use curve2D and a simple drag and drop code that checks if can_drag and can_drop. The hard part would be making interactions between them when linked, I think.

                      Godoten True but it's a good opportunity to challenge myself

                      Well if you want to challenge yourself, then you should figure it out on your own. By asking "how to", you're challenging the people on the forum instead 😉

                      This can be done in several ways. Start by precisely describing the behavior. Can you drag one or multiple boxes at a time? Should they rearrange as you drag or only when you drop? Should they be pushed in the direction of drag or only moved out of the way... etc.

                        xyz I tried myself for a long time. If I'm asking is because I got stuck and you gotta know your limits. Now @packrat gave me a great idea that a can try to implement and learn more.

                        I thought it would be possible to give them some kind of "collide" property just like bodies, but I guess I will need to code the whole interaction.

                          Godoten thanks for the validation. i use knowledge from vain/pointless projects all the time.
                          i do appreciate custom UI behaviour. altering how the player interacts with a menu can make your game subconsciously memorable. i didn't love Metroid Prime 2, but the main menu in that game still sticks in my head, simply because it was weird.
                          do be careful with that, it can also cause your game to suck..

                          Godoten A quick and dirty custom implementation of rectangular Separating Axis Theorem should do the trick. It's been a while since I implemented one of those, so challenge accepted 😃

                          main.gd:

                          extends Node2D
                          
                          func separate(window1, window2, bias = .5):
                          	var r1 = window1.get_rect()
                          	var r2 = window2.get_rect()
                          
                          	var ri = r1.intersection(r2)	
                          	if not ri.has_area():
                          		return
                          
                          	var displace = Vector2.ZERO
                          	var o1 = r1.end - r2.position
                          	var o2 = r2.end - r1.position
                          
                          	if(ri.size.x < ri.size.y):
                          		if abs(o1.x) < abs(o2.x):
                          			displace.x += o1.x
                          		else:
                          			displace.x -= o2.x	
                          	else:
                          		if abs(o1.y) < abs(o2.y):
                          			displace.y += o1.y
                          		else:
                          			displace.y -= o2.y	
                          	
                          	window2.position += displace * bias
                          	window1.position -= displace * (1-bias)
                          
                          func _process(delta):
                          	for w1 in get_children():
                          		for w2 in get_children():
                          			if w1 != w2:
                          				var bias = .5
                          				if w1.dragging: 
                          					bias = 1
                          				elif w2.dragging:
                          					bias = 0
                          				separate(w1, w2, bias)

                          window.gd:

                          extends ColorRect
                          
                          var dragging = false
                          
                          func _gui_input(event):
                          	if event is InputEventMouseButton:
                          		if event.is_pressed():
                          			dragging = true
                          			modulate = Color(1.0, 0.0, 0.0, 1.0)
                          
                          	if event is InputEventMouseMotion and dragging:
                          		position += event.relative
                          
                          func _input(event):
                          	if event is InputEventMouseButton and not event.is_pressed():
                          		dragging = false
                          		modulate = Color(1.0, 1.0, 1.0, 1.0)

                          Note that running it once cannot guarantee cascaded separation in very crowded situations. However we run it every frame and it eventually sorts itself out throughout several frames, which is mostly unnoticeable.

                          You homework is to adapt it for multiple dragging windows, and optimize for performance 😉

                            xyz Wow that actually looks amazing, great work! I understand part of what you did there, but another part of the code is a mystery to me. I will spend the day studying it, thank you so much!