HTX Frederikshavn & Hjørring

Det har aldrig været sjovere at være nørd

Brugerværktøjer

Webstedsværktøjer


ddu:godot:trin4_inventory_ui

Trin 4: Inventory-UI med 9-patch baggrund og grid

← Forrige: Grafik til én slot | Forside | Næste: Vis spillerens inventory →

I dette trin bygger du selve inventory-vinduet: en baggrund, der skalerer pænt, med et grid af slots i. Du skriver også koden, der opretter ét slot-UI for hvert slot i et Inventory.

Nye begreber

  • NinePatchRect er en node til baggrunde. Den deler et billede op i ni felter og skalerer dem forskelligt, så hjørner og kanter ikke bliver forvrænget (forklares nedenfor).
  • GridContainer er en container, der placerer sine børn i et gitter. Du fortæller den, hvor mange kolonner den skal have, og den lægger børnene ud række for række. Med 3 kolonner og 9 børn får du 3 rækker.
  • MarginContainer er en container, der giver luft (en margin) rundt om sine børn.
  • PackedScene er en scene, der er pakket som data, så koden kan oprette (instantiere) kopier af den. Vi bruger den til at oprette slots.

Scenens opbygning

Opret en ny scene med MarginContainer som rod, og lav disse noder:

InventoryUI (MarginContainer)
├── Background (NinePatchRect)
└── Content (MarginContainer)
    └── Grid (GridContainer)

Gem den som Scenes/InventoryUI.tscn. Rækkefølgen er vigtig: Background skal stå før Content, fordi noder, der står først, tegnes først (bagest).

Hvorfor er scenen bygget sådan? En container giver alle sine børn samme plads. Roden InventoryUI har ingen margin og strækker derfor både Background og Content ud, så de fylder hele roden. Roden bliver samtidig mindst så stor som sit største barn. Da Content (med grid og margin) er størst, får baggrunden automatisk den rette størrelse. Hvis du senere ændrer antal slots, vokser både grid og baggrund med, uden at du skal regne på størrelser.

Indstillinger i Inspector

Node Indstilling Værdi
Content Theme Overrides → Constants → Margin Left, Top, Right, Bottom 16 (samme i alle fire)
Grid Columns 3
Grid Theme Overrides → Constants → H Separation og V Separation 4

Columns = 3 er det, der gør inventoryet til et grid med 3 kolonner. Med 9 slots giver det 3×3. Antallet af slots styres i Inventory (Slot Count), og antallet af kolonner styres her i UI'et.

NinePatchRect: en baggrund der skalerer pænt

Hvis du strækker et almindeligt billede af en ramme, bliver rammens kanter tykke og hjørnerne forvrængede. En 9-patch løser det ved at dele billedet i ni felter:

+---+-----------+---+
| 1 |     2     | 3 |    1, 3, 7, 9: hjørnerne. Strækkes aldrig.
+---+-----------+---+    2, 8: top og bund. Strækkes kun vandret.
| 4 |     5     | 6 |    4, 6: siderne. Strækkes kun lodret.
+---+-----------+---+    5: midten. Strækkes både vandret og lodret.
| 7 |     8     | 9 |
+---+-----------+---+

Hjørnerne forbliver derfor skarpe, uanset hvor stor baggrunden bliver. Det er præcis det, vi har brug for, fordi inventoryet får forskellig størrelse alt efter antal slots.

Markér Background, og indstil:

Indstilling i Inspector Værdi
Texture Træk dit panel-billede fra Assets hertil
Patch Margin → Left, Top, Right, Bottom Tykkelsen på billedets kant i pixels, fx 12
Axis Stretch → Horizontal og Vertical Stretch (eller Tile, hvis kanten har et mønster)
Draw Center Til (slå fra, hvis kun kanten skal vises)

Sådan vælger du patch margins: Patch margins er afstandene fra billedets kanter ind til de linjer, der deler billedet i ni felter. Sæt dem til tykkelsen af den dekorative ramme, altså hjørnerne. Er rammen i dit billede 12 pixels tyk, bruger du 12. Er værdien for lille, bliver hjørnerne strakt og uskarpe. Er den for stor, bliver midten for lille. Prøv dig frem, indtil hjørnerne ser ens ud, uanset størrelse.

Axis Stretch bestemmer, hvordan top, bund og sider fyldes ud. Stretch strækker billedet, Tile gentager det som fliser, og Tile Fit gentager det, så det går op i størrelsen. Til de fleste paneler er Stretch fint.

Script til UI'et

Højreklik på rod-noden InventoryUI, vælg Attach Script, vælg C#, og sæt stien til Scripts/Inventory/InventoryUI.cs. Erstat indholdet med:

InventoryUI.cs
using Godot;
using System.Collections.Generic;
 
// InventoryUI viser indholdet af ét Inventory i et grid.
// Den kan vise ALLE Inventory-komponenter: den får bare at vide, hvilken den skal vise.
public partial class InventoryUI : MarginContainer
{
    // Slot-scenen, som skal oprettes én gang pr. slot. Sættes i Inspector.
    [Export] public PackedScene SlotScene { get; set; }
 
