• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
6
Question by supremegrandruler · Dec 27, 2014 at 09:36 PM · function-type

How can I find all objects that have a script that implements a certain interface?

And also run functions implemented from the interface?

Right now I have this:

             IStats[] ss = (IStats[])FindObjectsOfType (typeof(IStats));
             foreach (IStats s in ss) {
                 enemies.Add (s);
             }

Then I do this:

                 foreach (IStats enemy in enemies) {
                     enemy.Damage (damage, (int)element);
                     enemies.Remove (enemy);
                 }


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)

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

6 Replies

· Add your reply
  • Sort: 
avatar image
30
Best Answer

Answer by Lichter · Mar 17, 2018 at 03:46 PM

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.

Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image brainwipe · Jun 26, 2018 at 06:32 AM 0
Share

I came here to write this! Thank you for saving me the effort. :)

avatar image alkohol · Jul 31, 2019 at 11:20 AM 3
Share

That approach is worse on performance and garbage creating. @glitchers solution with running through root objects in scenes is faster

avatar image Lichter alkohol · Jul 31, 2019 at 12:53 PM 1
Share

@alkohol Good to know. I'll keep that in my back pocket in case this solution ever becomes a real bottleneck.

avatar image Mikael-H alkohol · Sep 26, 2020 at 05:28 PM 1
Share

if the performance of this call is of concern to you then you have bigger problems than optimizing it a little bit like 10x. $$anonymous$$ethods like these should NOT be used in any hot path

avatar image aurelien-defossez · Jun 20, 2020 at 12:58 PM 0
Share

You don't have to create a List, and directly go with a pure Linq query, increasing the performance of the solution:

 public static IEnumerable<T> FindInterfacesOfType<T>(bool includeInactive = false)
 {
     return Scene$$anonymous$$anager.GetActiveScene().GetRootGameObjects()
             .Select$$anonymous$$any(go => go.GetComponentsInChildren<T>(includeInactive));
 }
avatar image Lichter aurelien-defossez · Aug 11, 2020 at 02:33 PM 0
Share

Just be careful if you have more than one active scene.

avatar image
2

Answer by ilya_ca · Jan 14, 2015 at 01:09 PM

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.

Here's the link: Interface Finder

Usage example:

 var stuff = InterfaceHelper.FindObject<IIrresistible>();
 var component = transform.GetInterfaceComponent<IIrresistible>();


Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Helical · Sep 29, 2015 at 01:12 AM 0
Share

About your interface finder.

I have a Script that inherits from another Script that inherits from $$anonymous$$onoBehaviour attached as a Component to one of my Game Objects in the scene.

 public abstract class $$anonymous$$obSpawner : $$anonymous$$onoBehaviour, ITerrainRequester {

 public class $$anonymous$$obSpawnerWave : $$anonymous$$obSpawner {

The function

  IList<ITerrainRequester> terrainYearners = InterfaceHelper.FindObjects<ITerrainRequester>();

returns the interface twice, once as the base class, and once as the child class.

avatar image ilya_ca Helical · Sep 29, 2015 at 03:44 PM 0
Share

@Helical this is the expected behavior - both of the classes implement this interface, therefore the InterfaceHelper will return both of them.

avatar image Helical ilya_ca · Sep 29, 2015 at 07:04 PM 1
Share

But its the same component! The desire was to find all Objects that have a script that implements the interface.

avatar image
0

Answer by IMD · Dec 05, 2017 at 07:58 PM

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[i].transform.GetComponent<T>()) != null) {
                     foundGameObject = gos[i];
                     return true;
                 }
             }
             return false;
         }

Cheers, Isaac :)

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
7

Answer by glitchers · Jun 11, 2018 at 09:08 AM

Here is my solution.

  1. Get all root GameObjects in scene

  2. Use GetComponentsInChildren on each (it works with Interfaces)

  3. Return list of interfaces found

Here's the code:

Gist: https://gist.github.com/glitchersgames/c1d33a635fa0ca76e38de0591bb1b798

 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;
         }
     }
 }




Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image alkohol · Jul 31, 2019 at 10:15 AM 0
Share

Additionally I made a little test and I think this solution is more preferable because of performance. Next results I became on 10k runs:

  • 3 seconds on this solution

  • 15 seconds on FindObjectsOfType`$$anonymous$$onoBehaviour+Linq solution

  • 56 seconds on FindObjectsOfType`Object+Linq solution

As you can see this solution is about 5 times faster in simplest case (18+ times in case with selecting through UnityEngine.Object).

Except that solution with Linq will provide more garbage for GC.

Below is snippet for testing:

         private void Awake()
         {
             var t1 = Test1<IEntity>();
             var t2 = Test2<IEntity>();
         }
 
         private List<T> Test1<T>()
         {
             List<T> results = new List<T>();
             Stopwatch sw = new Stopwatch();
             sw.Start();
             for (int k = 0; k < 10000; k++)
             {
                 for (int i = 0; i < Scene$$anonymous$$anager.sceneCount; i++)
                 {
                     var rootObjects = Scene$$anonymous$$anager.GetSceneAt(i).GetRootGameObjects();
                     foreach (var root in rootObjects)
                     {
                         results.AddRange(root.GetComponentsInChildren<T>(true));
                     }
                 }
             }
             sw.Stop();
             UnityEngine.Debug.LogError($"Test1[{results.Count} found] time elapsed: {sw.Elapsed$$anonymous$$illiseconds} ms");
             return results;
         }
 
         private List<T> Test2<T>()
         {
             List<T> results = new List<T>();
             Stopwatch sw = new Stopwatch();
             sw.Start();
             for (int k = 0; k < 10000; k++)
             {
                 results.AddRange(FindObjectsOfType<UnityEngine.Object>().OfType<T>());
             }
             sw.Stop();
             UnityEngine.Debug.LogError($"Test2[{results.Count} found] time elapsed: {sw.Elapsed$$anonymous$$illiseconds} ms");
             return results;
         }

 

Result is next:

Test1[820000 found] time elapsed: 2939 ms // <-- using GetComponentsInChildren

Test2[820000 found] time elapsed: 15001 ms // <-- using FindObjectsOfType`$$anonymous$$onoBehaviour + Linq

Test2[820000 found] time elapsed: 55911 ms // <-- using FindObjectsOfType`Object + Linq

avatar image
0

Answer by Free286 · Jan 09, 2019 at 11:01 AM

This should do the trick to find a single object.

     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);
     }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Lichter · Jan 09, 2019 at 01:58 PM 0
Share

Or just use LINQ: using System.Linq; ... return FindObjectsOfType<$$anonymous$$onoBehaviour>().OfType<IStats>().FirstOrDefault();

Depending on your needs you should also consider LastOrDefault, SingleOrDefault, First, Last, and Single. Each provides different behavior when multiple or none are found.

  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

14 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Yield on a Function Typed Variable 0 Answers

syntax error woe 0 Answers

Stop all instances of same coroutine? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges