- Home /
Creating a single-line function for GameObject.Find and GetComponent (for multiple components)
Hi, all, this is my first time asking a question on UnityAnswers. I've been here plenty of times and it's been a very useful resource so far, and now that I've got an account, hopefully I can start giving back to the community.
On with my question: up until recently I've been getting by with a single function, activated in the Awake function, which finds each and every object needed by the script and its' GameObject:
public GameObject cwGO;
public GUIText cwTx;
void FindObjects()
{
cwGO = GameObject.Find("CurWep");
cwTx = cwGO.GetComponent<GUIText>();
}
void Awake()
{
FindObjects();
setVars();
}
and as you can see, another function to set the variables.
What I'm trying to figure out is a way of condensing GameObject.Find and GetComponent to a single line and activating one function for each object I'm attempting to find. This is what I have so far:
void objF(GameObject gO, string gOs, Component cmp, Component typ)
{
gO = GameObject.Find(gOs);
cmp = gO.GetComponent<typ>();
}
My end goal would be something like this:
objF(cwGO, "CurWep", cwTx, GUIText);
However, what I have isn't working: the second instance of 'typ' (GetComponent())
is throwing up an error. What should the datatype(s) be so that this function will work, if it could work?
Help would be appreciated, thanks.
EDIT:
void objF(GameObject gO, string gOs, Component cmp, *datatype* *variable*)
{
gO = GameObject.Find(gOs);
cmp = gO.GetComponent<*variable*>();
}
In order to be able to include any datatype that can be found using 'GetComponent' (box colliders, sphere colliders, GUIText and even C# scripts), what should be entered in the spaces marked variable and datatype? As of now I'm limited to only ever being able to find a single type of component, be it GUIText, colliders or the like: I'd like to make this function universal so that I can find any type of component by entering it in the brackets when calling the function:
objF(cwGO, "CurWep",cwTx, *any component*);
Answer by Gizmoi · Jan 20, 2015 at 03:27 PM
You probably want to be using generics:
public static void FindObject<T>(string name, ref GameObject go, ref T component) where T : Component
{
go = GameObject.Find(name);
component = go.GetComponent<T>();
}
Called like this:
FindObject("CurWep", ref cwGO, ref cwTx);
But like DFortun81 said, GameObject.Find() calls are costly, so be careful, especially if calling every frame.
$$anonymous$$y implementation of this will be up in a bit (I credited you in the answer). Have a look.
By the way, I had a look at DFortun81's alternative to GameObject.Find calls, which was the use of Singletons. However, according to $$anonymous$$icrosoft's database, Singletons are out of date. I know that I can tag every object that I'd like to find using the function and then use FindGameObjectsWithTag, but are there any alternatives out there? I've scoured the internet for solutions and not had much luck.
I wouldn't say Singletons are out of date, but they're not a solution for everything either.
Generally I make sure everything is parented to a single root object in each scene. And let each $$anonymous$$onoBehaviour attached to an object find its own children.
For example, I have a 'GUI' object in most scenes, with a specific script depending on the type of GUI that it is. This script finds all its children that it needs in Awake and then other scripts further up in the hierarchy can modify them, post-Awake.
Answer by DFortun81 · Jan 13, 2015 at 12:26 AM
The arguments (variables passed to objF) do not retain values that you pass into the function unless you mark the argument with the keyword "ref" in both the definition and wherever you call the function.
void objF(ref GameObject gO, string gOs, ref Component cmp, Component typ)
{
gO = GameObject.Find(gOs);
cmp = gO.GetComponent<typ>();
}
And you would call it like this:
objF(ref cwGO, "CurWep", ref cwTx, GUIText);
Bare in mind that there are much better ways of doing this than using "GameObject.Find" as it can be very expensive at run time depending on the size of your game, it might be better to utilize Singletons. (http://msdn.microsoft.com/en-us/library/ff650316.aspx)
Hi, apologies for the delay in answering and thanks for the input.
I attempted the supplied method and have a similar error this time around. The 'typ' keyword is still throwing up an error, but now, so is the calling of the function in its entirety.
I'm going to rephrase the question a little to generalise it more for any datatype, not just GUIText. The edited question will be above.
I figured that you called the type "typ", but reading through this again points to it ins$$anonymous$$d as a "I want to get a specific type of component from the game object with the name contained in the gOs variable".
To do that, all you have to do is pass the Type ins$$anonymous$$d of the component and then the format of the cmp assignment line. (See this for reference: http://docs.unity3d.com/ScriptReference/GameObject.GetComponent.html)
// Use this to call the function with a System.Type:
// objF(ref cwGO, "CurWep", ref cwTx, typeof(GUIText));
void objF(ref GameObject gO, string gOs, ref Component cmp, Type typ)
{
gO = GameObject.Find(gOs);
cmp = gO.GetComponent(typ);
}
// Use this to call the function with a string:
// objF(ref cwGO, "CurWep", ref cwTx, "GUIText");
void objF(ref GameObject gO, string gOs, ref Component cmp, string typ)
{
gO = GameObject.Find(gOs);
cmp = gO.GetComponent(typ);
}
I've posted examples on how to use it in the comment directly above each function.
I followed both methods, and the first one required me to declare 'typ' as datatype 'Type'. 'Type' isn't a datatype according to C#, so I used the closest option available, 'Types'. This caused an error for the following:
'static types cannot be used as parameters'
gO.GetComponent(typ);
in
void objF(ref GameObject gO, string gOs, ref Component cmp, Types typ)
{
gO = GameObject.Find(gOs);
cmp = gO.GetComponent(typ);
}
I then tried the second method, which worked great when declaring the function (no errors here):
void objF(ref GameObject gO, string gOs, ref Component cmp, string typ)
{
gO = GameObject.Find(gOs);
cmp = gO.GetComponent(typ);
}
but when I attempted to write the code to invoke it:
objF(ref cwGO, "CurWep", ref cwTx, "GUIText";
Error CS1503: Argument 3 cannot convert UnityEngine.GUIText expression to type 'UnityEngine.Component'
The final parameter won't take. If I try and directly solve the cause of the error, I'll only be converting the GUIText string to Component, so what I need to be able to do now is to convert any string that goes into the space for the final parameter, all of which will be component names in String format, to a component. Any ideas?
Answer by DarKAeRiX · Jan 20, 2015 at 04:16 PM
Implementing Gizmoi's solution into my code:
public static void objF<typ>(ref GameObject gO, string gOs, ref typ cmp) where typ : Component
{
gO = GameObject.Find(gOs);
cmp = gO.GetComponent<typ>();
print("object found");
}
It's called like this:
objF<GUIText>(ref cwGO, "CurWep", ref cwTx);
Looks like it's working now. You missed the instance of 'GUIText' between 'FindObject' and the parameters, but I figured it out, added it in and the function is working now.
Thanks for your help, much appreciated.