Ahhoz, hogy egy komponenst írjunk a Unity-ben, amit aztán hozzáadhatunk egy GameObject-hez le kell származtatni az új saját osztályunkat a MonoBehaviour osztályból. A motor ezután megadott események hatására automatikusan hívogatja ezen osztályok bizonyos speciális metódusait minden betöltött példányra.
Amit most leírtam az a lapja a Unity programozásnak. Minden kezdő játékprogramozó ezt tanulja meg legelőször. Egy csapda azonban, amibe sok kezdő fejlesztő belefut, hogy kizárólag MonoBehaviour osztályokat írnak. Szinte minden játékhoz elengedhetetlen egyéb (akár sehonnan nem öröklő) osztályok írása is. Most azonban a egy másik Unity ősosztályt tekintünk meg, a ScriptableObject-et.
Ahogy egy MonoBehaviour osztály példányait komponensként tudjuk használni, úgy egy ScriptableObject példányaiból speciális Asset fájlokat tudunk készíteni. Ezen asset-eknek nincsenek olyan eseménymetódusai, mint a MonoBehaviour osztályoknak Pl: Start
, Update
, mégis sokkal hasznosabbak, mint azt elsőre gondolnánk.
Elsődleges feladata ezen osztályoknak és a belőlük készült asset fájloknak, hogy adatokat tudunk bennük tárolni Scene-en kívül. Azután ezen asset-eket hozzáköthetjük [SerializeField]
referenciaként MonoBehaviour komponensekhez vagy egyéb ScriptableObject-ekhez.
Miért hasznos ez?
- Újrahasználhatóság: Egy ScriptableObject-et több MonoBehaviour-ból is használhatunk. Ezáltal egy beállítás több helyen is felhasználható lesz. Egy adatot egyszer állítunk be, egy helyen kell módosítani, ám a hatása sok objektumon érzékelhető lehet. A ScriptableObject tehát egy hatékony eszköz az adatok duplikálásának kerüléséhez.
- Játék közbeni szerkeszthetőség: A ScriptableObject-ek nem állnak vissza eredeti állapotba a játék futása végén az Editor-ban, így a fejlesztők bármikor változtathatják azokat anélkül, hogy félniük kéne attól, hogy elveszítik a beállításaikat a Play mód végeztével.
- Jobban strukturált projekt: A ScriptableObject-eket könnyen szervezhetjük és rendszerezhetjük, ami javítja a játék átláthatóságát és segíti az architektúra megértését, kezelését.
- Optimálisabb futás: Az első pontból fakadó előny, hogy a ScriptableObject-ek használatával javítható a játék teljesítménye, mivel azokat a memóriában egyszerre tároljuk, és nem kell többször betölteni őket a játék futása során. Ez kevesebb memóriahasználatot és gyorsabb betöltési időket eredményezhet.
Példa
Tegyük fel, hogy egy térbeli pontszerű eseményhez tartozhat egy hang. Ilyen esemény lehet például egy lépés, amit lejátszatjuk egy adott pontban. Azt is szeretnénk, hogy mondjuk egy lépésnél vagy bármi más ilyen eseménynél több hangot is be lehessen állítani, amik közül mindig csak egy játszódik le véletlenszerűen. Erre létrehozhatunk egy ScriptableObject-et.
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "AudioEffect",
menuName = "ScriptableObjects/AudioEffect", order = 1)]
public class AudioEffect : ScriptableObject
{
[SerializeField] List<AudioClip> clips = new();
public void Play(Vector3 position)
{
if (clips.Count > 0)
{
int randomIndex = Random.Range(0, clips.Count);
GameObject instance = new("AudioEffect");
instance.transform.position = position;
AudioSource source = instance.AddComponent<AudioSource>();
source.clip = clips[randomIndex];
source.Play();
instance.AddComponent<AutoDestroy>();
}
}
}
Ekkor az AudioEffect-ből létrehozhatunk egy példányt, egy file-t mondjuk Step néven: Jobb gomb az Projekct ablakban / ScriptableObjects / AudioEffect.
Ezt a fájlt megfelelően beállíthatjuk a kívánt hangokkal.
Végül a példányt beköthetjük egy vagy több MonoBehaviour-nak, aminek már csak használnia kell. A következő szkript például ott játssza le a beállított AudioEffect-et, ahova kattintunk.
using UnityEngine;
// Ahova kattintunk, ott lejátssza a beállított AudioEffect -et.
public class Clicker : MonoBehaviour
{
[SerializeField] AudioEffect audioEffect;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray cursorRay = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(cursorRay, out RaycastHit hit))
audioEffect.Play(hit.point);
}
}
}
Próbáld ki magad is! A fenti példához még szükséged lesz a következő segéd osztályra is, ami töröl egy GameObject-et a rajta lévő AudioSource lejátszása után.
using UnityEngine;
// Autómatikusan töröl egy objektumot az AudioSource hangjának lejátszása után
public class AutoDestroy : MonoBehaviour
{
void Start()
{
float destroyTime = 0;
AudioSource source = GetComponent<AudioSource>();
if (source != null)
destroyTime = source.clip.length;
Destroy(gameObject, destroyTime); // Késletetett elpustítás
}
}
Hasonló ScriptableObject-et lehetne írni mondjuk ParticleSystem-ekhez is.