Godot UI
Created: 2020-07-12 21:43:58 -0700 Modified: 2020-07-12 21:47:11 -0700
Basics
Section titled Basics- If you’re seeing a Control node in world space, then it’s likely because you didn’t use a canvas layer (reference). Don’t make your UI a child of a Camera (reference).
Making elements clickable (reference)
Section titled Making elements clickable (reference)In general, if you find yourself trying to write code to detect if the mouse is within a rectangle yourself, then you’re likely doing things wrong.
E.g. I originally tried to use global_position and global_scale to figure out a Rect2 so that I could call “has_point” on it with event.position. However, this didn’t take the Camera2D’s bounds into account, so it would mess up whenever I moved the camera, and probably would have been a pain to maintain anyway.
Instead, the “right” way to do things is to add an Area2D and CollisionShape2D to your object, then use the Area2D’s input_event signal:
Then, the issue I ran into was that my CanvasLayer was consuming clicks (reference). I had a Control under the CanvasLayer whose mousefilter I needed to set to IGNORE. I don’t fully understand why that still lets child Controls consume events, but children _can still get mouse events, so everything worked as intended.
Fonts
Section titled Fonts- Add your TTF font to res://assets/fonts (not required, but a good convention)
- Set it as font data for something like a label using the “Custom Fonts” property:
Spritesheet sprite in a TextureRect
Section titled Spritesheet sprite in a TextureRect- To use a single sprite from a spritesheet as a TextureRect, use an AtlasTexture.
- Make a new TextureRect
- In the Inspector, make a new AtlasTexture
- Expand the AtlasTexture so that you can see the “Atlas” property
- Drag a spritesheet onto the “Atlas”
- Set the region below it
- If you end up using the AtlasTexture a lot, you can save it as a file and share it between controls.
- Note: I had found a much more complicated way of doing this with a ViewportTexture in the TextureRect, then a sibling Viewport in the scene with a Sprite child of that Viewport, but then the Sprite size had to be doubled for some reason and I couldn’t figure out why.
Centering an AtlasTexture sprite in a layout
Section titled Centering an AtlasTexture sprite in a layoutTo achieve something like this:
…my scene tree looks like this:
- Panel
- GridContainer
- TextureRect
- CenterContainer
- Label
- GridContainer
The TextureRect has “Keep Aspect Centered”:
Center elements in a GridContainer
Section titled Center elements in a GridContainerThis is sort of like “justify-content: space-between” in CSS:
How I accomplished this was with this scene tree:
- Container
- CenterContainer
- Label (“Row 1”)
- GridContainer (or HBoxContainer if you want)
- Label (“Row”)
- Label (“Two”)
- Label (“Here”)
- CenterContainer
The GridContainer has 3 columns and has the “fill” and “expand” size flags for “Horizontal” (the scripting constant for this is SIZE_EXPAND_FILL). Each child label has the same horizontal size flags and also “Align: Center”.
To get closer to “justify-content: space-between”, I think you’d just set the middle label to SIZE_EXPAND_FILL, not the left/right labels.
Overlapping problems with containers
Section titled Overlapping problems with containersI kept running into issues like this:
This is a scene tree that looks like this:
- VBoxContainer
- CenterContainer
- HBoxContainer
- Item
- HBoxContainer
- CenterContainer
- HBoxContainer
- Item
- Item
- HBoxContainer
- CenterContainer
- HBoxContainer
- Item
- Item
- HBoxContainer
- CenterContainer
…where “Item” was itself another scene whose root node was a Panel:
My issue ended up being that I didn’t set a minimum size on the Panel in Item. Without that, a CenterContainer can’t know how big the Panel should be, so it sets the size to (0, 0).
Alternatively, you could be running into this issue where dynamically laying out a container’s children isn’t straightforward.
MarginContainer (reference)
Section titled MarginContainer (reference)A MarginContainer is like the “padding” style in HTML; it puts extra space inside the container. This is not to be confused with the “Margin” properties on all Control nodes! MarginContainer’s properties are here:
Here’s a MarginContainer with a Panel as a child:
As you can see, the panel is “pulled away” from each edge by 25 pixels.