Find GameObjects in Specific Scene only?

Now that we can SceneManager.LoadScene ( .. , {ADDITIVE}), is there a method or a way to (FASTER) find all objects in a SPECIFIC SCENE?

Something like the old GameObject.Find, but with maybe secondary optional attribute of scene_Id/scene_name like this:

GameObject.Find ("object_name", "scene_name");

I checked docs but didn’t see anything new in this regard. Id like to only search in specific scene (and save time - save BIG for bigger scenes). Should i create Feature request for this? What do You think?

GameObject.find will find only what is currently in the scene hierarchy.. What do u mean by specific scene?

Feature request for what? All you need is at your disposal. GameObject.Find searches for gameobjects in the current scene. I don't think you can find objects that are in other scenes. If you want speed you might want a class that caches your Gameobject in a dictionary or something...

GameObject.Find does find objects that are in other scenes as well. Thats why after i realized this, i wondered is there a faster way. By specific scene i mean.. lets say you have "Main" scene that you load other scenes into.. Additively. So say in my Additively loaded Child scene i dont want GameObject.Find to search my Base Scene wasting cpu cycles.

4 Answers

4

I don’t know if you are still looking for a solution. You can get all the objects from a scene using this:

// get a reference to the scene you want to search. 
Scene s = SceneManager.GetSceneByName("sceneName");
GameObject[] gameObjects = s.GetRootGameObjects();

Then search through the array. This should work with additive scenes.

If you’re deeply concerned about time, then using GameObject.Find probably isn’t the best choice to begin with. As for executing code in specific scenes, you can use the GetActiveScene() method.

if( SceneManagement.Scene GetActiveScene().name=="Scene 3" )
{
    // execute
}

Might not work with additive though, I don’t have 5-3 installed to test.

I do understand GameObject.Find is pretty slow. I already disregarded GameObject.FindObjectsOfType, and i can not use Tags or Layers in my particular use-case for seaching. Now im not aware of any other methods i could use to search for GameObjects. Either looking for fast GameObject search or Script search utility function. The only other thing i could think of is limit the scope.. to particular Scene perhaps.

If someone needs it:

using UnityEngine;
using UnityEngine.SceneManagement;

public class FindScriptInActiveScene : MonoBehaviour
{
    void Start()
    {
        Scene activeScene = SceneManager.GetActiveScene();

        // Find all instances of MyScript in the active scene
        MyScript[] scripts = FindObjectsByType<BaseSceneGameplayController>(FindObjectsInactive.Include, FindObjectsSortMode.None);

        // Filter for instances that are part of the active scene
        foreach (MyScript script in scripts)
        {
            if (script.gameObject.scene == activeScene)
            {
                Debug.Log("Found MyScript instance in the active scene: " + script.gameObject.name);
                return;
            }
        }
    }
}

If thats the case, then you need to use events and generic lists/dictionaries

An approach like this would be good: (Read about events and delegates)

Attach a script like this for all your gameobjects which you want to be search in scenes

using UnityEngine;
using System.Collections;

public class GameObjectEvents : MonoBehaviour {

	public static event System.Action<GameObject> notifyAwake;
	public static event System.Action<GameObject> notifyDeath;

	// Use this for initialization
	void Start () 
	{
		//Notify if any listeners are present about its awake status
		if(notifyAwake != null)
			notifyAwake(gameObject);
	}

	void OnDestroy()
	{
		// tell any listeners if present that this gameobject is dying
		if(notifyDeath != null)
			notifyDeath(gameObject);
	}

}

and now have this script where you can access the scene specific gameobjects

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class GameObjectEventsHandler : MonoBehaviour {


	

//Dictionary of specific scene gameobjects
	Dictionary<string, List<GameObject>> specificSceneObjects = new Dictionary<string, List<GameObject>>();

//Listen to the events
	void OnEnable()
	{
		GameObjectEvents.notifyAwake += HandlenotifyAwake;
		GameObjectEvents.notifyDeath += HandlenotifyDeath;
	}

	void OnDisable()
	{
		GameObjectEvents.notifyAwake -= HandlenotifyAwake;
		GameObjectEvents.notifyDeath -= HandlenotifyDeath;
	}

	void HandlenotifyAwake (GameObject obj)
	{
		//if there are no objects for this scene then create a new list with the current scene list name
		if(!specificSceneObjects.ContainsKey(Application.loadedLevelName))
			specificSceneObjects.Add(Application.loadedLevelName, new List<GameObject>());

		//now add the gameobject which sent this event upon awake/start to this list
		specificSceneObjects[Application.loadedLevelName].Add(obj);
	}

	void HandlenotifyDeath (GameObject obj)
	{
		//if the dicitonary has this object then remove it upon object destroy
		if(specificSceneObjects.ContainsKey(Application.loadedLevelName))
		{
			if(specificSceneObjects[Application.loadedLevelName].Contains(obj))
				specificSceneObjects[Application.loadedLevelName].Remove(obj);
		}
	}
}

Use scene manager if u r using new unity 5.3

If scene manager can give which scene is currently loading(the additive one) then u will have to feed that value into the dictionary key instead of loaded scene name which will give the one which was loaded before

Now you will have a dictionary of gameobjects for that scene .
and you can access its list like this :

List<GameObject> objList = GameObjectEventsHandler.specificSceneObjects["your scene you want"];

now you can iterate through this list to find any object by using list.first or something similar methods

Holy crap, i do understand delegates and what you are trying to do there, but the need to do it for each object to register them sounds like an overkill (i mean may be the same implementation "under the hood" if done by unity team to get the funct i need [still think could be simpler if done by them], but not seeing it wouldnt kill me as much as seeing what you did there. Still at this time ill mark your answer as correct, appreciate the effort, as its also obvious no native functionality exists atm.