    private GridContainer _grid;
    private Inventory _inventory;
 
    // En liste over de slot-grafikker, vi har oprettet.
    private readonly List<SlotUI> _slotUIs = new List<SlotUI>();
 
    public override void _Ready()
    {
        _grid = GetNode<GridContainer>("Content/Grid");
    }
 
    // Fortæller UI'et, hvilket inventory det skal vise, og bygger slots.
    public void SetInventory(Inventory inventory)
    {
        if (SlotScene == null)
        {
            GD.PushError("InventoryUI: SlotScene er ikke sat i Inspector.");
            return;
        }
 
        _inventory = inventory;
 
        // Fjern eventuelle gamle slots, hvis SetInventory kaldes igen.
        foreach (SlotUI oldSlot in _slotUIs)
        {
            oldSlot.QueueFree();
        }
        _slotUIs.Clear();
 
        // Opret én SlotUI pr. slot i inventoryet.
        for (int i = 0; i < _inventory.GetSize(); i++)
        {
            SlotUI slotUi = SlotScene.Instantiate<SlotUI>();
            _grid.AddChild(slotUi);   // Først nu kører slottens _Ready
            _slotUIs.Add(slotUi);
        }
 
        Refresh();
    }
 
    // Opdaterer alle slots, så de matcher inventoryets indhold.
    // Skal kaldes, hver gang inventoryets indhold er ændret.
    public void Refresh()
    {
        for (int i = 0; i < _slotUIs.Count; i++)
        {
            _slotUIs[i].SetItem(_inventory.GetItem(i));
        }
    }
}

Forklaring:

  • [Export] public PackedScene SlotScene er et felt i Inspector, hvor du trækker SlotUI.tscn ind. Vi gør det på denne måde frem for at hardkode stien i koden. Det er nemt at skifte slot-scene senere, og der er ingen filstier, du kan stave forkert.
  • SetInventory(Inventory inventory) er den vigtigste metode. UI'et ved ikke på forhånd, hvilket inventory det skal vise. Det får det at vide udefra. Det er netop det, der gør UI'et genbrugeligt: samme UI-scene kan vise spillerens inventory ét sted og kistens et andet.
  • SlotScene.Instantiate<SlotUI>() laver en ny kopi af slot-scenen. AddChild sætter den ind i gridet. Først når den er tilføjet, kører slottens _Ready(). Derfor kalder vi SetItem bagefter i Refresh() og ikke før.
  • Løkken kører GetSize() gange og opretter én slot pr. slot i inventoryet. Derfor ændrer antallet af slots i UI'et sig automatisk, hvis du ændrer Slot Count i inventoryet.
  • En liste (List<SlotUI>) er en samling, der kan vokse. Vi gemmer de oprettede slot-UI'er i den, så Refresh() kan opdatere dem én for én og SetInventory kan slette dem igen.
  • QueueFree() sletter en node sikkert, når Godot er færdig med den aktuelle opgave.
  • Refresh() henter hvert item fra inventoryet og beder den tilsvarende slot vise det. Det er en simpel og tydelig løsning: Når noget er ændret, kalder vi Refresh(). Vi bruger ikke avancerede mekanismer til at holde UI'et opdateret, og det er nemt at gennemskue.
  • GD.PushError(…) skriver en rød fejlbesked i Output. Det er hjælp til dig selv, hvis du glemmer at sætte Slot Scene.

Tryk på Build. Markér derefter InventoryUI i scenen, og træk Scenes/SlotUI.tscn fra FileSystem ind i feltet Slot Scene i Inspector.

Test af 9-patch baggrunden

Slots oprettes først af koden i trin 5. For at se baggrunden nu, kan du midlertidigt lave dem i hånden:

  1. Træk SlotUI.tscn ind på Grid ni gange. (Eller træk den ind én gang, og tryk Ctrl+D otte gange.)
  2. Kør scenen med F6. Du skal se et 3×3 grid med en baggrund bagved.
  3. Tilføj en tiende slot med Ctrl+D. Gridet får en fjerde række, og baggrunden vokser med, uden at hjørnerne bliver forvrænget. Sæt til sammenligning Patch Margin til 0 på Background, og se, hvordan hjørnerne bliver strakt. Sæt værdien tilbage bagefter.
  4. Slet de ni slots igen, så Grid er tom. Ellers får du ekstra tomme slots ved siden af dem, koden opretter.
  5. Gem scenen.

Tjekliste

  • InventoryUI.tscn har Background, Content og Grid i den rigtige rækkefølge.
  • Grid har Columns = 3, og baggrunden skalerer pænt.
  • Slot Scene er sat til SlotUI.tscn.
  • Grid er tom i editoren, og Build giver ingen fejl.

Næste: Vis spillerens inventory →

ddu/godot/trin4_inventory_ui.txt · Sidst ændret: af admin