Serialize the field from Scriptable in another Scriptable - c#

I have found an interesting "issue" in UnityEditor regarding Scriptable objects. Below is simple example:
I have scriptable class ScriptableExpressionBulder that holds some list and a float field. Then I have another class ScriptableExpressionCreator that holds a LIST of scriptable objects mentioned previously. The code looks like this:
public class ScriptableExpressionBuilder : ScriptableObject
{
public List<MultipleExpressionBuilder> multipleExpressionBuilder;
public float delay;
}
public class ScriptableExpressionCreator : ScriptableObject {
public List<ScriptableExpressionBuilder> List;
}
When creating ScriptableExpressionBuilder the fields from (MultipleExpressionBuilder) comes up nicely but it also adds a second field "delay" at the end (which is perfect to this point).
Now for the interesting part:
The second class ScriptableExpressionCreator holds a list of previous scriptables but it doesn't serialize the "delay" field in this current scriptable. The only field that is serialized is a Scriptable class.
Is there a way to serialize the field from ScriptableExpressionBuilder in another Scriptable that holds a list of these scriptables so I can basically set the delay from where this expressions are called. I could however populate the field in the inspector of original scriptable, but the wouldnt be reusable since each delay is different.

You had the question deleted but I voted to reopen it since I already had started to write the solution and finished just when you deleted it and I think this now does what you want and gives you a good start point for further extending it where needed ;)
That's not really an issue, however, not possible built-in.
For ScriptableObject (and anything else that inherits from UnityEngine.Object) the Inspector by default draws an object field. If you want to draw something else you would need a custom editor script. There is not really away around customizing the Inspector in order to expose fiels of other UnityEngine.Object references in the Inspector of another one.
It could look somewhat like e.g. (for now assuming you only want the delay field to be exposed additionally)
#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
[CustomEditor(typeof(ScriptableExpressionCreator))]
public class ScriptableExpressionCreatorEditor : Editor
{
private SerializedProperty _list;
// I know ... but that's your fault for naming th field List :P
private ReorderableList _listList;
// For Edito this is called when the object gains focus and the Inspector is loaded for this scriptableobject instance
private void OnEnable()
{
// Find and link the serialized field called "List"
_list = serializedObject.FindProperty(nameof(ScriptableExpressionCreator.List));
// Initialize and configure the ReorderableList to draw the referenced elements in the way we want
_listList = new ReorderableList(serializedObject, _list, true, true, true, true)
{
// How is te list header drawn?
drawHeaderCallback = rect => EditorGUI.LabelField(rect, _list.displayName),
// how should each element be drawn?
drawElementCallback = (rect, index, active, focused) =>
{
// get the current element
var element = _list.GetArrayElementAtIndex(index);
// draw the default object reference field with the height of a single line without the label
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), element, GUIContent.none);
// if no object is referenced do nothing more
if (!element.objectReferenceValue) return;
// move one line lower
rect.y += EditorGUIUtility.singleLineHeight;
// get a serializedObject of the reference
var elementsSerializedObject = new SerializedObject(element.objectReferenceValue);
// same as in our own OnInspectorGUI method below loads the current values
elementsSerializedObject.Update();
// for now assuming you only want the delay field
var delay = elementsSerializedObject.FindProperty(nameof(ScriptableExpressionBuilder.delay));
// draw the delay field
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), delay);
// same as in our own OnInspectorGUI method below writes back changed values and handles undo/redo marking dirty etc
elementsSerializedObject.ApplyModifiedProperties();
},
// how do we get the height of one element?
elementHeightCallback = index =>
{
// get the current element
var element = _list.GetArrayElementAtIndex(index);
// if nothing is referenced we only need a single line
if (!element.objectReferenceValue)
{
return EditorGUIUtility.singleLineHeight;
}
// otherwise we need two lines, one for the object field and one for the delay field
return EditorGUIUtility.singleLineHeight * 2;
}
};
}
public override void OnInspectorGUI()
{
// draw the script field
DrawScriptField();
// loads current values into the serialized version
serializedObject.Update();
// draw the list according to the settings above
_listList.DoLayoutList();
// writes bac any changed values into the actual instance and handles undo/redo marking dirty etc
serializedObject.ApplyModifiedProperties();
}
// Draws the default script field on the top the Inspector
private void DrawScriptField()
{
// The script field is disabled since nobody is supposed to evr change it
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField("Script", MonoScript.FromScriptableObject((ScriptableExpressionCreator)target), typeof(ScriptableExpressionCreator), false);
EditorGUI.EndDisabledGroup();
// leave a little space between the script field and the actual inspector conten
EditorGUILayout.Space();
}
}
#endif
For now this would look like this

