Is there no clean way to provide data to a GameObject’s Script directly when Instantiating ? I am currently looking for an option to pass data to my script. I spawn enemies in my game, but the script is empty at first. I found some article how to pass data, but they are always just workarounds, I feel like atleast. Some kind of “Setup” Method that is called after the GameObject is created. Is there no direct way to pass data to the script when created?
For example
You would create a reference to your script.
GameObject InstantiatedObject = Instantiate(YourGameObject)!
var MyScript = InstantiatedObject.GetComponent<MyScript>();
MyScript.SomeVariable = SomeValue;
First of All, thanks for the answer, but that is the way I try to avoid, cause after the Instantiate, the Object is already running and Update/etc will already process. I am looking for a way to set the scipt values before instantiate.
Oh I see, well then prefabs are the method.
Start won’t occur until next frame. So you shouldn’t really be too worried about doing it that way. I have not encountered an issue with that before. You may want to check if assigning variables following an instantiate is actually problematic or whether it’s a superstition you have picked up from a mistake in a previous project or something.
Prefabs will otherwise work for you.
But if you didn’t want to make prefabs you could create a bunch of objects in the hierarchy on start and reference those objects as if they are prefabs.
You should also check if the instantiated scripts start had set any variables that you wanted to modify on instantiate. Because in that case it could seem to undo any variables you set. But you know that is something I couldn’t possibly know that is happening. But it’s definitely a possibility.
Okay, good take. Already using Prefabs, but I have the problem that i tyred to have the Variables like Movementspeed/Basedamage etc out of the editor in a seperate xml and ready them at the startt of the program. Dunno if that works then tho.
This isn’t true. Update is called for all scripts during the update cycle of the player-loop, not immediately after you instantiate.
You are also free to ensure that the root GameObject prefab you’re cloning is disabled so you can clone it, set whatever you like then finally enable it so you can react in the Awake callback etc.
Via XML. Very interesting I know what you mean. I am not knowledgeable on how unity specifically is performing that during GO creation. But yes in a VS game. I see what you’re going for. I can’t be of any more help on that. So il drop here hopefully somebody can answer that. That’s an interesting approach.
It’s literally the one, only, and best way you pass values to objects that you’re instantiating. Doing it before you instantiate it doesn’t make sense, as the copy doesn’t even exist at that point.
If you want them to have values before you instantiate them, then those values should already be in the prefab in the first place.
No idea why you’d keep all your values out of the editor in XML. That just seems like ignoring the primary purpose of the editor… to edit values inside of it.
I wanted the parameter of the prefabs combined in an XML. I want to make them editable in the game and saveable but I maybe have to rethink that. I use the Prefabs to give them logic, but want the Variables be loaded of a XML, so I can load the xml on the gamestart.
Good take, have to think about that one.
Factory Pattern in lieu of AddComponent (for timing and dependency correctness):
Friends don’t let friends use XML. It’s 2023. Seriously. We have evolved. Use JSON if you must, otherwise keep your data all inside of Unity with something like ScriptableObjects.
Unity supports extremely robust custom data authoring and custom editor extending to support it. You could make any editor you want within Unity and capture all the data using Unity’s in-built classes.
What does this mean precisely? Are you referring to players modding them? Or are you just referring to saving the state of the object?
Did not implement the XML yet, will just do JSON then, thanks man
already found a way. Directly loading the Data in The Contructor instead of passing it in by parameters
MonoBehaviour (and ScriptableObject) constructors shouldn’t be used. Unity uses these under the hood with the expectation that you don’t try to set them up yourself. Trying to use them will lead to problems that are difficult to track down. The code that @StarBornMoonBeam gave earlier is the correct approach.
Parameterless constructors can be defined in components, and they will get executed automatically when Unity creates the instance. There are however a couple of caveats:
- The constructor is executed before deserialization takes place, so anything you assign to serialized fields will get overridden during deserialization. This is mentioned in Unity’s documentation for Awake.
- Constructors are not executed on the main thread (just like ISerializationCallbackReceiver methods).
- When instantiating a prefab, the constructor can get executed more than once (on different instances) as part of the deserialization process.
In this case, since the data will be read from a file, a parameterless constructor could indeed be used.
Also, I believe File.ReadAllText, for example, can be used to read text from the same file on multiple threads simultaneously.
If however you need to have support for assigning data to serialized fields, or want to avoid doing unnecessary work during instantiation, you could do the reading in OnAfterDeserialize or Awake instead.
As an alternative solution, I also do have an asset which makes it possible to pass any arguments to objects during instantiation.
In general, you can follow this process to instantiate without allowing the new thing to run any Unity callback code (Awake, OnEnable, Start, Update, etc.):
- create an Empty
- deactivate the Empty
- Instantiate whatever prefab you like, as a child of the inactive Empty
- do whatever initialization you want before any of the prefab code can run
- unparent the prefab (set parent to null), or activate the Empty to allow the prefab code to run
Avoid constructors on MonoBehaviours. As mentioned above, code in constructors and field initializers will run even with this approach.
Also the constructor and OnAfterDeserialize get executed even in edit mode (e.g. when you select a prefab), while Awake won’t.