Everything in Unity is a game object. GameObject is the base class for all entities in a Unity Scene. Therefore, a good deal of our program runtime will revolve around adding and removing new game objects. In the appropriate parlance this means Instantiating (adding) and Destroying (removing) game objects.
What we will be adding (and removing) are what Unity calls prefabs. Think of prefabs as little game object factories or templates. Each time we instantiate a prefab a new copy is created. Each one is created as an exact duplicate of the prefab. What happens after creation to each one is up to the game play. When we are finished with the object, we destroy it.
Our laser prefab will be instantiated by the player game object. Every time the player presses the spacebar, a new laser game object is created. To do this, the player object must know about the prefab. This is done through the simple expedient of creating variable to store it. This can be done by making the variable public (generally bad idea) or by making it a serialized private variable (better idea).
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField] private float mySpeed = 5f;
[SerializeField] private GameObject laserPrefab;
...
}
This will expose the variable in the Unity Editor Inspector.
It is then a simple matter of dragging the laser prefab over and dropping it on the on the field.
Once this is done, our Player script will now have a reference to the Laser prefab and can instantiate it with a single line of code.
void Update()
{
MovePlayer();
CheckBoundaries();
if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(laserPrefab, transform.position, Quaternion.identity);
}
}
The if statement checks for each time the spacebar is pressed down. When the keypress is detected, a new laser game object is created. The Instantiate()
function takes three arguments. The first is the reference to the prefab. The second is position to place it. In this case, the same position as our player game object. The third is a rotation. Since we actually do not actually care about rotation we can use the default Quaternion.identity
property.
Once the laser game object has been instantiated, however, the laser takes over control of itself. The first thing we need to do is tell the laser to go up. Fortunately, we already know how to do this.
using UnityEngine;
public class Laser : MonoBehaviour
{
[SerializeField] float mySpeed = 8.0f;
void Start()
{
}
void Update()
{
transform.Translate(Vector3.up * Time.deltaTime * mySpeed);
}
}
We create and set a variable to control the speed of the laser and then just tell it to go up. But letting it go up eternally makes no real sense. At some point the laser is no longer needed and can be destroyed. The question is just when. The simplest answer is to just check its position and destroy it once it gets off screen. It is important to understand what is actually being destroyed. It is not the keyword this
which actually refers to the script itself. Simply executing Destroy(this)
will destroy the script object, but not the laser game object. Fortunately, the script contains a reference to the game object it is attached to and is stored in the property this.gameObject
. Of course, destroying the game object destroys everything attached to it, including the script.
using UnityEngine;
public class Laser : MonoBehaviour
{
[SerializeField] float mySpeed = 8.0f;
void Start()
{
}
void Update()
{
transform.Translate(Vector3.up * Time.deltaTime * mySpeed);
if (transform.position.y > 8f) { Destroy(this.gameObject); }
}
}
But I really don’t like running an if statement sixty times a second if not needed. It turns out, the Destroy()
method has an alternate form. The alternate form allows us to set a time limit on the object’s lifespan. Conceptually, this makes our laser more of a “fire and forget” rather than a “fire and keep checking” design.
using UnityEngine;
public class Laser : MonoBehaviour
{
[SerializeField] float mySpeed = 8.0f;
void Start()
{
Destroy(this.gameObject, 3);
}
void Update()
{
transform.Translate(Vector3.up * Time.deltaTime * mySpeed);
}
}
Since we don’t need to keep checking it, the Destroy()
method can be called just once, in the Start()
method. Once invoked, a three second countdown will begin and the object will be destroyed, no matter where it is. Unless of course, it is destroyed before that.