Godot Version
v4.2.1.stable.official [b09f793f5]
Question
Hello, I’m trying to build a HUD with a custom health bar that consists in a series of elements along a HBoxContainer.
However, each element = health cell is quite complex, and consists of 3 elements: frame, BG fill (visible when health segment was lost), cell fill (visible when health segment is filled). So I parent each trio of elements under a common parent.
The easiest seemed to use a Control parent:
but it turns out that the Control’s size in the box container direction (here, X for HBoxContainer) is 0, causing all the elements to be placed at the same position.
(note the single vertical bar showing that Control parent node size X = 0)
The only ways to force resize the Control parent are:
- set Custom Minimum Size: good for precise placement, but bad when the children may change size later (due to runtime code or when updating assets), as the value will have to be updated manually
- check Container Sizing > Horizontal > Expand: this will however occupy all the space left inside the container, sharing it with other elements and spreading the controls over the full container, instead of aligning them to the left with minimal size X. I searched for a setting to force alignment along X, but there was none.
And an extra solution that doesn’t resize the Control parent but still works if you know the Control size you want in advance, and all the Controls will have the same size:
set HBoxContainer > Theme Overrides > Constants > Separation to the wanted Control size X (more exactly the distance between every Control top-left). This can be enough in simple situations, but you still need to tune the number if you change the UI sprites later.
Note the vertical bars: parent controls are still thin, they just happen to be placed at a distance interval equal to the wanted size X.
Besides using Custom Minimum Size, I did find a solution that allows dynamic: replace Control with a Container child class, which happen to fit their own size to their children (more exactly their maximum bounding box). Container base class does nothing on its own so you need to pick a Container child class. Unfortunately there is no “generic” container class that only does this (fit size to children) so we need to pick a Container child class that doesn’t do much.
The easiest is to use one of these:
- CenterContainer: OK if you want to center your elements (along the orthogonal direction of the Box Container). It will not scale child elements.
- PanelContainer: you must remember to disable the BG with Theme Overrides > Styles > Panel > set to StyleBoxEmpty. It will also scale the element if parent Box Container orthogonal direction is bigger than children should be, so consider setting each child element of Panel Container > Stretch Mode > Keep instead of Scale
Default setup:
After hiding panel BG and setting Stretch Mode to Keep on every child of every PanelContainer:
- MarginContainer: make sure margins are 0 (may depend on theme, in this case just set Theme Overrides > Constants > all margins to 0), and you basically get a container whose only role is to fit t children. Like PanelContainer, you may need to set every child Stretch Mode to Keep instead of Scale
(same result as above)
In all these cases, note that you cannot rearrange child element offsets for a custom composition, since containers control element positions. You could add an intermediate Control to allow its own child to set a custom position, but then you’d fall back on the issue of Control size X/Y being 0 (unless you set Custom Minimum Size).
In the examples above, I made my sprites so that they all had the same dimensions, and they would perfectly overlap when placed at the same top-left (this means the inside fill actually contains a padding of 1px on the edges).
The Container child class solution feels a bit hacky and needs more setup on each child.
Is there any way to have the parent Control dynamically fit children easily?
Otherwise I’ll open a feature request to add such an option to the Control node, or alternatively add a more generic Container child class to fulfill this purpose (but we’ll still be unable to tune child offsets…), or add yet another Control child class that is not a Container subclass and is specialized in fitting to child size, e.g. some “ChildFittingControl” node.