- Home /
Instantiating a prefab at runtime (without using Monobehaviour or Resources folder)
I would like to instantiate a prefab using a script that does not inherit from Monobehaviour. The way I have been doing it is this:
GameObject unitPrefab = (GameObject)Resources.Load("Unit", typeof(GameObject));
GameObject.Instantiate(unitPrefab);
where "Unit" is a prefab in the Resources folder.
Recently however, I have read that loading resources in this way is bad practice. Is there another way I can instantiate the prefab? Or is it wrongheaded for me to create classes that do not inherit from Monobehaviour? (I want to be able to create objects using "new", pass parameters etc).
Answer by Lysander · Jan 19, 2018 at 06:17 AM
At least 90% of the scripts in Unity projects are NOT MonoBehaviours, or derived from UnityEngine.Object. I also don't see why it would be bad practice to use Resources.
Unity asset types MUST be either referenced by a scene object. stored in Resources, or loaded from an asset bundle in order to be usable in the build (with minor exceptions like PNGs, and barring significant effort). If you don't want to use Resources, then your only easy option is to make a GameObject in a scene, have a public GameObject variable on a MonoBehaviour attached to that GameObject, and drag-and-drop the prefab into that reference.
Some people choose to do this by creating a kind of "initialization scene" where they handle loading assets and making them available to the rest of the game's objects. You can manage this with a singleton GameObject (use DontDestroyOnLoad on it so it persists through scene changes), or by simply passing along the references to a static handler. You'll still have to make GameObjects and attach those prefab references to MonoBehaviours attached to them, but it gets it all done in one place so that you don't need to worry about doing it for individual scenes.
There's nothing at all wrong with Resources as long as you don't get lazy though- load everything you need at the beginning of the scene, try to avoid instantiating or destroying objects (use object pools- use the HELL out of object pools), and always start off big dynamic events by pre-loading temporary stuff and then dump it all immediately after the event is over- this is the reason for those brief pauses before cutscenes in most console games. Don't think that just because a file is in Resources that you can load it whenever you like, and don't put anything in Resources that you may not want included in the build (all assets there are included, whether they're used or not) and there's zero reason not to use it.
As a final note, I would like to make you aware of the RuntimeInitializeOnLoad attribute. Toss that onto a static method, and that method will run when the game starts (either before anything in the scene is created, or after Awake has been called on everything in the starting scene). This allows you to cut out the need for "initialization scene" MonoBehaviours, since you can just immediately load whatever you like from Resources into a static handler, without any middle-men in the scene to hand them over. It also means that, if you have a singleton MonoBehaviour set up for it, you can actually hook into Unity's Update/LateUpdate loops without being a scene object or deriving from MonoBehaviour. Just create events on your "UpdateHook" singleton, allowing anything to sign up to them, and invoke them in Update so everything that's listening gets updated as well. This can be tremendously useful.
Thanks for the answer. A follow-up question: I'm trying to work out how to structure my code in a good way. I have a Squad class that contains an array of unit objects. These units need to be represented in the scene however, so I have them create a unit prefab at initialisation saved as a variable in the unit class, which is moved when the unit is moved. Is this a typical thing to do?
Then I would like to be able to select units. So I will need a new script that uses $$anonymous$$onobehaviour (for On$$anonymous$$ouseEnter()) attached to the unit prefab. But where should the logic for selecting and moving units go? In the squad class? Unit class? A new script on the Unit prefab?
Additionally, do you have any tips/resources on how I can learn to structure my code well in Unity generally?
Disclaimer: this is all my own personal beliefs and style, and should not be taken as gospel.
I like the idea of separating the data from the visual representation of that data, but I prefer it when there's a well-defined dependency chain. The avatars as they exist in the scenes (GameObject entities) should know about the data objects they represent, but the data objects shouldn't know about the avatars. UI is the same way- nothing should have direct knowledge of any UI elements that isn't itself a part of the UI system, but the UI needs to know what data it's representing so it knows how to display it properly.
With that in $$anonymous$$d, I wouldn't have the characters' data objects instantiate their own avatars into the scene. I wouldn't even have them hold their own prefabs- I would use a static handler that's in charge specifically of all of the in-game avatars for the project, and whatever manager in the scene decides "I need CharacterX here" should ask that handler "Give me the avatar for CharacterX", and it should comply. This is especially important later on when you're working with AssetBundles.
I'm having a bit of trouble visualizing your situation (it's extremely late at the moment), so I'll just give some general advice. $$anonymous$$ost important I$$anonymous$$O: objects should handle themselves. The big point that you'll often see made in program$$anonymous$$g about "never make fields publicly accessible, only properties and methods" really boils down to "never change another object's fields". When ObjectA changes a field for ObjectB, ObjectB has no possible way to know that that change has occurred and react to it, unless it's (ridiculously) constantly monitoring the value. By using properties, you allow for the possibility that ObjectB will be able to tell the value is being retrieved, or set, and react appropriately.
This mentality should, I$$anonymous$$O, be extended to every aspect of your development. An object should be in charge of its own data- if the data needs to be changed, it should be the one to do it. Responsibility for any action should be given to the object most intimately associated with it (least common deno$$anonymous$$ator kind of thing). If you want to perform an action on the squad as a whole, the squad object should process that action, but then relay commands down to its members- the members should then respond appropriately to that command.
If you're worried about where to put the controls for the squad, you need to ask yourself "is the squad controlling itself?". No, it's not, you're controlling it (think of yourself like the Game $$anonymous$$aster). You should probably handle that from a Game$$anonymous$$anager style object ins$$anonymous$$d- if an input command relates to the squad, then pass it to the squad, but if it relates to UI or something else, then pass it there ins$$anonymous$$d.
Out of space for the comment, and exhausted, so I'll stop here for now. Let me know if you need any additional assistance.
Thanks this is super helpful.
If I have a static handler for getting prefabs, are they are stored in that class?
Also, if I create a new Unit data object I will want a prefab created at the same time. $$anonymous$$y first instinct would be to make a call in the constructor to a method in the static handler like "CreateUnitPrefab". But should the models know about the handler?
Your answer
Follow this Question
Related Questions
Instantiate Reference Problem 1 Answer
Fireball instantiate - lags 1 Answer
Instantiating Prefabs Lags in Android 0 Answers
Prefabs wont instantiate using a for loop? 1 Answer
Threads for Instantiate 1 Answer