Making the laser… uh… laser
If you haven’t been following along with this series, I recommend you read part 1, part 2, and part 3 before continuing. We’ll be building on the code created in those articles.
This isn’t really related to Unity’s new Input System, but since we’ve gone as far as creating our laser bolt I thought it would be nice to actually make it do something instead of just hovering in mid-air. So we’re going to make our player fire those bolts straight up towards the top of the screen a la Space Invaders.
Moving the laser
Start by creating a new script on the Laser prefab and opening it in your editor of choice (I use Visual Studio). At the top of the class, create the following variable:
[SerializeField]
private float _speed = 8f;
This gives us an easy way to tweak the speed that the bolt will move at while keeping it nice and private so that other classes can’t change it unexpectedly.
Now in the Update() loop add the following:
transform.Translate(Vector3.up * _speed * Time.deltaTime);
Vector3.up
is a nice shorthand way of saying new Vector3(0, 1, 0)
. Not only is it shorter, but it’s clearer to see at a glance exactly what the vector is doing. And like when we moved our player, we’re using Time.deltaTime
to tie the movement to realtime instead of framerate.
If you run the game now and fire your laser, you should see it moving straight up the screen.
Clean up after yourself
If you fired a number of laser bolts, you’ll probably have noticed that you start accumulating quite a list of them in the hierarchy. And if you click on any of those instances you’ll see that their y-position just keeps increasing — they’re firing off into forever! This is bad practise for a number of reasons, not least the fact that they’re sitting there in memory for no good reason.
Back in your Laser script, add this variable:
private float _destroyPos = 7.5f;
This is going to hold the point at which the laser bolt is far enough off screen that we can remove it without the player noticing. For me, this is about 7.5 on the y-axis.
Now add the following into the Update() loop, under the line where we moved the laser:
if (transform.position.y >= _destroyPos)
{
Destroy(gameObject);
}
Here we’re checking if the laser’s y-position is greater than or equal to the position at which we can safely destroy it. If it is, then we destroy it.
Cool your lasers!
At the moment, you can fire as fast as you can hit the button. While fun, this is probably not what you’re going to want in your game. It makes far more sense to restrict the rate at which the laser can be fired.
For this one, we’re returning to our Player script. Open it up and add these variables:
[SerializeField]
private float _fireRate = 0.5f;
private float _nextFire = 0;
_fireRate
is the delay we want between shots, and we’re serialising it so that we can tweak it in the editor if we want to. _nextFire
does exactly what it says on the tin: it’s the time when we can next fire a laser bolt. We’ll see how to use that next.
Find the OnFire() method we created. We’re going to put that Instantiate call into an if-statement, like this:
if (Time.time > _nextFire)
{
_nextFire = Time.time + _fireRate;
Instantiate(_laserPrefab, transform.position + _laserOffset, Quaternion.identity);
}
So what are we doing here? First of all, we’re looking at Time.time
, which is the time that the game has been actively running. We’re comparing it to that _nextFire
variable we created and if it’s greater then we can actually do laser-firing things. Otherwise nothing happens.
If we can do laser-firing things, then we modify our _nextFire
variable by adding the _fireRate
(remember, this is the delay between shots) to the current time the game has been running. So say the game had been running for 30 seconds and we’d just fired a shot. If the _fireRate
was 5 seconds, another shot won’t fire until the game has been running for 35 seconds (in total, not 35 seconds from now).
Then the instantiation of the laser prefab happens just as before.
Now the player fires like this, no matter how quickly they mash that fire button!