Related

Unity3D_2019: Adding EventTriggers at runtime

In Unity3D Version 2017 you could add multiple EventTriggers at once by doing this:
for (int i = 0; i < 20; i++)
{
EventTrigger.Entry pDown = new EventTrigger.Entry();
pDown.eventID = EventTriggerType.PointerDown;
pDown.callback.AddListener((eventdata) => { InventorySlotCopy(); });
slots[i].GetComponent<EventTrigger>().triggers.Add(pDown);
EventTrigger.Entry pUp = new EventTrigger.Entry();
pUp.eventID = EventTriggerType.PointerUp;
pUp.callback.AddListener((eventdata) => { InventorySlotInsert(); });
slots[i].GetComponent<EventTrigger>().triggers.Add(pUp);
}
where slots is just an array of GameObjects, each with an Image and an EventTrigger attachted to it.
However, using the same code as above in Unity3D Version 2019 results in adding those EventTriggers but not in assigning the functions to the Listener.
How is that been done in Unity2019?
First of all:
You will not see the added listeners in the Inspector!
In the Inspector you only see the permanent listeners, not the ones added on runtime! These are basically UnityEvent<BaseEventData>'s so see Manual: UnityEvents
When a UnityEvent is added to a MonoBehaviour it appears in the Inspector and persistent callbacks can be added.
The only way to add permanent listeners is either via the Inspector or a custom EditorScript! But this is not what you want to do here anyway.
I would slightly modify your script to make it more secure. I simply log some messages for the methods when they get called to show that they get called.
public class Example : MonoBehaviour
{
// Rather make these directly of type EventTrigger
// So you don't have to use GetComponent later and can be sure that these array only receives
// objects that actually have that Component attached!
public EventTrigger[] slots;
private void Start()
{
// Instead of a hardcoded index either iterate using slots.Length
// or simply directly foreach
foreach (var slot in slots)
{
var pDown = new EventTrigger.Entry
{
eventID = EventTriggerType.PointerDown
};
pDown.callback.AddListener(eventData => { InventorySlotCopy(); });
slot.triggers.Add(pDown);
var pUp = new EventTrigger.Entry
{
eventID = EventTriggerType.PointerUp
};
pUp.callback.AddListener(eventData => { InventorySlotInsert(); });
slot.triggers.Add(pUp);
}
}
private void InventorySlotCopy()
{
Debug.Log(nameof(InventorySlotCopy));
}
private void InventorySlotInsert()
{
Debug.Log(nameof(InventorySlotInsert));
}
}
The rest depends on your setup. We don't know what objects your slots are but there are basically two(three) options:
Option 1 - UI
If these slot objects are UI elements in a Canvas such as Image or Text.
This seems to be the case for your specifically.
Make sure that there is an EventSystem present in the scene.
Usually one gets created when creating the first Canvas.
If not create it now via Hierachy View &rightarrow; right click &rightarrow; UI &rightarrow; EventSystem
Make sure you have the option RayCast Target enabled on your slot's UI Components.
Result:
Options 2 - 3D Objects (Option 3 - 3D Objects with 2D Colliders)
Just adding this for other users.
If these objects are not UI elements but rather 3D objects make sure
Again you need the EventSystem as before
The slots have Collider Components attached to the same GameObject the EvenTrigger Component is attached to or any of its children (it may be nested).
Your Camera needs the Component PhysicsRaycaster attached. Make sure here that the eventMask includes the layer(s) your slot objects are placed on. (For Option 3 using 2D Colliders instead use the Physics2DRaycaster)
Result:
As you can see the methods will not be visible in the Inspector (due to the reason mentioned before) but the added listener methods still get called.

Dynamically render GameObject in Unity C#

