But I’m getting an error when running the game:
FindAllObjectsOfType: The type has to be derived from UnityEngine.Object. Type is IStats.
UnityEngine.Object:FindObjectsOfType(Type)
Projectiles.c__Iterator3:MoveNext() (at Assets/Scripts/Projectiles/DemonStar.cs:25)
These answers are unnecessarily complex. Just use LINQ.
using System.Linq;
...
var ss = FindObjectsOfType<MonoBehaviour>().OfType<IStats>();
foreach (IStats s in ss) {
enemies.Add (s);
}
If you’re looking for something that isn’t a subclass of MonoBehaviour, then just broaden the search by replacing MonoBehaviour in the snippet above with Behaviour, Component, or Object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Glitchers
{
public static class FindInterfaces
{
public static List<T> Find<T>( )
{
List<T> interfaces = new List<T>();
GameObject[] rootGameObjects = SceneManager.GetActiveScene().GetRootGameObjects();
foreach( var rootGameObject in rootGameObjects )
{
T[] childrenInterfaces = rootGameObject.GetComponentsInChildren<T>();
foreach( var childInterface in childrenInterfaces )
{
interfaces.Add(childInterface);
}
}
return interfaces;
}
}
}
I’ve thought on this problem and came up with a solution that looks for all types that implement a given interface at initialization (in a static constructor), adds them to a lookup table, and then uses that table at runtime to find required objects. This solution is almost as fast as Unity’s built-in FindObjectsOfType() method.
public static T FindOfType<T>() where T : class {
foreach(var monoBehaviour in GameObject.FindObjectsOfType<MonoBehaviour>()) {
if (monoBehaviour is T) {
return monoBehaviour as T;
}
}
return default(T);
}
A bit of an oldie, but hopefully this might help some folks out… This will return True along with references to the first found gameobject with a component that is of type T (or implements an interface of type T), or False if not found in the active scene.
public static bool TryFindGameObjectWithType<T>(ref GameObject foundGameObject, ref T foundObject)
{
GameObject[] gos = UnityEngine.Object.FindObjectsOfType<GameObject>();
for (int i = 0; i < gos.Length; i++) {
if ((foundObject = gos*.transform.GetComponent<T>()) != null) {*
Hi,
I tried out some different versions and thought I would continue the post here.
My InterfaceService looks like this:
public static class InterfaceService
{
public static IEnumerable<T> FindOnActiveScene<T>(bool includeInactive = false)
{
return SceneManager.GetActiveScene().GetRootGameObjects().SelectMany(go => go.GetComponentsInChildren<T>(includeInactive));
}
public static IEnumerable<T> FindOnAllScenes<T>(bool includeInactive = false)
{
return Enumerable.Range(0,SceneManager.sceneCount).SelectMany(sceneIndex => SceneManager.GetSceneAt(sceneIndex).GetRootGameObjects().SelectMany(go => go.GetComponentsInChildren<T>(includeInactive)));
}
public static IEnumerable<T> FindOnDontDestroyOnLoad<T>(bool includeInactive = false)
{
return DontDestroyOnLoadAccessor.GetInstance().GetRootGameObjects().SelectMany(go => go.GetComponentsInChildren<T>(includeInactive));
}
public static IEnumerable<T> FindGeneral<T>(bool includeInactive = false) {
return Object.FindObjectsOfType<MonoBehaviour>(includeInactive).OfType<T>();
}
}
With a singleton that uses DontDestroyOnLoad to get the scene of the DontDestroyOnLoad objects
public class DontDestroyOnLoadAccessor : PersistentSingleton<DontDestroyOnLoadAccessor>
{
public GameObject[] GetRootGameObjects() {
return this.gameObject.scene.GetRootGameObjects();
}
}
I also ran a test to see how fast they where by running each of the 10000 times in a row.
FindOnActiveScene Execution Time: 7 ms, with count: 0
FindOnDontDestroyOnLoad Execution Time: 7 ms, with count: 3
FindGeneral Execution Time: 1386 ms, with count: 3
FindOnAllScenes Execution Time: 2 ms, with count: 0
As you can see only FindGeneral() and FindOnDontDestroyOnLoad finds the gameobjects with the interface when it has a component using DontDestroyOnLoad.
I do not know why FindOnActiveScene is so much slower than FindOnAllScenes, they should have been close since I only have one scene. Maybe the GetActiveScene() method does something slightly demanding.