Indholdsfortegnelse
Brug af Resources i Godot
Introduktion
Forestil dig, at du udvikler et RPG, hvor spilleren kan finde forskellige våben. Et sværd gør 10 i skade, en kniv gør 5, og et spyd har længere rækkevidde.
Hvordan kan vi beskrive alle disse våben uden at skrive en ny C#-klasse for hvert våben?
Her kan vi bruge en Resource i Godot.
En Resource er et objekt, der kan indeholde data og gemmes som en fil. Den kan eksempelvis beskrive et våbens navn, skade, rækkevidde og ikon.
Resources kan også bruges til fjender, rustninger, healing items, lyde, teksturer og meget andet.
I denne guide lærer du at:
- Oprette en Resource i C#.
- Oprette forskellige ressourcefiler ud fra den samme klasse.
- Bruge ressourcerne i dine spilscener.
- Forstå forskellen mellem en Resource og en Node.
1. Resource kontra Node
I Godot bruger vi både Resources og Nodes, men de har forskellige roller.
| Resource | Node |
|---|---|
| Indeholder eller beskriver data. | Indgår i scenetræet. |
Kan gemmes som en .tres-fil. | Bruges til at opbygge spilobjekter og scener. |
| Kan deles mellem flere Nodes. | Kan håndtere eksempelvis input, bevægelse og kollisioner. |
Eksempel: WeaponData. | Eksempel: WeaponPickup eller CharacterBody2D. |
Forestil dig et sværd i dit spil:
- En Resource beskriver sværdet: navn, skade, rækkevidde og ikon.
- En Node kan repræsentere sværdet i spillet og håndtere, hvad der sker, når spilleren samler det op.
En Resource behøver ikke at være en del af scenetræet. Den kan bruges af en eller flere Nodes, der har brug for dens data.
2. Sådan fungerer en Resource
Vi skal bruge tre dele:
| Del | Formål | Eksempel |
|---|---|---|
| Klasse | Definerer, hvilke egenskaber dataene har. | WeaponData.cs |
| Ressourcefil | Indeholder værdierne for et bestemt våben. | Sword.tres |
| Bruger | Læser og anvender dataene. | WeaponPickup.cs |
Vi kan illustrere det sådan:
WeaponData.cs
|
+-- Sword.tres
|
+-- Knife.tres
|
+-- Spear.tres
|
v
WeaponPickup
|
v
Player / spillet
Vi skriver altså én klasse, men kan oprette mange forskellige ressourcefiler ud fra den.
Vigtigt: Det er klassens struktur, vi genbruger. Hver ressourcefil kan indeholde sine egne værdier.
3. Opret klassen WeaponData
Først skal vi definere, hvilke data et våben skal indeholde.
Opret et nyt C#-script med navnet WeaponData.cs.
using Godot; [GlobalClass] public partial class WeaponData : Resource { [Export] public string Name { get; set; } = "Default Weapon"; [Export] public int Damage { get; set; } = 10; [Export] public int Range { get; set; } = 40; [Export] public Texture2D Icon { get; set; } }
Lad os gennemgå de vigtigste dele.
Klassen arver fra Resource
public partial class WeaponData : Resource
WeaponData arver fra Godots Resource-klasse. Derfor kan vi oprette og gemme objekter af denne type som ressourcer.
GlobalClass
[GlobalClass]
Attributten gør klassen tilgængelig som en global type i Godot-editoren. Det gør det nemmere at oprette nye ressourcer af typen WeaponData.
Export
[Export] public int Damage { get; set; } = 10;
Attributten [Export] gør egenskaben tilgængelig i Godot-editorens Inspector.
Du kan dermed ændre våbnets skadeværdi uden at ændre C#-koden.
Hvorfor bruger vi properties?
I C# bruger vi ofte properties med get og set til at repræsentere data, som andre dele af programmet skal kunne læse og ændre.
Godot kan eksportere disse properties til Inspector, så længe typen understøttes.
Kompilér projektet
Når du har oprettet klassen, skal du bygge/kompilere dit C#-projekt.
Godot skal registrere den nye klasse, før du kan oprette ressourcer af typen WeaponData.
Hvis typen ikke vises i editoren, skal du kontrollere, at filnavnet og klassenavnet stemmer overens, og at projektet kompilerer uden fejl.
4. Opret tre forskellige våben
Nu skal vi bruge klassen til at oprette tre våben.
I Godot-editoren:
- Find FileSystem-panelet.
- Højreklik i den mappe, hvor du vil gemme våbnene.
- Vælg at oprette en ny Resource.
- Find og vælg typen
WeaponData. - Udfyld egenskaberne i Inspector.
- Gem ressourcen som en
.tres-fil.
Opret følgende tre ressourcer:
| Ressourcefil | WeaponName | Damage | Range |
|---|---|---|---|
Knife.tres | Knife | 5 | 20 |
Sword.tres | Sword | 10 | 40 |
Spear.tres | Spear | 8 | 70 |
Tildel eventuelt et ikon til hvert våben.
Du har nu tre forskellige ressourcer, som alle er oprettet ud fra den samme klasse.
Hvad har vi opnået?
Vi har ikke skrevet tre forskellige klasser. Vi har skrevet én klasse, der beskriver strukturen for et våben.
De tre ressourcefiler indeholder forskellige værdier:
- Kniven gør 5 i skade og har en rækkevidde på 20.
- Sværdet gør 10 i skade og har en rækkevidde på 40.
- Spyddet gør 8 i skade og har en rækkevidde på 70.
Vi kan ændre disse værdier direkte i Inspector.
Det er en af de store fordele ved Resources: Vi kan adskille data fra den kode, der bruger dataene.
5. Brug ressourcen i spillet
Nu skal vi bruge vores ressourcer i en Node.
Vi opretter en WeaponPickup, der repræsenterer et våben, som spilleren kan samle op.
Opret scenen
Opret en scene med følgende struktur:
WeaponPickup (Area2D) └── Sprite2D
Opret et C#-script med navnet WeaponPickup.cs, og tilknyt det til Area2D-noden.
WeaponPickup.cs
using Godot; public partial class WeaponPickup : Area2D { [Export] public WeaponData Data { get; set; } private Sprite2D _sprite; public override void _Ready() { _sprite = GetNode<Sprite2D>("Sprite2D"); BodyEntered += OnBodyEntered; if (Data == null) { GD.PushWarning( "WeaponPickup mangler en WeaponData-ressource." ); return; } _sprite.Texture = Data.Icon; GD.Print($"Våben: {Data.Name}"); GD.Print($"Skade: {Data.Damage}"); GD.Print($"Rækkevidde: {Data.Range}"); } private void OnBodyEntered(Node2D other) { if (Data == null) { return; } if (other is Player player) { player.PickupWeapon(Data); QueueFree(); } } }
Hvad sker der i koden?
1. Vi eksporterer en reference til ressourcen
[Export] public WeaponData Data { get; set; }
Denne property gør det muligt at tilknytte en WeaponData-ressource i Inspector.
Det betyder, at vi kan vælge mellem Knife.tres, Sword.tres og Spear.tres uden at ændre scriptet.
2. Vi bruger dataene
_sprite.Texture = Data.Icon;
Vi bruger ikondataene fra ressourcen til at vise våbnet i spillet.
På samme måde kan vi læse:
Data.WeaponName Data.Damage Data.Range
3. Vi håndterer opsamling
if (other is Player player) { player.PickupWeapon(Data); QueueFree(); }
Når spilleren kommer ind i området, sendes ressourcen videre til spillerens PickUpWeapon-metode. Derefter fjernes pickup-noden.
Du skal selv have en passende PickUpWeapon(WeaponData data)-metode i dit Player.cs-script. Metoden skal håndtere, hvad spillet skal gøre med våbnets data. f.eks.
public void PickupWeapon(WeaponData data){ GD.Print("PLAYER PICKED UP WEAPON: "+ data ); }
Husk også, at spillerens collision skal kunne registreres af Area2D, og at scenens collision layers og masks skal være sat korrekt.
Tilknyt ressourcen i Inspector
Vælg din WeaponPickup-node.
I Inspector finder du egenskaben Data. Her kan du tilknytte en af dine ressourcefiler.
Prøv at oprette tre pickup-scener eller tre instanser, hvor du vælger henholdsvis:
Knife.tresSword.tresSpear.tres
Hver pickup kan nu bruge de data, der hører til det valgte våben.
Du genbruger den samme C#-kode, men ændrer ressourcefilen.
6. En vigtig detalje: Delte ressourcer
En Resource kan bruges af flere Nodes. Men det er vigtigt at forstå, at flere Nodes som udgangspunkt kan referere til den samme ressourceinstans.
Forestil dig, at to våben-pickups bruger den samme Sword.tres-ressource.
Hvis den ene Node ændrer Data.Damage, kan den anden Node også opleve ændringen, fordi begge refererer til den samme ressourceinstans.
Det er normalt ikke et problem, hvis ressourcen bruges til at beskrive faste våbendata.
Men hvis du vil gemme individuelle værdier for hvert våben under spillet, skal du overveje, om du har brug for separate ressourceinstanser eller en anden datastruktur.
Husk: Resources er gode til data, som kan genbruges. De er ikke automatisk separate kopier, blot fordi flere Nodes bruger dem.
7. Øvelse: Tre våben – én Resource
Nu skal du selv arbejde med Resources.
Opgave A: Opret ressourcerne
- Opret klassen
WeaponData.cs. - Kompilér projektet.
- Opret
Knife.tres,Sword.tresogSpear.tres. - Giv hvert våben de værdier, der fremgår af tabellen i afsnit 4.
- Tildel et ikon til hvert våben.
Opgave B: Brug ressourcerne
- Opret en
WeaponPickup-scene med enArea2Dog enSprite2D. - Tilknyt
WeaponPickup.cs. - Tildel
Sword.trestil egenskabenData. - Kør spillet, og kontrollér outputtet i Godots Output-panel.
- Skift til
Knife.tresog derefterSpear.tres. - Kontrollér, at navn, skade og rækkevidde ændres uden ændringer i C#-koden.
Opgave C: Udvid dit spil
Opret et nyt våben, som passer til dit eget spil.
Du skal:
- Bruge den eksisterende
WeaponData-klasse. - Oprette en ny
.tres-fil med egne værdier. - Tilknytte ressourcen til en pickup.
- Undersøge, hvordan våbnets skade og rækkevidde kan bruges i spillets kampsystem.
Du må ikke oprette en ny C#-klasse alene for at repræsentere det nye våben.
8. Kontrolspørgsmål
Besvar spørgsmålene med dine egne ord.
- Hvad er en Resource i Godot?
- Hvad er forskellen på
WeaponData.csogSword.tres? - Hvorfor kan vi oprette mange forskellige våben ud fra én klasse?
- Hvad er forskellen på en Resource og en Node?
- Hvordan får
WeaponPickupadgang til våbnets skadeværdi? - Hvad sker der, hvis flere Nodes deler den samme ressourceinstans?
- Hvilke fordele giver det at adskille data fra den kode, der anvender dataene?
9. Fejlfinding
Opsummering
En Resource gør det muligt at adskille data fra den kode, der bruger dataene.
I denne guide har vi:
- Oprettet én klasse,
WeaponData. - Oprettet flere ressourcefiler med forskellige våbendata.
- Brugt ressourcerne fra en
WeaponPickup-Node. - Undersøgt forskellen mellem Resources og Nodes.
Den vigtigste pointe er, at én klassedefinition kan bruges til mange forskellige datasæt.
Det gør det lettere at tilføje nye våben, ændre værdier og vedligeholde dit spil uden at skulle skrive en ny klasse for hvert våben.
