It is fairly easy to add any component to a game object on instantiation, including classes, using GameObject.AddComponent<T>()
. If your script is good to go from the start, you can do this inline. If you need to do anything with your script after adding it, you can create references as you instantiate.
For further clarity, note that I say classes instead of scripts. When you create a script, a class is created inside that script with the same name. When you drag the script on to an object in the inspector, this is the class that is added. This is not a coincidence. While a compiler will not complain if you proceed to change the name of that class, Unity will complain that it can no longer find the original class, and start throwing errors. What you may not realise is that you are free to create additional classes after the first, within the same script file. While you can not simply "drag and drop" these additional classes on to an object via the Unity inspector, you can still add them to a game object using AddComponent<>
.
Adding a class inline
Setting it up inline is quicker, but it leaves us with no reference to the game object nor the object destroyer we have created. If they are designed to run by themselves, without need of setup once they have been instantiated, we are fine. If you should need to reference either, later, read below for creating references.
using UnityEngine;
public Class ObjectCreator : MonoBehaviour
{
public GameObject blueprint;
public void CreateNewGameObject()
{
Instantiate<GameObject>(blueprint).AddComponent<ObjectDestroyer>();
}
}
public Class ObjectDestroyer : MonoBehaviour
{
public void Destroy(){...}
}
Adding and referencing the class
Sometimes just creating the class won't cut it. The same may go for your instantiated game object. If we create them inline, as the example above shows, we do not create any reference for further manipulation. We might want to create a reference to the game object we make for later use, or even add it to a list of all game objects we have created from the same class. Likewise, we may want to grab a local reference to the added ObjectDestroyer
class, to perform additional setup.
You are free to only create a reference to the game object, or only create a reference to the class you are adding to the game object. With only referencing the game object, you can still create it inline, like the above example.
using System.Collections.Generic;
using UnityEngine;
public Class ObjectCreator : MonoBehaviour
{
public GameObject blueprint;
public GameObject lastCreatedObject;
public List<GameObject> allCreatedObjects;
public Start()
{
/* Lists are like arrays, but more complex. They allow *
* you to store a list of data like an array, but *
* provide additional features, such as the ability to *
* add more data on the fly without potential issues that *
* arrays may cause. Just make sure that you have *
* using System.Collections.Generic; at the top, and *
* initialise it in your Start() function. */
allCreatedObjects = new List<GameObject>();
}
public void CreateNewGameObject()
{
// Single reference
lastCreatedObject = Instantiate<GameObject>(blueprint);
// Adding to a list
allCreatedObjects.Add(lastCreatedObject);
// Adding the ObjectDestroyer class w/ reference
ObjectDestroyer script = lastCreatedObject.AddComponent<ObjectDestroyer>();
// Adjusting the ObjectDestroyer on our GameObject
script.countdownTimer = 5f;
}
}
public Class ObjectDestroyer : MonoBehaviour
{
public float countdownTimer;
public void Destroy(){...}
}
I referenced my GameObject, but not my class! Oh Noeeeeeee!
Of course, you may find that you need to access your ObjectDestroyer
attached to the game object, but did not create (or otherwise lost) a reference to it. In similar fashion to the above examples, we can use GetComponent<>()
to grab a reference after the initial creation.
using UnityEngine;
public Class ObjectCreator : MonoBehaviour
{
public GameObject blueprint;
public GameObject gameObject;
public ObjectDestroyer myObjectDestroyer;
public void CreateNewGameObject()
{
gameObject = Instantiate<GameObject>(blueprint).AddComponent<ObjectDestroyer>();
}
public void ReferenceDestroy()
{
// This works if we need to create a reference for later...
myObjectDestroyer = gameObject.GetComponent<ObjectDestroyer>();
}
public void PostponeDestroy()
{
// But this works if we only need the reference for one call.
gameObject.GetComponent<ObjectDestroyer>().Postpone();
// Actually, you could use this for more than one call, but
// anything more and it will be more efficient and easier
// to store an actual reference, locally, first.
}
}
public Class ObjectDestroyer : MonoBehaviour
{
public void Postpone(){...}
public void Destroy(){...}
}
One last thing about Types, since you will run into it
Since you will run into the T type in using the above examples, I felt it would be wise to provide a quick explanation, to avoid potential confusion. When you see a T specified (for example, GetComponent<T>()
or List<T>()
), it simply means that that method or class is generic. That means that you can replace the T with a variety of other types, and it will work.
It is more complicated than that, but for a beginner, all you need to know is that GetComponent<T>()
can be written as GetComponent<Collider>()
if you want to retrieve an attached collider, or as GetComponent<Rigidbody>()
if you want to retrieve an attached Rigidbody, or even as GetComponent<DooHickey>()
if you want to retrieve an attached class called DooHickey
.
There are limitations to how you can use generics, but in the general sense the above examples should not lead you astray. Just know that if you try GetComponent<T>()
and the game object does not contain such a component, it will return null
.
Instantiate
an object then manually add the script throughnewObject.AddComponent<DestroyScript>();
. For further details for prefabs, have a look at this link \$\endgroup\$