The simplest way to create a First Person Shooter! (Part 1)

In just a few steps, learn how to make your very own First Person Shooter with multiple Guns, with different shooting ranges and ammunition types in Unity. Practical explanation + Code included.

Seemanta Debdas
Eincode
9 min readJan 17, 2022

--

Introduction

This is an introduction to a multiple-part series covering details about creating a Modular First Person Shooter. In the first section, we’re going to cover the following topics:
Introducing a Gun to the Player
Raycasting.
Implementing Muzzle Flash and Bullet Hole Textures.
Adding Fire Rate.

Resources

Full Course(RPG Game): https://academy.eincode.com/courses/the-complete-unity-guide-3d-beginner-to-rpg-game-dev-in-c
GitHub Repository: Blog-FirstPersonShooter

Prerequisites:

The project has been made using Universal Render Pipeline. To properly follow, install the Universal RP package from Package Manager.

This article presumes that you have a basic understanding of Unity and coding with C#. We’re going to use a First-Person Controller as a base. I’ve covered First Person Controller creation in the following article:

Learn how to create a First-Person Controller

Although not mandatory, it’s always helpful to understand what we’re working with to extend its functionalities.
You may also use one of the Controllers available on the Unity Asset Store.

With that out of the way, let’s get started!

1. Introducing a Gun to the Player!

Add a Ground for the Player to stand on by:
Right, Click on the Hierarchy → 3D Object → Plane.

Drag the First Person Character controller(Created/Imported) into the scene and manipulate its transform to make it stand on the Plane.

IMPORTANT: Make sure the Controller has a Camera as its child. If it’s there, delete all other existing Cameras in the scene.

