- Home /
Assign exposed vars before instantianting prefab?
I have a prefab (a few GameObjects with my scripts). Some of these scripts have exposed variables. In their Start()
method I'm initialising some other variables based on the exposed ones. The problem is - when I try to instantiate such a prefab the Start()
method gets called before I get a chance to assign the exposed variables.
What should I do?
Answer by whydoidoit · Feb 10, 2014 at 01:00 PM
You can set variables in the script on the prefab before you instantiate it. Then the variables will be set correctly in Awake and Start.
For some reason I can assign some variables but can't assign others. (For instance my prefab has $$anonymous$$egaShapeFollow.cs from $$anonymous$$egaShapes plugin and $$anonymous$$yScript.cs. Both scripts have a variable of the same type ($$anonymous$$egaShape) but I can assign only the variable in $$anonymous$$egaShapeFollow.cs and not in $$anonymous$$yScript.cs. :/ )
I guess that one of those $$anonymous$$egaShapes things might doing its stuff in Awake or Start itself. But you could post some code, perhaps it's something else not ready yet?
I do assign paths for $$anonymous$$egaShapes pathfollowing in my code, but I'm sure the use case is different.
By "can't" I meant Unity Editor doesn't allow me to "drop" an object on the variable field (like when the types don't match and the option is disabled). $$anonymous$$yScript has just a public $$anonymous$$egaShape variable so I'm not sure what code I could post.
Oh hang on - you mean you are looking at the project view of your script and wanting to assign default parameters to exposed variables. Right it's making a bit more sense now. Ugh - I just wish that functionality wasn't there, it's very flaky. If you AddComponent that script it just ignores all those values for instance.
$$anonymous$$ost likely you are trying to allocate an item from the scene to the script - that is never possible as the script doesn't know which scene it will be instantiated in.
Answer by yatagarasu · Feb 10, 2014 at 03:03 PM
You can call SetActive(false) on prefab before instantiating it, then instantiate an object and set your vars, and then class SetActive(true) on instantiated object and prefab. Start and Awake are called only on active objects.
I wish I could mark 2 answers as correct as this one also solves my problem. +1 though. ;)
I like this answer in combination with @wibble82 's. Essentially what you're looking for here is a Unity-compatible version of a class constructor function where you'd just pass your initialization values into the constructor as parameters, e.g.:
//Note: these won't work
$$anonymous$$yGameObject newObject = new $$anonymous$$yGameObject(initValue1, initValue2);
//or
newObject.AddComponent(new $$anonymous$$yComponent(initValue1, initValue2));
Unfortunately, as I understand it, $$anonymous$$onobehavior-derived classes prohibit this approach in favor of initialization through the Awake(), Start(), and OnEnable() functions. This works well in most cases, but doesn't do so well when you're trying to instantiate a new GameObject with components that need initial values set from an external source at that moment, and need those values right away to start working properly. So making sure that GameObject is set Inactive -- or that component is un-enabled! -- in your prefab, until you can call an init function to pass in starting values, seems like a good solution.
//Set GameObject or Component to inactive / disabled in prefab first
$$anonymous$$yGameObject newObject = Instantiate<GameObject>($$anonymous$$yGameObject);
newObject.GetComponent<$$anonymous$$yComponent>().Init(initValue1,initValue2);
newObject.SetActive(true);
//or
newObject.GetComponent<$$anonymous$$yComponent>().enabled = true;
There is also an interesting discussion here about how you can get something like constructors in $$anonymous$$onobehavior components:
https://answers.unity.com/questions/445444/add-component-in-one-line-with-parameters.html
Answer by wibble82 · Feb 10, 2014 at 11:37 AM
So my understanding (just to clarify) is that you have a prefab, which contains some scripts. Those scripts have a load of members that control how the script operates, so you want effectively want to be able to go:
create object
set the members (lets call them initialisation members)
have it 'start' and let the script do its thing!
In the simplest case, if you know what the initialisation values are at edit time you would just set these properties in the editor, however you've probably hit the scenario where the initialisation members are dependent on run time data? In this case what you'll need to do is remove the functionality from the start function (so it does very little), then create a new function (lets call it Init) that you call manually which does the bulk of the work. So the order would be:
create the object
(its start function is automatically called, but does very little)
set the members on the script
call 'Init' on the script
That sound ok?
You can make it a little more robust by having the script raise an error when updating if it hasn't been initialised, adding the custom parameters as arguments to the init function and even creating your own special static helper functions that internally do the above code. So you might have:
public static GameObject CreatePlayer(float player_fatness)
{
GameObject obj = Instantiate(player_prefab); //the player is created and start is called
PlayerScript player = obj.GetComponent<PlayerScript>();
player.fatness = player_fatness;
player.Init();
return obj;
}
or if you passed the parameters into the init function:
public static GameObject CreatePlayer(float player_fatness)
{
GameObject obj = Instantiate(player_prefab); //the player is created and start is called
obj.GetComponent<PlayerScript>().Init(player_fatness);
return obj;
}
Thx for answering! I know I can move the init stuff from Start()
to $$anonymous$$yInitFunction()
and call it manually. But my question was - is it possible to assign the exposed variables before the Start()
is called. I guess it isn't? Also - if I "know what the initialisation values are at edit time" how do I set them in prefab? I mean - how do I assign exposed variables of a prefab?
If you make a member of a mono behaviour public, it should appear as an editable property in the editor. I often have 1 script that represents say 'enemy behaviour', with a load of properties that control it. Then I create a prefab for each type of enemy.
Your answer
Follow this Question
Related Questions
Monobehaviour resets variables after the initialization cycle 0 Answers
bool field initialization ignored 0 Answers
Initialising List array for use in a custom Editor 1 Answer
When do components of loaded prefabs get initialized? 1 Answer
Order of GameObject.FindGameObjectsWithTag(string tag) 3 Answers