Steuerungslayout in Godot 4
Die meisten kaputten Godot-Benutzeroberflächen entstehen aus drei Fehlern: Kinder eines Containers von Hand positionieren, ein Steuerelement verankern ohne seine Versätze zurückzusetzen, und die Stretch-Einstellungen auf den Standardwerten lassen. Gestalten Sie mit Containern, verankern Sie nur die Wurzel jeder Benutzeroberfläche und lassen Sie minimale Größen den Rest bestimmen.
Container besitzen ihre Kinder
Ein Kind eines beliebigen Container (VBoxContainer, HBoxContainer, GridContainer, MarginContainer, PanelContainer, CenterContainer, ScrollContainer, FlowContainer) kann seine eigenen position, size oder Anker nicht behalten: der Container überschreibt sie beim nächsten Sortieren. Steuern Sie den Platzanteil eines Kindes mit:
size_flags_horizontal/size_flags_vertical:Control.SIZE_FILL(Standard),SIZE_EXPAND_FILLum restlichen Platz zu nehmen,SIZE_SHRINK_CENTER/SIZE_SHRINK_ENDum klein und ausgerichtet zu bleiben.size_flags_stretch_ratio: Anteil am restlichen Platz zwischen expandierenden Geschwistern.custom_minimum_size: die kleinste Größe, die das Kind akzeptiert. Container verkleinern ein Kind nie unter seine kombinierte Mindestgröße, wodurch Text und Schaltflächen nicht abgeschnitten werden.
Wählen Sie den Container nach Layout: Zeilen oder Spalten (VBoxContainer, HBoxContainer), ein Gitter (GridContainer mit columns), Abstände (MarginContainer, Abstände gesetzt durch Themen-Konstanten margin_left, margin_top, margin_right, margin_bottom), ein Hintergrund (PanelContainer, Style-Box panel), langer Inhalt (ScrollContainer mit einem Kind, das SIZE_EXPAND_FILL hat), umbrechende Elemente (HFlowContainer).
Anker nur für die Wurzel
Anker platzieren ein Steuerelement relativ zum Rechteck seines Elternteils und werden für den äußersten UI-Knoten verwendet. Verwenden Sie aus Code set_anchors_and_offsets_preset(). set_anchors_preset() verschiebt nur die Anker und behält die alten Versätze, sodass ein in Code erstelltes Steuerelement bei Größe (0, 0) bleibt.
Voreinstellungen: PRESET_FULL_RECT, PRESET_TOP_LEFT, PRESET_TOP_RIGHT, PRESET_BOTTOM_LEFT, PRESET_BOTTOM_RIGHT, PRESET_CENTER, PRESET_TOP_WIDE, PRESET_BOTTOM_WIDE, PRESET_LEFT_WIDE, PRESET_RIGHT_WIDE, PRESET_HCENTER_WIDE, PRESET_VCENTER_WIDE sowie die Mitte-Rand-Voreinstellungen wie PRESET_CENTER_TOP.
HUD auf einer CanvasLayer
Ein Control unter einem Node2D wird im Weltraum gezeichnet und bewegt sich mit der Camera2D. Platzieren Sie das HUD unter einer CanvasLayer, damit es auf dem Bildschirm bleibt; layer ordnet mehrere Canvas-Ebenen (höhere werden oben gezeichnet).
extends CanvasLayer
var score_label: Label
func _ready() -> void:
var margin := MarginContainer.new()
margin.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
for side in ["margin_left", "margin_top", "margin_right", "margin_bottom"]:
margin.add_theme_constant_override(side, 16)
add_child(margin)
var column := VBoxContainer.new()
margin.add_child(column)
var top_bar := HBoxContainer.new()
column.add_child(top_bar)
score_label = Label.new()
score_label.text = "Score: 0"
score_label.add_theme_font_size_override("font_size", 24)
score_label.add_theme_color_override("font_color", Color.GOLD)
top_bar.add_child(score_label)
var spacer := Control.new()
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
spacer.mouse_filter = Control.MOUSE_FILTER_IGNORE
top_bar.add_child(spacer)
var pause_button := Button.new()
pause_button.text = "Pause"
pause_button.custom_minimum_size = Vector2(96, 40)
top_bar.add_child(pause_button)
func set_score(value: int) -> void:
score_label.text = "Score: %d" % value
Im Editor erstellt ist der gleiche Baum: CanvasLayer > MarginContainer (Layout: Full Rect) > VBoxContainer > HBoxContainer > Label, Control (Expand), Button.
Text, der nicht abgeschnitten wird
- Ein
Labelmit gesetztemautowrap_modebenötigt eine Breite von irgendwoher. Innerhalb einesHBoxContainermit Standard-Flags kollabiert es auf 1 Pixel Breite und wird sehr hoch. Geben Sie ihmSIZE_EXPAND_FILLoder eincustom_minimum_size.x. - Für einzeiligen Text in einem festen Raum setzen Sie
text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS(oderclip_text = true). - Bevorzugen Sie
add_theme_font_size_override("font_size", n)gegenüber dem Skalieren eines Steuerelements:scaleändert nicht die Größe, die Container reservieren.
extends VBoxContainer
func add_message(text: String) -> void:
var label := Label.new()
label.text = text
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
add_child(label)
func add_title(text: String) -> void:
var label := Label.new()
label.text = text
label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
label.custom_minimum_size = Vector2(0, 32)
add_child(label)
Klicks, die das Spiel nicht erreichen
mouse_filter entscheidet, ob ein Steuerelement Mauseingaben frisst. Die Vorgaben unterscheiden sich: einfaches Control, ColorRect und Panel verwenden MOUSE_FILTER_STOP, Container verwenden MOUSE_FILTER_PASS, Label verwendet MOUSE_FILTER_IGNORE. Ein Vollbild-Control oder ColorRect mit STOP schluckt jeden Klick, sodass _unhandled_input() im Spiel ihn nie sieht. Setzen Sie mouse_filter = Control.MOUSE_FILTER_IGNORE auf Überlagerungen, Abstandshaltern und dekorativen Rechtecken.
Theme-Overrides (Godot 4 Namen)
| Godot 3 | Godot 4 |
|---|---|
add_color_override("font_color", c) | add_theme_color_override("font_color", c) |
add_font_override("font", f) | add_theme_font_override("font", f) |
| (Schriftgröße lebte in DynamicFont) | add_theme_font_size_override("font_size", 24) |
add_stylebox_override("normal", sb) | add_theme_stylebox_override("normal", sb) |
add_constant_override("separation", 8) | add_theme_constant_override("separation", 8) |
add_icon_override("icon", tex) | add_theme_icon_override("icon", tex) |
custom_colors/font_color in .tscn | theme_override_colors/font_color |
Entfernen Sie eine Überschreibung mit dem passenden remove_theme_*_override(name). Für ein einheitliches Aussehen weisen Sie dem Wurzelsteuerelement eine einzelne Theme-Ressource zu, anstatt jeden Knoten zu überschreiben; Kinder erben sie.
Auflösung und Streckung
Stellen Sie diese in Projekteinstellungen > Anzeige > Fenster ein (gespeichert in project.godot):
display/window/size/viewport_widthundviewport_height: die Basisauflösung, für die Sie entwerfen (Standard 1152 x 648).display/window/stretch/mode:canvas_itemsfür die meisten Spiele (UI und 2D skalieren flüssig),viewportfür Pixel-Art,disabledfür Werkzeuge. Godot 3s2d-Modus istcanvas_itemsin Godot 4. Die Standardeinstellung istdisabled; Projekte, die in Godot 4.7 oder später erstellt wurden, beginnen mitcanvas_items.display/window/stretch/aspect:expandlässt verankerte UI bei breiteren oder höheren Bildschirmen zusätzlichen Platz nutzen;keepfügt schwarze Balken hinzu. Der Standard istkeep; Projekte, die in Godot 4.7 oder später erstellt wurden, beginnen mitexpand.display/window/stretch/scale_mode:integerfür gestochen scharfe Pixel-Art.
Zur Laufzeit sind dieselben Einstellungen am Fenster: get_window().content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS und get_window().content_scale_aspect = Window.CONTENT_SCALE_ASPECT_EXPAND.
Checkliste, wenn die UI abgeschnitten oder falsch platziert ist
- Ist das Steuerelement ein Container-Kind mit handgesetzter
positionodersize? Verwenden Sie Größenflags undcustom_minimum_size. - Wurde die Wurzel nur mit
set_anchors_preset()verankert? Verwenden Sieset_anchors_and_offsets_preset(). - Hat ein umbrechendes
Labeleine Breite? - Ist das HUD unter einer
CanvasLayerstatt einemNode2D? - Ist
display/window/stretch/modenochdisabled, während sich die Fenstergröße ändert? - Liegt ein unsichtbares Vollbild-Steuerelement mit
MOUSE_FILTER_STOPobenauf?