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));
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).
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.