Ha egy darab létezik egy komponensből, akkor az elérhető a FindObjectOfType() metódussal.
Ennél jóval gyorsabb megoldást ad a Singleton vagy a ServiceLocator pattern: Látsd: Singleton és Service Locator
Ehhez hasonlóan egy sok példányban létező komponens tömbjét megkaphatjuk a FindObjectsOfType() lekérdezni, de tudjuk ezt a lekérdezést jóval gyorsabbá is tenni saját kóddal.
Ehhez egy adott típushoz létre kell hoznunk egy statikus listát és gondoskodnunk róla, hogy az egyes objektumok létrejöttükkor és megszűnésük idejében regisztrálják majd töröljék magukat ebből a listából.
Erre használható az Awake() és az OnDestroy() MonoBehaviour üzenetmetódusok.
Ha csak az aktív objektumokat szeretnénk számon tartani, akkor pedig az OnEnable() és az OnDisable() eljárások használatosak.
Példakód:
class TestComponent : MonoBehaviour
{
static readonly List<TestComponent> activeTestComponents = new();
public static IReadOnlyList<TestComponent> AllActives => activeTestComponents;
void OnEnable()
{
activeTestComponents.Add(this);
}
void OnDisable()
{
activeTestComponents.Remove(this);
}
}// Példa a használatára: Végigiterálás az összes aktív TestComponent-en
foreach(TestComponent testComponent in TestComponent.AllActives)
{
//...
}A lekérdezéshez használtam a IReadOnlyList interface-et, ami a listának csak lekérdező metódusait tartalmazza. Segítségével elérhető, hogy kívülről semmiképp ne lehessen módosítani a listát.
Object Finder
A Singleton-t leválthattuk egy Service Locator-ral annak érdekében, hogy támogatni tudjuk az absztrakciót (interface-eket és absztrakt osztályokat).
Ennek mintájára a több számban létező objektumokra is létrehozhatunk egy ObjectFinder-t, ami hasonló módon működik majd, mint a Service Locator, de ahelyett, hogy minden típusból egyet tárolnánk el, egy egész listát fogunk.
Mindezt egy statikus Dictionary-val végezzük, amiben egy-egy típushoz társítunk egy listát az adott típus elemeiből a következőképp:
Használat:
// Típus definíciók és regisztráció a ComponentLocator-ba:
interface IExampleInterface { /* ... */ }
class TestComponent : MonoBehaviour, IExampleInterface
{
void Awake()
{
ObjectFinder.Add<IExampleInterface>(this);
}
void OnDestroy()
{
ObjectFinder.Remove<IExampleInterface>(this);
}
}//Lekérdezés:
IReadOnlyList<IExampleInterface> all = ObjectFinder.GetAll<IExampleInterface>();Ahogy a saját Sercice Locator a FindObjectOfType-ot tudja jóval optimálisabban leváltani, úgy az imént megírt megoldás gyakorlatilag a FindObjectsOfType metódust helyettesíti.
Az ObjectFinder előnyei a FindObjectsOfType -hoz képest:
- Képes abstrakció (interface és absztrakt osztály)alapján keresni
- Nem termel memóriaszemetet
- Futása összehasonlíthatatlanul gyorsabb
Alább egy kísérlet eredménye látható, ahol 5000 objektumot kerestem meg 5000-szer a FindObjectsOfType valamint a fenti saját ObjectFinder segítségével:
Az ObjectFinder hátránya a FindObjectsOfType -hoz képest:
- A regisztrációt és unregisztrációt manuálisan kell végezni.