Create a central-control script to manage your prefabs
If you would prefer the "drag and drop" approach of being able to drag your prefabs in from the inspector, there is an easy work around to working with a script that is not inherited from MonoBehaviour; create a separate MonoBehaviour to work as the go-between. This script can also handle any other management functionality you might need, in regards to prefabs, now or in the future.
The first step is to set up a global controller script. I tend to favor the static self-reference approach, as I work in a very controlled environment.
public class PrefabManager: MonoBehaviour
public static PrefabManager control; // cheeky self-reference
void Start ()
control = this; // linking the self-reference
In this example, I can access my
PrefabManager script from any other script, using the line
PrefabManager.control. You have to ensure that you only have one instance running, for it to work correctly, but it can be a simple and helpful workaround. There are other, and far better, ways to approach creating a central 'control script'.
Though I am still fairly new to the concept, I am told that Singletons can be helpful in this area. In XNA, I have used services to the same effect, but can not comment on how they relate to or work in Unity. If you are working within a team, discuss other options with them. There will likely be a specific method used to create these static classes, throughout your project, as you will often find need to do so.
From here, all you need to do is create an interface to allow you to store your prefab references through the Unity interface. There are several approaches you can take for this, two of which I will mention:
Arrays or Lists
You can create a simple
GameObject array to store your references. You can do this with a list or array.
public List<GameObject> prefabList;
A list allows greater manipulation functionality, and are more suitable when you intend to add more items to the list past the initial instantiation. It sounds like all objects would be referenced before the game is run, so you will probably be better off with an array.
public GameObject prefabArray;
A more generic array has its limitations. As I have always been taught, C# is particularly troublesome with increasing the maximum size of an array, past the initial instantiation. There are always ways around that, but it sounds like you may not need to, in the first place. Most importantly, arrays store the elements in a more generic format. You can easily reference the elements in the array by their index, using
prefabArray to access the first, second and third prefabs listed in the array.
You might prefer to create your own structure, in order to store extra values with your prefab reference. A text-based tag for easier searching, for example.
public PrefabElement prefabStruct;
[System.Serializable] // Expose the struct inside the Unity Inspector
public struct PrefabElement
public GameObject prefab;
public string tag;
In this example, we have an array of elements that each store a
GameObject reference and a
string. Note the use of
[System.Serializable]. This is important, as it tells Unity to serialise the
struct, allowing it to display the fields in the inspector. Without it, you do not have the ability to drag items in, or edit it from the inspector, at all. This sort of implementation allows you to bind other variables to your prefab reference. If it would be helpful to search for a particular prefab using text-based naming conventions, for example, this would be the better option.
You can access the elements with
prefabStructure[i].tag. In the example implementation, where you only have two variables, it might be more beneficial to use
Dictionary<GameObject, string> prefabDictionary. The
Dictionary type is more suited to handling sets, in this case. I have not been able to determine a way to make it accessible via the inspector, however, and am unable to suggest a good method to implement a
Dictionary for supplying prefabs via the inspector.
What if I can not use public variables?
Of course, in the examples given so far, the variables need to be public in order to allow you to drop values and references in from the inspector. But you can enable variables from the inspector, without making them publicly accessible to everything else. Simply use
public float a; // shown in inspector
private float b; // not shown in inspector
[SerializeField] private float c; // shown in inspector
You would also need to include some sort of
Get() function in your prefab controller, to allow access to the prefab references from outside the controller.
Loading resources with the Resource.Load() function
If you instead prefer to load in the prefabs using script, the
Resource.Load() function will help you with that. I am not as familiar with it, but you can find documentation on it here.
Resource.Load(string) looks in your resources folder for any prefab matching the string. You can look directly for a prefab with
Resource.Load("prefabName"), or look in a specific folder with
Resource.Load("folder/prefabName". Note that we always use forward slashes. This is important, as while you may be use interchanging the forward slash (
/) with a backward slash (
\) for use with alternate operating systems, Unity always accepts the forward slash (
/), regardless of the operating system.
You can overload the function with a type, in order to narrow your selection down.
Resource.Load("prefabName", typeof(GameObject) will only return GameObjects, even if you have a texture that is also named "prefabName".
Note that this does not immediately instantiate the prefab, although you can load the resource inline with an instantiation. You should also consider the possible return structure, as follows:
- If the search returns multiple prefabs, it will return an array of the prefabs. If your code is set up to only interpret a single instance, this can lead to errors. Unless you intend to load an array of like-named prefabs, I would recommend ensuring your prefabs each use different names. Regardless, this is generally a good idea for the purpose of keeping your project tidy. 50 tips for working with Unity (Best Practices) offers some sound advice for naming conventions, as well as a plethora of other useful tips.
- If the search returns no prefab, it will instead return
null. Obviously, this should not happen. It might still be a good idea to double check that your prefab reference
!= null after your
Resource.Load(), to prevent possible issues, later.
You would generally load and/or instantiate a prefab as so:
// Loading in the reference to your prefab
prefab = Resource.Load("prefabName", typeof(GameObject)) as GameObject;
// Loading in and instantiating an instance of your prefab
prefab = Instantiate(Resource.Load("prefabName", typeof(GameObject))) as GameObject;
as GameObject at the end. Documentation infers that you must confirm that you wish to load it as the particular type you are setting it as. This concept is also new to me, but I am sure others can explain why you have to do this, if you are curious.