A GameObject-ek azonosítása fejezetben átnéztük, hogy miért érdemes komponens szerinti keresést használni egy típusú GameObject megkeresésére.
Ekkor tisztáztuk, hogy egyáltalán nem értelmetlen dolog teljesen üres osztályokat létrehozni csak azért, hogy azokkal megjelöljünk GameObject-eket.
A módszer egyetlen hátránya, hogy ilyen tag-nek használt komponenst egyedül programozó tud felvenni. Ez akkor lehet gond, ha ez a tagrendszer alapvető része a játéknak és beállításuk felett teljes kontrolt szeretnénk adni dizájnerek kezébe.
Példa
Például egy olyan játékot írunk, amiben minden objektum egy adott fajhoz, csapathoz vagy frakcióhoz tartozik. Nem akarjuk egyenként kóddal leírni a ezen frakciókat és a kapcsolataikat. Helyette egy keretrendszert is készíthetünk, amiben a dizájner dönt minderről kódolás nélkül.
Nevezzük ezt a “frakciót” Team
-nek és valósítsuk meg egy ScriptableObject-ként.
using UnityEngine;
[CreateAssetMenu(menuName = "Teams/Team")]
class Team : ScriptableObject
{
[SerializeField] Color teamColor; // Csapatszín
public Color TeamColor => teamColor; // Csapatszínt lekérdező property
}
Csak hogy ne legyen teljesen üres a Team
osztály adtam neki egy csapatszín beállítást és hozzá egy lekérdező property-t. Gondoltam ez a jövőben úgyis hasznos lesz valamire. Ezt a lépést azonban nyugodtan ki is hagyhattam volna egyelőre és lehetne a ScriptableObject osztály teljesen üres is.
Ezután létrehozhatok annyi példányt ebből amennyit szeretnék:
Most hozzuk létre a MonoBehaviour osztályunkat, amivel bármely GameObject-hez adhatunk csapatot.
using UnityEngine;
class TeamMember : MonoBehaviour
{
[SerializeField] Team team; // Csapat
public Team Team => team; // Csapatot lekérdező property
}
Használjuk az önregisztráció módszerét, hogy minden számon tartsunk minden minden egyes csapa minden egyes tagját.
Ehhez most egy Dictionary-t fogok használni (Egyéb adatszerkezetek ), amiben elteszem minden egyes csapathoz az összes csapattag listáját. Emellett egy statikus lekérdező függvényt is hozzáadok mindehhez.
Az alábbi kódot a TeamMember-en belülre írom:
// Az üsszes csapat összes tagját számontartó dictionary
static Dictionary<Team, List<TeamMember>> members = new();
// Minden csapattag regisztálja magát
void OnEnable()
{
// Csak ha van capat bekötve. Egyébként ERROR
if (team == null)
{
Debug.LogError($"TeamMember {name} has no team assigned", this);
return;
}
// Ha mi regisztálunk először a csapatunkba, akkor létre kell hozni a listá is.
if (!members.ContainsKey(team))
members.Add(team, new List<TeamMember>());
// Felírjuk magunkat a listánkba!
members[team].Add(this);
}
// Minden csapattag törli magát
void OnDisable() => members[team].Remove(this);
// Satikus lekérdezés => Visszaadja egy csapat összes aktív tagját.
public static List<TeamMember> GetMembers(Team team) => members[team];
// Még szebb lenne IReadOnlyList-et használni a lekérdezésnél így:
// public static IReadOnlyList<TeamMember> GetMembers(Team team) => members[team];
Ezután bárki bárhonnan könnyedén lekérdezheti az egy csapathoz tartozó összes csapattagot.
Hogy ez mire használjuk azt ettől a pontól kezdve nem is számít. Vegyünk pár példát:
- Írhatunk egy komponenst, ami automatikusan színez egy SpriteRender-t a csapata színére. Ezáltal nem kéne ezt manuálisan megenni minden csapatra.
- Írhatunk karaktereket, akik megtámadják az ellenséges csapatok tagjait ha elég közel érnek
- Írhatunk szövetség rendszert, amiben meg tudjuk adni, mely csapatok barátságosak és melyek ellenségek.
- Írhatunk ételt, amit csak bizonyos csapatok tudnak megenni.
- … Határ a képzeletünk …