I am working on a AR project, where the virtual objects will be shown/hide in the scene based on information found in a text file. The text files will be updated from an external service. So I need to read the file on a frequent interval and update the scene. As a result I only have the Camera object and I am rendering the scene in OnPreCull() method.
The text files contain many objects but not all the objects are within the scene at any instance of time. I was looking for a way to render only those objects that are within the scene.
Will creating and placing the gameobjects in the OnPreCull() method crate any performance issue?
Will creating and placing the gameobjects in the OnPreCull() method crate any performance issue?
Yes absolutely ... so would it if you do it in Update or any other repeatedly called method.
Instead you should rather Instantiate objects in Awake and only activate or deactivate them.
Let's say you have 3 objects A, B and C than I would make a kind of controller class that looks like
public class ObjectsController : MonoBehaviour
{
// Define in which intervals the file should be read/ the scene should be updated
public float updateInterval;
// Prefabs or simply objects that are already in the Scene
public GameObject A;
public GameObject B;
public GameObject C;
/* Etc ... */
// Here you map the names from your textile to according object in the scene
private Dictionary<string, GameObject> gameObjects = new Dictionary<string, gameObjects>();
private void Awake ()
{
// if you use Prefabs than instantiate your objects here; otherwise you can skip this step
var a = Instantiate(A);
/* Etc... */
// Fill the dictionary
gameObjects.Add(nameOfAInFile, a);
// OR if you use already instantiated references instead
gameObjects.Add(nameOfAInFile, A);
}
}
private void Start()
{
// Start the file reader
StartCoroutine (ReadFileRepeatedly());
}
// Read file in intervals
private IEnumerator ReadFileRepeatedly ()
{
while(true)
{
//ToDo Here read the file
//Maybe even asynchronous?
// while(!xy.done) yield return null;
// Now it depends how your textile works but you can run through
// the dictionary and decide for each object if you want to show or hide it
foreach(var kvp in gameObjects)
{
bool active = someConditionDependingOnTheFile;
kvp.value.SetActive(active);
// And e.g. position it only if active
if (active)
{
kvp.value.transform.position = positionFromFile;
}
}
// Wait for updateInterval and repeat
yield return new WaitForSeconds (updateInterval);
}
}
If you have multiple instances of the same prefab you also should have a look at Object Pooling
I'd recommend adding each of the game objects to a registry and the switching them on or off (dis/enable SetActive) via the registry class's Update() cycle.
One Update() process to retrieve and handle the server file, another Update() process to dis/enable objects. Might sound oversimplified however it's the fastest way I think of getting the result.
Good Luck!

Unity3d: Adding gameobject to List from an array

