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:
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 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.
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.
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.
public partial class WeaponData : Resource
WeaponData arver fra Godots Resource-klasse. Derfor kan vi oprette og gemme objekter af denne type som ressourcer.
[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] 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.
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.
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.
Nu skal vi bruge klassen til at oprette tre våben.
I Godot-editoren:
WeaponData..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.
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:
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.
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 en scene med følgende struktur:
WeaponPickup (Area2D) └── Sprite2D
Opret et C#-script med navnet WeaponPickup.cs, og tilknyt det til Area2D-noden.
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(); } } }
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.
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.tresHver pickup kan nu bruge de data, der hører til det valgte våben.
Du genbruger den samme C#-kode, men ændrer ressourcefilen.
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.
Nu skal du selv arbejde med Resources.
WeaponData.cs.Knife.tres, Sword.tres og Spear.tres.WeaponPickup-scene med en Area2D og en Sprite2D.WeaponPickup.cs.Sword.tres til egenskaben Data.Knife.tres og derefter Spear.tres.Opret et nyt våben, som passer til dit eget spil.
Du skal:
WeaponData-klasse..tres-fil med egne værdier.Du må ikke oprette en ny C#-klasse alene for at repræsentere det nye våben.
Besvar spørgsmålene med dine egne ord.
WeaponData.cs og Sword.tres?WeaponPickup adgang til våbnets skadeværdi?En Resource gør det muligt at adskille data fra den kode, der bruger dataene.
I denne guide har vi:
WeaponData.WeaponPickup-Node.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.