Indholdsfortegnelse

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

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:

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

Næste: Vis spillerens inventory →