Import a Gun Model and place it under the Player Prefab

  • Make an empty Game Object under the Camera and name it “Weapons”.
  • As a child, place the Gun Prefab that you imported (Make it a child of “Weapons” Game Object.
  • Rotate and move the Gun Prefab under the Weapons to make it a point towards the center of the screen. As shown below.
Steps to set up your gun in the scene

NOTE: If the Gun’s rear end seems to clip as it comes near the screen, change the Near Clipping Plane of the Camera component from 0.3 → 0.01.

Add a gun crosshair in the center of the screen

  1. Make a Canvas and name it “UI”.
  2. Under the Canvas Scaler component of “UI”, change UI Scale Mode to Scale with Screen Size and Reference Resolution to X:1920, Y:1080.
  3. Under “UI” make an Image and name it “Crosshair”.
  4. Download and Import a crosshair Image of choice.
  5. Make sure that the Texture Type of the imported image is set to Sprite(2D and UI).

6. Drag and drop the imported image to the Source Image section of the Image component of the “Crosshair” Game Object.

Step Conclusion

Play around with the rotation and position of the weapon according to your need. The final product should look something like this:

2. Raycasting!

Raycasting is the process of shooting a ray from a point(vector3) in a direction. When the ray collides with an object, it returns a structured data object called RaycastHit.

Some of the properties of the RaycastHit include collider, distance, rigid body, and transform.

Here’s a quick example of how Raycasting works

Component of a Raycast:

  1. origin: The starting point of the ray. In the above example, the origin is the gun.
    In our project, we’re going to set the camera's position as the origin point.
  2. direction: The direction of the ray. In the above example, we’re casting the ray in the direction of the gun’s forward direction.
    In our project, we’re going to set direction as the forward of the camera.
  3. maxDistance: The max distance the ray should check for collisions. This can be used to set different Weapon Ranges.
  4. layerMask: A Layer mask used to ignore Colliders when casting a ray selectively. In the above example, the raycast ignores the Non-Hittable Layer, so it does not collide with the red wall.

RaycastHit:

It is a structure to get information back from a raycast. Basically, it contains all the details related to the raycast collision.

Properties of interest:

  1. point: It is the point of collision — the impact point where the ray hits the collider
  2. normal: It is the unit vector, normal to the surface the ray hit. In the above example, it’s depicted using a blue arrow.

Raycasting is one way of handling shooting in FPS games, and it’s also a fundamental concept of Unity.

To get started:

  1. Make a script called “Weapon” where we’re going to detect whether the Mouse0 button is being pressed.
  2. Cast a ray from the camera's position along the camera's forward direction. It would seem like we’re shooting towards the crosshair in the game.
  3. Finally, when the ray hits an object, store that information in a RaycastHit variable.

We can also add the length of the Ray we handle using the variable weaponRange, which is also serialized. That way, we can handle the Range for different weapons.

Add the above code to the Weapon prefab under “Weapons” Game Object.

Make a cube and scale it up to make it a Wall. Change the layer of the wall to “Hittable”

In the inspector, set the value of hittableLayer to “Hittable” and set the weaponRange to something reasonable (maybe 50 or more).

Play the Game, point towards the wall, and click to see our code in action!

3. Adding Game Juice!

Game Juice is what gives the player a more immersive experience. Even though our system works, this doesn’t feel like we’re operating a gun.
Let's add some particle effects for when the gun shoots and bullet holes on the points the ray hits the wall. This will significantly amplify the Game Feel!
For this project, I will use imported assets from the asset store. Feel free to use your own.

Adding Muzzle Flash

Particle System

For Muzzle Flash, we will be using Unity’s Particle System. Unity features a robust Particle System where you can simulate moving liquids, smoke, clouds, flames, magic spells, and a slew of other effects.
What differentiates a Particle System game object from any other game object is the Particle System component.

The particle system could cover many pages worth of explanations for every module it contains, so instead of making one from scratch, we’re going to use a premade asset from Unity Asset Store.

The one I’m using in this project can be found in the prefabs section of this fantastic, free to use asset pack:

Implementation

Like what we did with the weapon, drag your Muzzle Flash Prefab under the Weapon(Make it a child) and change its transform so that it sits right in front of the weapon's Muzzle.

We will be Playing and Stopping this based upon whether or not we’re shooting.

Make sure that the Play On Awake and Looping checkbox is unchecked in the particle system component. Also, set Stop Action to None.

We are going to handle its properties via code. In the Weapons script:

  1. Reference the Muzzle Flash Particle System in our code by serializing a field( in our case, muzzleFlash)

2. Check if muzzleFlash.isPlaying is true. If true, then stop it and play it again. This ensures that muzzleFlash plays for every frame when shooting is true, i.e., we’re holding the left mouse button.

NOTE: To add a bit of challenge, you can also add weapon sounds. The logic is analogous to this.

Adding Bullet Holes

To create the Bullet Hole Prefab,

  1. Right Click on Hierarchy tab→ 3D Object → Quad. Name it “Bullet Holes”.
  2. Right Click on the Project tab → Select Material. Name it “Bullet Hole Mat”. This is going to be the material of our Quad. Drag and drop it on the Quad, in the Scene view or manually assign it in the Inspector.
  3. Assign a bullet hole texture(Bullet hole Image from the internet). If you’ve got a set of normal map and metallic map, then assign it to the following sections of the Material:

4. Make the Bullet Holes Game Object a prefab by dragging it into the Project tab. We now have a blueprint for the Game Object that can be instantiated through code. So, delete the existing version of the Bullet Holes Game Object from the Hierarchy.

In our “Weapons” Script, refer the Quad Prefab, and we’ll instantiate it at the point where the ray meets the wall.

Let’s modify our HandleRaycast function to instantiate the bulletHole prefab:

The Quad will be instantiated at an added offset(bulletHolePositionOffset) so that it’s clearly visible and doesn’t get clipped through the wall.

For the above example, the bulletHolePrefab get’s instantiated at position:

hit.point +(hit.normal * bulletHolePositionOffset) = (0,0,0) + (1,0,0) * 0.05 = (0.05, 0, 0)

Step Conclusion

With all of that in mind, the following is the modified code:

4. Adding Fire Rate!

Implementing Fire Rate gives us control over how fast the Player can shoot with each weapon and solves the problem where we can shoot multiple times each frame.

To implement this, make the following changes in the code. Set the fire rate value depending on how fast or slow you want your weapon to be.

This prevents the Player from shooting continuously without any interval in between.

Time.time represents the time passed(in seconds) since the start of the application or start of Play Mode.

Let’s say our Fire Rate is 0.5 and Time.time is 0.7.

Initially thresholdTime is 0. Therefore, thresholdTime < Time.time is True. Hence, canShoot is set to True. thresholdTime is updated to 0.7+0.5( Time.time + fireRate) = 1.2

Until Time.time reaches the 1.2-second mark, canShoot remains false, restricting the Player from shooting.

Before adding Fire Rate

After adding Fire Rate

Conclusion

In the next parts, we’re going to take it to cover the following topics:

→ Zooming functionality!
→Multiple Weapon Types!
→Weapon Differentiation!

If this simple First Person Shooter piqued your curiosity, then you should consider opting for The Complete Unity Guide 3D- Beginner to RPG Game Dev in C# offered by Eincode. This course features among the most immersive and practical resources out there.
This course is curated by experienced software engineer and freelance developer Filip Jerga, this course starts with the fundamentals. Then, it progresses gradually to eventually take its subscribers through the journey of developing their own RPG game by using Unity 2020 and C#!

Cheers!
Debdas

--

--

Seemanta Debdas
Eincode

Game Dev enthusiast contributing to the Gaming Industry!