Basic Projectile Shooting in Unity 2019.4 for 2.5D Shooter
Objective: Implement the concept of shooting projectiles by pressing the spacebar, and learn how to create a prefab of an object.
Creating the Bullet Prefab
The first thing we are going to do is create a sphere object in our hierarchy. To do this, go over to the hierarchy and press the + button, then select 3D Object, followed up by Sphere.
The next step involves renaming the object to Bullet, and adding a few components to it. The first component needing to be added is a rigidbody. A rigidbody component is being added so when the bullet collides with an object, the collision can be detected. If there is no rigidbody, no collision will be detected.
The next component that needs to be added to the Bullet is a script. Create a new script and call Bullet. Drag it onto the Bullet Object.
Now that the necessary components have been added, some components that already existed on the object need to be modified. The first component being the Bullet’s transform. Both the position and rotation will need to be zeroed out and the scale for the x, y and z will be set to 0.25.
To follow, the next steps will be to make sure Is Trigger is checked for the Sphere Collider, and to uncheck Use Gravity from the Rigidbody component.
Finally, we can create the prefab!
First, create a folder called Prefabs. Then click and drag the Bullet object from the hierarchy to the Prefabs folder. It’s not so bad, is it?
The Bullet Script
Now we have a bullet, but it can’t do anything or go anywhere. We need to create a script to make this bullet more than a paper weight!
Open the Bullet script that was created for the Bullet object and remove both the Start() and Update() methods. The first thing the bullet will need is a speed variable so it can travel. To do this, make a float variable with a SerializeField attribute and call it _spd and as a default value set it to 15.0f. It is serializable that way we can adjust the value in the inspector if need be.
Now that the _spd variable has been created the bullet actually needs to move. To do so, create two methods: Update() and BulletMovement().
In the Update method, add BulletMovement() to it.
In the BulletMovement method, the first thing that needs to be done is to set a direction for the bullet to travel. In this instance, the bullet needs to be shooting right because the enemies are going to be coming from that direction. That being said, create a local Vector3 variable called bulletVelocity variable and set it equal to Vector3.right multiplied by _spd.
So, the bullet has a direction and a speed but it still can’t move. Using transform.Translate and using the bulletVelocity variable will make the bullet move. There’s one thing wrong with this however, if we leave it the way it is, the bullet will move as fast as the frame rate of the device. It has to move at the same speed regardless of any device’s FPS. This means the bulletVelocity argument must be multiplied by Time.deltatime, therefore it works based on timeframe not framerate.
That should be it for now for our bullet script. If we go back into Unity and run the game we should see the bullet fly in the right direction.
Now that the bullet moves, delete it from the hierarchy.
Allowing the Player to Shoot
The bullet moves, but we can’t spawn them. How do we fix this issue? The initial step is to reopen the player script and create a new method called PlayerShoot().
Every gun needs a trigger, in this case, our trigger will be the space bar. So in the PlayerShoot method the first thing to check for is if the space bar is pressed.
A bullet can’t be spawned right now simply because it won’t prevent the person playing the game from spamming the space bar. To stop this, create two global variables: the first a float with the SerializeField attribute called _fireRate set to 1.0f, and float called _cycleTime set to 0.0f.
_fireRate will be the interval at which another round is chambered and _cycleTime will be the time since the last shot was fired.
That being said, the next check in our PlayerShoot method will be to check and see if Time.time > _cycletime. This checks to see the amount of time since the game has been playing and checks to see if it is greater than the last time a bullet was shot. If it is, we can shoot.
Before the bullet leaves the player, the _fireRate variable will be used to set our next _cycleTime, which will be the next time we will be allowed to shoot again.
To create a bullet when pressing the spacebar a global GameObject variable using the SerializedField attribute needs to be created. Call this variable _bullet.
To assign the bullet prefab, go back to Unity and click on the Player object in the hierarchy. Then drag the Bullet Prefab from the prefab folder onto the Player Script’s Bullet Object.
A good habit to get into is to always check that something exists before calling on it. If not, weird bugs can happen. To check if an object exists is easy. Just use an if statement and see if the _bullet is not null. If it isn’t we will create one, otherwise, we will throw an error to let us know that it does not exist.
To create an object use a function called Instantiate. In this function you will call the object you want to create (our bullet), the position at which it is created (the player’s center), and the rotation of the object (none).
When deciding the position, figure that the player is shooting and wherever it moves it needs to shoot from. Calling transform.position will get the position of the player object and spawn it from there no matter where the player is on the screen. For the rotation, using Quaternion.Identity will not impose any rotation on the bullet object.
When you are all done, your PlayerShoot method should look like the code below. Just add PlayerShoot() to the Update method and it will be ready to try out.
The Result
When testing this out, what we are looking for is the player to shoot a bullet when the space bar is pressed from any position the player is at.
Congratulations!
Thanks for taking your time and going through this! The next step will be spawning enemies and setting boundaries. Before you know it, we will have a full fledged game.