Indholdsfortegnelse

Resources i Inventory

I et RPG skal spilleren kunne samle våben, potions og armor op og beholde dem, når spilleren skifter scene.

Vi løser det ved at oprette en global `InventoryManager` som Autoload. Den eksisterer, så længe spillet kører, og kan tilgås fra alle scener.

1. Opret InventoryManager

Opret et C#-script med navnet `InventoryManager.cs`.

using Godot;
using Godot.Collections;
 
public partial class InventoryManager : Node
{
    public Array<Item> Items { get; private set; } = new();
 
    public void AddItem(Item item)
    {
        if (item == null)
            return;
 
        Items.Add(item);
        GD.Print($"Samlede op: {item.Name}");
    }
}

Hvad sker der?

Bemærk, at `Item` er den fælles Resource-klasse fra den foregående øvelse. Både `WeaponItem` og `PotionItem` kan derfor tilføjes.


2. Gør InventoryManager global

For at inventory overlever sceneskift, skal `InventoryManager` oprettes som en Autoload.

  1. Åbn Project → Project Settings → Globals → Autoload. Menunavnet kan variere lidt mellem Godot-versioner.
  2. Vælg filen `InventoryManager.cs`.
  3. Angiv navnet `InventoryManager`.
  4. Aktivér Autoload. (markér checkbox 'Enabled')

Godot opretter nu en global instans af `InventoryManager`, som ikke bliver fjernet, når en almindelig scene skiftes ud.

Du kan tilgå den fra C# med:

GetNode<InventoryManager>("/root/InventoryManager");

3. Opret ItemPickup

Opret et script med navnet `ItemPickup.cs`. Det sættes på en `Area2D`, som spilleren kan gå ind i for at samle et item op.

using Godot;
 
public partial class ItemPickup : Area2D
{
    [Export]
    public Item Data { get; set; }
 
    public override void _Ready()
   {
	_sprite = GetNode<Sprite2D>("Sprite2D");
 
	if (item != null)
	{
	    _sprite.Texture = item.Icon;
         }
	    BodyEntered += OnBodyEntered;
   }
 
    private void OnBodyEntered(Node2D other)
    {
        if (other is Player)
        {
            var inventory = GetNode<InventoryManager>("/root/InventoryManager");
 
            inventory.AddItem(Data);
            QueueFree();
        }
    }
}

Bemærk: `Player` skal svare til navnet på jeres spillers C#-klasse.


4. Opsæt pickup-scenen

Opret følgende nodestruktur:

ItemPickup (Area2D)
├── Sprite2D
└── CollisionShape2D
  1. Tilføj `ItemPickup.cs` til `Area2D`.
  2. Opret en `CollisionShape2D`, der dækker det område, spilleren skal ramme.
  3. Sørg for, at `Area2D` har `Monitoring` aktiveret.
  4. Forbind signalet `body_entered` til metoden `OnBodyEntered`.
  5. Tildel en konkret `Item`-resource til egenskaben `Data` i Inspector.

Du kan nu genbruge samme pickup-scene til eksempelvis `Sword.tres`, `HealthPotion.tres` og `IronArmor.tres`.


5. Test sceneskift

  1. Start spillet i en scene med et item.
  2. Gå hen til item'et, og saml det op.
  3. Skift til en anden scene.
  4. Undersøg `InventoryManager.Items`, eller udskriv indholdet i Output.

Tilføj eventuelt denne metode til `InventoryManager` for at teste indholdet:

public void PrintItems()
{
    foreach (Item item in Items)
    {
        GD.Print(item.Name);
    }
}

Kald metoden fra et passende sted i spillet, når du vil kontrollere inventory.


6. Hvorfor virker det?

En almindelig scene bliver fjernet, når spillet skifter til en anden scene. En Autoload-instans lever derimod videre, mens spillet kører.

Inventory ligger derfor ikke i den scene, spilleren forlader, men i en global instans.

Vigtigt: Hvad gemmes egentlig?

Opgave

  1. Opret en `HealthPotion.tres` baseret på `PotionItem`.
  2. Placér en potion i én scene og et sværd i en anden.
  3. Saml begge items op.
  4. Skift mellem scenerne, og kontrollér, at inventory stadig indeholder begge items.
  5. Forklar, hvorfor `InventoryManager` skal være en Autoload, og hvorfor det er praktisk at lade inventory indeholde `Item` i stedet for kun `WeaponItem`.

Opsummering