Thanks for help in advance. Here is a short snippet of the code that I am having an issue with.
GameObject[] allMotor_array;
public List<GameObject> BrokenMotor_list = new List<GameObject>();
void Start()
{
allMotor_array = GameObject.FindGameObjectsWithTag ("Motors");
}
void Update()
{
foreach (GameObject motor in allMotor_array)
{
if(motor.GetComponent<Pump_event>().damaged)
{
BrokenMotor_list.Add(motor);
}
}
}
I have an array of Gameobjects that is created on Start, each of the gameobjects in the array have a script called Pump_event. What I want to do is add the gameobject with a true boolean (damaged) to the list so that I can create a GUI list of all the motors that are damaged (and then take further action on those motors).
With the current code it instantiates the array fine, but when One of the motors boolean changes to true the list tends to continuously add the motor gameobject to the list on each update cycle. So what I want is to figure out a way of adding the gameobject to the list ONCE.
Having it in the update() is probably not the best method but I really am stuck on how to approach this.
G
The Solution to my problem
Thanks for your answers, you all had well thought out responses. I appreciate it. I didn't go with 1 persons method but instead adapted logical approaches found here to work with my script/s.
Here is what I did.
In my pump_event script the events are sorted in a Case and switch as damage increased on the pump the event would escalate. So I added in a section to that script to include "reporting" the damage.
public class Pump_event : MonoBehaviour
//The damage has taken place and event_category=0\\
switch (event_category)
{
case 0:
Master_script.GetComponent<Control_room>().AddtoList (gameObject);
event_category = 1;
break;
I took advice not to insert these types of programing and placed it into its separate class which works out well.
public class Master_script: MonoBehaviour
public void AddtoList(GameObject motor_tobadded)
{
BrokenMotor_list.Add(motor_tobadded);
}
This also eliminated the need on having an array holding all of the pump event controllers as well.
Now the script all works fine. It may not be most efficient but it is doing its job.
Thank you again to all that helped.
In your Pump_event Script you can have a event Action which you register in this snippet and whenever damaged is set true you need to fire the event.
Example:
// in Pump_event Class
public static event Action<GameObject> OnDamagedValueChanged;
private bool _damaged;
public bool Damaged
{
get { return _damaged;}
set
{
_damaged = value;
if(_damaged)
{
if(OnDamagedValueChanged != null)
OnDamagedValueChanged(gameObject);
}
}
}
In your Current Class where you have array of GameObjects:
void OnEnable()
{
Pump_event.OnDamagedValueChanged += HandleOnDamagedValueChanged;
}
void OnDisable()
{
Pump_event.OnDamagedValueChanged -= HandleOnDamagedValueChanged;
}
void HandleOnDamagedValueChanged(GameObject obj)
{
if (!BrokenMotor_list.Contains (obj))
{
BrokenMotor_list.Add (obj);
}
}
Using Actions is a better approach than doing it in Update Method. It is not good for performance to keep checking for a bool in iteration in update method. and try to avoid GetComponent and Find/FindObjectWithTag Methods in Update. It is not good practice. I hope this is helpful.
According to the code you have posted, the problem lies within the fact that the damaged property is never reset. One solution would be to reset this property once you add it to the list, like so:
if(motor.GetComponent<Pump_event>().damaged)
{
motor.GetComponent<Pump_event>().damaged = false;
BrokenMotor_list.Add(motor);
}
However, multiple copies of the same object could still be added to your list if the motor is damaged again.
To go around this, you could use a HashSet. The hash set will allow only one copy of an object to exist within it, thus, if an object is already present is will not be added again.
The catch is that you will need to override the GetHashCode and Equals methods for your GameObject class since these will be used internally by the hash set to place items within itself and identify duplicates.
check if list already contains motor.
if(motor.GetComponent<Pump_event>().damaged)
{
if(BrokenMotor_list.Contains(motor))
{
BrokenMotor_list.Add(motor);
}
}
although on msdn describes how to implement IEquatable in case if you want compare different objects(with different references) https://msdn.microsoft.com/ru-ru/library/vstudio/bhkz42b3%28v=vs.100%29.aspx
if (!BrokenMotor_list.Contains (motor)) {
BrokenMotor_list.Add (motor);
}
You'd better do this after damage event occur by add a delegate.

Saving PlayerPrefs for multiple instances

I have setup a simple shop where when the player clicks to 'BUY' a character, the item gets unlocked and stays saved as unlocked. This is in one scene (Shop scene).
I have a second scene where the character gets unlocked based on this purchase for the player to be able to select (character scene).
I am placing the scripts on empty gameObjects on each scene. It works fine when it is just buying one character. But how do I replicate this for multiple characters.
I could place the scripts on individual buttons and place corresponding gameobjects under the inspector but this would not be practical if I have like a 100 characters.
Please advice how I could make this work across multiple instances. Thought of tagging and that too doesn't seem feasible. I am open for suggestions if there is a better way of doing this. Thanks.
//Class controlling Shop Scene via an empty Gameobject
public class ShopManager : MonoBehaviour
{
private bool unlocked;
public GameObject greyImg;
void Start()
{
unlocked = PlayerPrefs.GetInt("unlocked") == 1;
greyImg.SetActive(unlocked);
}
public void Buy()
{
unlocked = true;
PlayerPrefs.SetInt("unlocked", 1);
PlayerPrefs.Save();
greyImg.SetActive(true);
}
}
This is how the unity setup looks for shop scene. If the item is already bought, the grey image is set to active thus not allowing the user to click the green buy button any more.
When character is unlocked/bought
//Class controlling Character select scene via an empty Gameobject
public class CharacterManager : MonoBehaviour
{
private bool unlocked;
public GameObject greySelect;
void Start()
{
unlocked = PlayerPrefs.GetInt("unlocked") == 1;
}
void Update()
{
if (unlocked)
{
greySelect.SetActive(false);
}
}
}
This is how Unity setup looks for Character select scene. If the character is already unlocked, the grey select image is set to inactive and the orange select button will be visible thus allowing the character to be selected.
when character unlocked
There are probably many ways in which to tackle this problem. Here's one;
You're going to need a separate player prefs entry for each character. So, you'll need a nice way to keep track of the characters you have and their unlock state. Instead of saving 'unlocked' in player prefs, why not create a class that contains unlocked information?
class UnlockedCharacters
{
bool characterAUnlocked = false;
bool characterBUnlocked = false;
bool characterCUnlocked = true;
}
You can then serialize this whole class and save the whole class inside player prefs. Then, when you load your game you can load this class from player prefs to populate your character information. This way, data is managed and is consistent across saved states.
You could go one step further and keep everything relating to your characters inside of a Dictionary whereby your int is an enum referring to a character and the bool is its unlock state. You can then save/load this dictionary again using player prefs.
Inside the class you could have helper methods with your generic gameobject scripts call to keep things nice and encapsulated.
This way, your individual GameObjects which handle specific characters can hold a reference to this enum and you can use your general script to set/modify your data contents based on your enum field that you can then set via your inspector, or in initialisation code for your object.
EDIT FOR COMMENT BELOW - AN EXAMPLE:
Your generic character controller would go on the individual objects, and by changing your CHAR_TYPE the same script will work to unlock multiple characters.
class CharacterManager
{
public enum CHAR_TYPE = { characterA, characterB, characterC }
private Dictionary<CHAR_TYPE, bool> characterUnlockState;
void Start()
{
// Seeding with some data for example purposes
characterUnlockState = new Dictionary<CHAR_TYPE, bool>();
characterUnlockState.Add(CHAR_TYPE.characterA, false);
characterUnlockState.Add(CHAR_TYPE.characterB, false);
characterUnlockState.Add(CHAR_TYPE.characterC, true);
}
public bool IsCharacterUnlocked(CHAR_TYPE character)
{
if (characterUnlockState.Contains(character)) return characterUnlockState[character];
return false;
}
public void UnlockCharacter(CHAR_TYPE character)
{
if (characterUnlockState.Contains(character)) characterUnlockState[character] = true;
}
}
class GenericCharacterController
{
public CHAR_TYPE character;
public CharacterManager manager;
public void UnlockButtonPressed()
{
manager.UnlockCharacter(character);
}
}
There are a number of ways to approach this. You are going to need an ID of some kind for each item in your store. So I would make a StoreItem script that you place on each thing for sale. The StoreItem script would need an ItemID property at the minimum. Then your StoreManager could check if it's unlocked like this:
PlayerPrefs.GetInt(selectedStoreItem.ItemID + "_unlocked");
Also, while this approach would work, it's not recommended. It's possible for playerprefs to be manipulated by the user outside of your game. So they could potentially give themselves free items. I don't know how important that is to you. The better approach would be store this info on a server somewhere and have the game sync up with that to determine what items the player owns.

How to find inactive objects using GameObject.Find(" ") in Unity3D?

I needed to find inactive objects in Unity3D using C#.
I have 64 objects, and whenever I click a button then it activates / inactivates objects for the corresponding button at runtime. How can I find inactive objects at this time?
Since Unity 2020
In the years since this question was asked, Unity put in the exact thing you need. At least, the exact thing I needed. Posting here for future peoples.
To find an object of a certain type whether it's on an active or inactive GameObject, you can use FindObjectsOfType<T>(true)
Objects attached to inactive GameObjects are only included if inactiveObjects is set to true.
Therefore, just use it like you regularly would, but also pass in true.
The following code requires System.Linq:
SpriteRenderer[] onlyActive = GameObject.FindObjectsOfType<SpriteRenderer>();
SpriteRenderer[] activeAndInactive = GameObject.FindObjectsOfType<SpriteRenderer>(true);
// requires "using System.Linq;"
SpriteRenderer[] onlyInactive = GameObject.FindObjectsOfType<SpriteRenderer>(true).Where(sr => !sr.gameObject.activeInHierarchy).ToArray();
The first array includes only SpriteRenderers on active GameObjects, the second includes both those on active and inactive GameObjects, and the third uses System.Linq to only include those on inactive GameObjects.
See this answers for Unity 2020 and higher.
Before Unity 2020
Well, using GameObject.Find(...) will never return any inactive objects. As the documentation states:
This function only returns active gameobjects.
Even if you could, you'd want to keep these costly calls to a minimum.
There are "tricks" to finding inactive GameObjects, such as using a Resources.FindObjectsOfTypeAll(Type type) call (though that should be used with extreme caution).
But your best bet is writing your own management code. This can be a simple class holding a list of objects that you might want to find and use at some point. You can put your object into it on first load. Or perhaps add/remove them on becoming active or inactive. Whatever your particular scenario needs.
If you have parent object (just empty object that plays role of a folder) you can find active and inactive objects like this:
this.playButton = MainMenuItems.transform.Find("PlayButton").gameObject;
MainMenuItems - is your parent object.
Please note that Find() is slow method, so consider using references to objects or organize Dictionary collections with gameobjects you need access very often
Good luck!
For newer Unity versions this answer provides probably a better solution!
First of all
In general any usage of Find or it's variants should be avoided.
Actually they are never really required but only a "hot-fix" used to cover an implementation "laziness".
Usually from the beginning storing and passing on required references is always the better approach.
Especially in your case you seem to have a fix amount of objects so you could probably already reference them all in a certain "manager" component and store them in a list or array (them you can get a reference by index) or even a Dictionary<string, GameObject> (then you can also get the according reference by name - you can find an example below).
Workarounds
There are alternative solutions (FindObjectsWithTag, FindObjectsOfType) but it will always be quite expensive (though most of the Find variants are expensive anyway).
You could e.g. also "manually" iterate through all objects in the scene using Scene.GetRootGameObjects
Returns all the root game objects in the Scene.
And then search through them until you find your object. This way you get also inactive GameObject.
public static GameObject Find(string search)
{
var scene = SceneManager.GetActiveScene();
var sceneRoots = scene.GetRootGameObjects();
GameObject result = null;
foreach(var root in sceneRoots)
{
if(root.name.Equals(search)) return root;
result = FindRecursive(root, search);
if(result) break;
}
return result;
}
private static GameObject FindRecursive(GameObject obj, string search)
{
GameObject result = null;
foreach(Transform child in obj.transform)
{
if(child.name.Equals(search)) return child.gameObject;
result = FindRecursive (child.gameObject, search);
if(result) break;
}
return result;
}
But ofcourse this should be strongly avoided and the usage of such deep searches reduced to a minimum!
What I would do
Another way - in my eyes the best approach here - could be to have a certain component attached to all your objects and actually store all the references once as said before in a dictionary like e.g.
public class FindAble : MonoBehaviour
{
private static readonly Dictionary<string, GameObject> _findAbles = new Dictionary<string, GameObject>();
public static GameObject Find(string search)
{
if(!_findAbles.ContainsKey(search)) return null;
return _findAbles[search];
}
private IEnumerator Start()
{
// Wait one frame
// This makes it possible to spawn this object and
// assign it a different name before it registers
// itself in the dictionary
yield return null;
if(_findAbles.ContainsKey(name))
{
Debug.LogError($"Another object with name /"{name}/" is already registered!", this);
yield break;
}
_findAbles.Add(name, gameObject);
}
private void OnDestroy ()
{
if(_findAbles.ContainsKey(name))
{
_findAbles.Remove(name);
}
// Optionally clean up and remove entries that are invalid
_findAbles = _findAbles.Where(kvp => kvp.Value).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
}
and then use it like
var obj = FindAble.Find("SomeName");
if(obj)
{
// ...
}
Also for this the component would need to be enabled at least once so Start is called.
Again an alternative would be to have instead a
public void Initialize(string newName)
{
if(_findAbles.ContainsKey(name))
{
Debug.LogError($"Another object with name /"{name}/" is already registered!", this);
return;
}
name = newName;
_findAbles.Add(name, gameObject);
}
which you could call also after e.g. spawning an inactive object.
You can use Predicates.
Just get the gameObjects and check them whith a Predicate as below:
public List<GameObject> FindInactiveGameObjects()
{
GameObject[] all = GameObject.FindObjectsOfType<GameObject> ();//Get all of them in the scene
List<GameObject> objs = new List<GameObject> ();
foreach(GameObject obj in all) //Create a list
{
objs.Add(obj);
}
Predicate inactiveFinder = new Predicate((GameObject go) => {return !go.activeInHierarchy;});//Create the Finder
List<GameObject> results = objs.FindAll (inactiveFinder);//And find inactive ones
return results;
}
and don't forget using System; using System.Collections.Generic;
You can do this at runtime by having your inactive gameobject under an active parent object as previously mentioned; slightly different from what was mentioned, this is an approach I've used for activating/deactivating menus that should be inactive by default:
canvas = GameObject.FindGameObjectWithTag("GameMenu").GetComponentInChildren<Canvas>().gameObject;
Now you can change its activeSelf to toggle it in a method/event listener of your choice:
canvas.SetActive(!canvas.activeSelf);
Even while it is inactive, you can still use the tag property of it and use it for a filter, if getting multiple components of the same type. I haven't tested this using GetComponentsInChildren, but you could probably use a 'Single' linq query, and get the object by tag name which would require creating a tag for every gameobject you want to do this to.
Although its not the correct answer, but this is what I did in my case.
1) Attach a script to (inactive) game objects and instead of setting then inactive keep it active.
2) Position them out of the scene somewhere.
3) Set a flag in the script which says inactive.
4) In Update() check for this inactive flag and skip function calls if false.
5) When needed the object, position it at the proper place and set the flag active.
It will be a bit of a performance issue but that's the only workaround I could think of so far.

Categories