Build a First Person Shooter

John P. Doran

February 2016

We will be creating a first person shooter; however, instead of shooting a gun to damage our enemies, we will be shooting a picture in a survival horror environment; similar to the Fatal Frame series of games and the recent indie title DreadOut. To get started on our project, we're first going to look at creating our level or, in this case, our environments starting with the exterior.

In the game industry, there are two main roles in level creation: the environment artist and level designer.

An environment artist is a person who builds the assets that go into the environment. He/she uses tools such as 3ds Max or Maya to create the model, 
and then uses other tools such as Photoshop to create textures and normal maps.

The level designer is responsible for taking the assets that the environment artist has created and assembling them into an environment for players to enjoy. He/she designs the gameplay elements, creates the scripted events, and tests the gameplay. Typically, a level designer will create environments through a combination of scripting and using a tool that may or may not be in development as the game is being made. In our case, that tool is Unity.

One important thing to note is that most companies have their own definition for different roles. In some companies, a level designer may need to create assets and an environment artist may need to create a level layout. There are also some places that hire someone to just do lighting, or just to place meshes (called a mesher) because they're so good at it.

(For more resources related to this topic, see here.)

Project overview

In this article, we take on the role of an environment artist whose been tasked with creating an outdoor environment. We will use assets that I've placed in the example code as well as assets already provided to us by Unity for mesh placement. In addition to this, you will also learn some beginner-level design.

Your objectives

This project will be split into a number of tasks. It will be a simple step-by-step process from the beginning to end. Here is an outline of our tasks:

  • Creating the exterior environment – Terrain
  • Beautifying the environment – adding water, trees, and grass
  • Building the atmosphere
  • Designing the level layout and background

The project setup

At this point, I assume you have a fresh installation of Unity and have started it. You can perform the following steps:

  1. With Unity started, navigate to File | New Project.
  2. Select a project location of your choice somewhere on your hard drive and ensure that you have Setup defaults for set to 3D.
  3. Once completed, click on Create. Here, if you see the Welcome to Unity pop up, feel free to close it as we won't be using it.

    Level design 101 – planning

    Now just because we are going to be diving straight into Unity, I feel it's important to talk a little more about how level design is done in the gaming industry. While you may think a level designer will just jump into the editor and start playing, the truth is you normally would need to do a ton of planning ahead of time before you even open up your tool.

    Generally, a level design begins with an idea. This can come from anything; maybe you saw a really cool building, or a photo on the Internet gave you a certain feeling; maybe you want to teach the player a new mechanic. Turning this idea into a level is what a level designer does. Taking all of these ideas, the level designer will create a level design document, which will outline exactly what you're trying to achieve with the entire level from start to end.

    A level design document will describe everything inside the level; listing all of the possible encounters, puzzles, so on and so forth, which the player will need to complete as well as any side quests that the player will be able to achieve. To prepare for this, you should include as many references as you can with maps, images, and movies similar to what you're trying to achieve. If you're working with a team, making this document available on a website or wiki will be a great asset so that you know exactly what is being done in the level, what the team can use in their levels, and how difficult their encounters can be. Generally, you'll also want a top-down layout of your level done either on a computer or with a graph paper, with a line showing a player's general route for the level with encounters and missions planned out.

    Of course, you don't want to be too tied down to your design document and it
    will change as you playtest and work on the level, but the documentation process
    will help solidify your ideas and give you a firm basis to work from.

    For those of you interested in seeing some level design documents, feel free to check out Adam Reynolds (Level Designer on Homefront and Call of Duty: World at War) at http://wiki.modsrepository.com/index.php?title=Level_Design:_Level_Desig....

    If you want to learn more about level design, I'm a big fan of Beginning Game Level Design, John Feil (previously my teacher) and Marc Scattergood, Cengage Learning PTR. For more of an introduction to all of game design from scratch, check out Level Up!: The Guide to Great Video Game Design, Scott Rogers, Wiley and The Art of Game Design, Jesse Schell, CRC Press.

    For some online resources, Scott has a neat GDC talk called Everything I Learned About Level Design I Learned from Disneyland, which can be found at http://mrbossdesign.blogspot.com/2009/03/everything-i-learned-about-game..., and World of Level Design (http://worldofleveldesign.com/) is a good source for learning about level design, though it does not talk about Unity specifically.

    Exterior environment – terrain

    When creating exterior environments, we cannot use straight floors for the most part, unless you're creating a highly urbanized area. Our game takes place in a haunted house in the middle of nowhere, so we're going to create a natural landscape. In Unity, the best tool to use to create a natural landscape is the Terrain tool. Unity's terrain system lets us add landscapes, complete with bushes, trees, and fading materials to our game.

    To show how easy it is to use the terrain tool, let's get started.

    The first thing that we're going to want to do is actually create the terrain we'll be placing for the world. Let's first create a terrain by navigating to GameObject | Create Other | Terrain:

    If you are using Unity 4.6 or later, navigate to GameObject | Create  General | Terrain to create the Terrain.

    At this point, you should see the terrain. Right now, it's just a flat plane, but we'll be adding a lot to it to make it shine. If you look to the right with the Terrain object selected, you'll see the Terrain Editing tools, which can do the following (from left
    to right):

    • Raise/Lower Height: This option will allow us to raise or lower the height of our terrain up to a certain radius to create hills, rivers, and more.
    • Paint Height: If you already know the exact height that a part of your terrain needs to be, this option will allow you to paint a spot on that location.
    • Smooth Height: This option averages out the area that it is in, and then attempts to smooth out areas and reduce the appearance of abrupt changes.
    • Paint Texture: This option allows us to add textures to the surface of our terrain. One of the nice features of this is the ability to lay multiple textures on top of each other.
    • Place Trees: This option allows us to paint objects in our environment, which will appear on the surface. Unity attempts to optimize these objects by billboarding distant trees so that we can have dense forests without a horrible frame rate.
    • Paint Details: In addition to trees, we can also have small things such as rocks or grass covering the surface of our environment. We can use 2D images to represent individual clumps using bits of randomization to make
      it appear more natural.
    • Terrain Settings: These are settings that will affect the overall properties of a particular terrain; options such as the size of the terrain and wind can be found here.

    By default, the entire terrain is set to be at the bottom, but we want to have some ground above and below us; so first, with the terrain object selected, click on the second button to the left of the terrain component (the Paint Height mode). From here, set the Height value under Settings to 100 and then click on the Flatten button. At this point, you should notice the plane moving up, so now everything is above
    by default.

    Next, we are going to add some interesting shapes to our world with some hills by painting on the surface. With the Terrain object selected, click on the first button to the left of our Terrain component (the Raise/Lower Terrain mode). Once this is completed, you should see a number of different brushes and shapes that you can select from.

    Our use of terrain is to create hills in the background of our scene so that it does not seem like the world is completely flat.

    Under the Settings area, change the Brush Size and Opacity values of your brush to 100 and left-click around the edges of the world to create some hills. You can increase the height of the current hills if you click on top of the previous hill. This is shown in the following screenshot:

    When creating hills, it's a good idea to look at multiple angles while you're building them, so you can make sure that none are too high or too short. Generally, you want to have taller hills as you go further back, otherwise you cannot see the smaller ones since they would be blocked.

    In the Scene view, to move your camera around, you can use the toolbar in the top right corner or hold down the right mouse button and drag it in the direction you want the camera to move around in, pressing the W, A, S, and D keys to pan. In addition, you can hold down the middle mouse button and drag it to move the camera around. The mouse wheel can be scrolled to zoom in and out from where the camera is.

    Even though you should plan out the level ahead of time on something like a piece of graph paper to plan out encounters, you will want to avoid making the level entirely from the preceding section, as the player will not actually see the game with a bird's eye view in the game at all (most likely). Referencing the map from the same perspective of your character will help ensure that the map looks great.

    To see many different angles at one time, you can use a layout with multiple views of the scene, such as the 4 Split.

    Once we have our land done, we now want to create some holes in the ground, which we will fill in with water later. This will provide a natural barrier to our
    world that players will know they cannot pass, so we will create a moat by first changing the Brush Size value to 50 and then holding down the Shift key, and
    left-clicking around the middle of our texture. In this case, it's okay to use the Top view; remember this will eventually be water to fill in lakes, rivers, and so on, as shown in the following screenshot:

    At this point, we have done what is referred to in the industry as "greyboxing", making the level in the engine in the simplest way possible but without artwork (also known as "whiteboxing" or "orangeboxing" depending on the company you're working for).

    At this point in a traditional studio, you'd spend time playtesting the level and iterating on it before an artist or you takes the time to make it look great. However, for our purposes, we want to create a finished project as soon as possible. When doing your own games, be sure to play your level and have others play your level before you polish it.

    For more information on greyboxing, check out http://www.worldofleveldesign.com/categories/level_design_tutorials/art_....

    For an example with images of a greybox to the final level, PC Gamer has a nice article available at http://www.pcgamer.com/2014/03/18/building-crown-part-two-layout-design-....

    This is interesting enough, but being in an all-white world would be quite boring. Thankfully, it's very easy to add textures to everything. However, first we need to have some textures to paint onto the world and for this instance, we will make
    use of some of the free assets that Unity provides us with.

  4. So, with that in mind, navigate to Window | Asset Store.

    • The Asset Store option is home to a number of free and commercial assets that can be used with Unity to help you create your own projects created by both Unity and the community. While we will not be using any unofficial assets, the Asset Store option may help you in the future to save your time
      in programming or art asset creation.
  5. An the top right corner, you'll see a search bar; type terrain assets and press Enter. Once there, the first asset you'll see is Terrain Assets, which is released by Unity Technologies for free. Left-click on it and then once at the menu, click on the Download button:
  6. Once it finishes downloading, you should see the Importing Package dialog box pop up. If it doesn't pop up, click on the Import button where the Download button used to be:
  7. Generally, you'll only want to select the assets that you want to use and uncheck the others. However, since you're exploring the tools, we'll just
    click on the Import button to place them all.
  8. Close the Asset Store screen; if it's still open, go back into our game view.
    You should notice the new Terrain Assets folder placed in our Assets folder. Double-click on it and then enter the Textures folder:
    • These will be the textures we will be placing in our environment:
  9. Select the Terrain object and then click on the fourth button from the left to select the Paint Texture button. Here, you'll notice that it looks quite similar to the previous sections we've seen. However, there is a Textures section as well, but as of now, there is the information No terrain textures defined in this section. So let's fix that. Click on the Edit Textures button and then select Add Texture.
  10. You'll see an Add Terrain Texture dialog pop up. Under the Texture variable, place the Grass (Hill) texture and then click on the Add button:
  11. At this point, you should see the entire world change to green if you're far away. If you zoom in, you'll see that the entire terrain uses the Grass (Hill) texture now:
  12. Now, we don't want the entire world to have grass. Next, we will add cliffs around the edges where the water is. To do this, add an additional texture by navigating to Edit Textures... | Add Texture. Select Cliff (Layered Rock) as the texture and then select Add. Now if you select the terrain, you should see two textures. With the Cliff (Layered Rock) texture selected, paint the edges of the water by clicking and holding the mouse, and modifying the Brush Size value as needed:
  13. We now want to create a path for our player to follow, so we're going to create yet another texture this time using the GoodDirt material. Since this is a path the player may take, I'm going to change the Brush Size value to 8 and the Opacity value to 30, and use the second brush from the left, which is slightly less faded. Once finished, I'm going to paint in some trails that the player can follow. One thing that you will want to try to do is make sure that the player shouldn't go too far before having to backtrack and reward the player for exploration. The following screenshot shows the path:
    • However, you'll notice that there are two problems with it currently. Firstly, it is too big to fit in with the world, and you can tell that it repeats.
  14. To reduce the appearance of texture duplication, we can introduce new materials with a very soft opacity, which we place in patches in areas where there is just plain ground. For example, let's create a new texture with the Grass (Meadow) texture. Change the Brush Size value to 16 and the Opacity value to something really low, such as 6, and then start painting the areas that look too static. Feel free to select the first brush again to have a smoother touch up.
  15. Now, if we zoom into the world as if we were a character there, I can tell that the first grass texture is way too big for the environment but we can actually change that very easily. Double-click on the texture to change the Size value to (8,8). This will make the texture smaller before it duplicates. It's a good idea to have different textures with different sizes so that the seams of each texture aren't visible to others. The following screenshot shows the size options:
  16. Do the same changes as in the preceding step for our Dirt texture as well, changing the Size option to (8,8):

    With this, we already have a level that looks pretty nice! However, that being said, it's just some hills. To really have a quality-looking title, we are going to need to do some additional work to beautify the environment.

    Beautifying the environment – adding water, trees, and grass

    We now have a base for our environment with the terrain, but we're still missing a lot of polish that can make the area stand out and look like a quality environment. Let's add some of those details now:

  17. First, let's add water. This time we will use another asset from Unity, but we will not have to go to the Asset Store. Navigate to Assets | Import Package | Water (Basic) and import all of the files included in the package.
  18. We will be creating a level for the night time, so navigate to Standard Assets | Water Basic and drag-and-drop the Nighttime Simple Water prefab onto the scene. Once there, set the Position values to (1000,50, 1000) and the Scale values to (1000,1,1000):
    • At this point, you want to repaint your cliff materials to reflect being next to the water better.
  19. Next, let's add some trees to make this forest level come to life. Navigate to Terrain Assets | Trees Ambient-Occlusion and drag-and-drop a tree into your world (I'm using ScotsPineTree).
    • By default, these trees do not contain collision information, so our player could just walk through it. This is actually great for areas that the player will not reach as we can add more trees without having to do meaningless calculations, but we need to stop the player from walking into these. To do that, we're going to need to add a collider.
  20. To do so, navigate to Component | Physics | Capsule Collider and then change the Radius value to 2.

    You have to use a Capsule Collider in order to have the collision carried over to the terrain.

  21. After this, move our newly created tree into the Assets folder under the Project tab and change its name to CollidingTree. Then, delete the object from the Hierarchy view. With this finished, go back to our Terrain object and then click on the Place Trees mode button. Just like working with painting textures, there are no trees here by default, so navigate to Edit Trees… | Add Tree, add our CollidingTree object created earlier in this step, and then select Add.
  22. Next, under the Settings section, change the Tree Density value to 15 and then with our new tree selected, paint the areas on the main island that do not have paths on them. Once you've finished with placing those trees, up the Tree Density value to 50 and then paint the areas that are far away from paths to make it less likely that players go that way.
  23. You should also enable Create Tree Collider in the terrain's Terrain
    Collider
    component:
  24. In our last step to create an environment, let's add some details. The mode next to the Plant Trees mode is Paint Details. Next, click on the Edit Details… button and select Add Grass Texture. Select the Grass texture
    for the Detail Texture option and then click on Add. In the terrain's Settings mode (the one on the far right), change the Detail Distance value to 250,
    and then paint the grass where there isn't any dirt along the route in the Paint Details mode:
    • You may not see the results unless you zoom your camera in, which you can do by using the mouse wheel. Don't go too far in though, or the results may not show as well.

    This aspect of level creation isn't very difficult, just time consuming. However, it's taking time to enter these details that really sets a game apart from the other games. Generally, you'll want to playtest and make sure your level is fun before performing these actions; but I feel it's important to have an idea of how to do it for your future projects.

  25. Lastly, our current island is very flat, and while that's okay for cities, nature is random. Go back into the Raise/Lower Height tool and gently raise and lower some areas of the level to give the illusion of depth. Do note that your trees and grass will raise and fall with the changes that you make, as shown in the following screenshot:
  26. With this done, let's now add some details to the areas that the player will not be visiting, such as the outer hills. Go into the Place Trees mode and create another tree, but this time select the one without collision and then place it around the edges of the mountains, as shown in the following screenshot:

    At this point, we have a nice exterior shape created with the terrain tools!

    If you want to add even more detail to your levels, you can add additional trees and/or materials to the level area as long as it makes sense for them to be there.

    For more information on the terrain engine that Unity has, please visit http://docs.unity3d.com/Manual/script-Terrain.html.

    Creating our player

    Now that we have the terrain and its details, it's hard to get a good picture of what the game looks like without being able to see what it looks like down on the surface, so next we will do just that. However, instead of creating our player from scratch as we've done previously, we will make use of the code that Unity has provided us. We
    will perform the following steps:

  27. Start off by navigating to Assets | Import Package | Character Controller. When the Importing Package dialog comes up, we only need to import the files shown in the following screenshot:
  28. Now drag-and-drop the First Person Controller prefab under the Prefabs folder in our Project tab into your world, where you want the player to spawn, setting the Y Position value to above 100. If you see yourself fall through the world instead of hitting the ground when you spawn, then increase the Y Position value until you get there.
  29. If you open up the First Person Controller object in the Hierarchy tab, you'll notice that it has a Main Camera object already, so delete the Main Camera object that already exists in the world.
  30. Right now, if we played the game, you'd see that everything is dark
    because we don't have any light. For the purposes of demonstration, let's add a directional light by navigating to GameObject | Create Other | Directional Light.

    If you are using Unity 4.6 or later, navigate to GameObject | Create  General | Terrain to create the Terrain.

  31. Save your scene and hit the Play button to drop into your level:

    At this point, we have a playable level that we can explore and move around in!

    Building the atmosphere

    Now, the base of our world has been created; let's add some effects to make the
    game even more visually appealing and so it will start to fit in with the survival horror feel that we're going to be giving the game.

    The first part of creating the atmosphere is to add something for the sky aside from the light blue color that we currently use by default. To fix this, we will be using a skybox. A skybox is a method to create backgrounds to make the area seem bigger than it really is, by putting an image in the areas that are currently being filled with the light blue color, not moving in the same way that the sky doesn't move to us because it's so far away.

    The reason why we call a skybox a skybox is because it is made up of six textures that will be the inside of the box (one for each side of a cube). Game engines such as Unreal have skydomes, which are the same thing; but they are done with a hemisphere instead of a cube. We will perform the following steps to build the atmosphere:

  32. To add in our skybox, we are going to navigate to Assets | Import Package | Skyboxes. We want our level to display the night, so we'll be using the Starry Night Skybox. Just select the StarryNight Skybox.mat file and textures inside the Standard Assets/Skyboxes/Textures/StarryNight/ location, and then click on Import:
  33. With this file imported, we need to navigate to Edit | Render Settings
    next. Once there, we need to set the Skybox Material option to the Starry Night skybox:
    • If you go into the game, you'll notice the level starting to look nicer already with the addition of the skybox, except for the fact that the sky says night while the world says it's daytime. Let's fix that now.
  34. Switch to the Game tab so that you can see the changes we'll be making next. While still at the RenderSettings menu, let's turn on the Fog property by clicking on the checkbox with its name and changing the Fog Color value to a black color. You should notice that the surroundings are already turning very dark. Play around with the Fog Density value until you're comfortable with how much the player can see ahead of them; I used 0.005.
    • Fog obscures far away objects, which adds to the atmosphere and saves the rendering power. The denser the fog, the more the game will feel like a horror game. The first game of the Silent Hill franchise used fog to make the game run at an acceptable frame rate due to a large 3D environment it had on early PlayStation hardware. Due to how well it spooked players, it continued to be used in later games even though they could render larger areas with the newer technology.
    • Let's add some lighting tweaks to make the environment that the player is walking in seem more like night.
  35. Go into the DirectionalLight properties section and change the Intensity value to 0.05. You'll see the value get darker, as shown in the following screenshot:

    If for some reason, you'd like to make the world pitch black, you'll need to modify the Ambient Light property to black inside the RenderSettings section. By default, it is dark grey, which will show up even if there are no lights placed in the world.

    In the preceding example, I increased the Intensity value to make it easier to see the world to make it easier for readers to follow, but in your project, you probably don't want the player to see so far out with such clarity.

    With this, we now have a believable exterior area at night! Now that we have this basic knowledge, let's add a flashlight so the players can see where they are going.

    Creating a flashlight

    Now that our level looks like a dark night, we still want to give our players the ability to see what's in front of them with a flashlight. We will customize the First Person Controller object to fit our needs:

  36. Create a spotlight by navigating to GameObject | Create Other | Spotlight. Once created, we are going to make the spotlight a child of the First Person Controller object's Main Camera object by dragging-and-dropping it on
    top of it.
  37. Once a child, change the Transform Position value to (0, -.95, 0). Since positions are relative to your parent's position, this places the light slightly lower than the camera's center, just like a hand holding a flashlight. Now change the Rotation value to (0,0,0) or give it a slight diagonal effect across the scene if you don't want it to look like it's coming straight out:
  38. Now, we want the flashlight to reach out into the distance. So we will change the Range value to 1000, and to make the light wider, we will change the Spot Angle value to 45. The effects are shown in the following screenshot:

    If you have Unity Pro, you can also give shadows to the world based on your lights by setting the Shadow Type property.

    We now have a flashlight, so the player can focus on a particular area and not worry.

    Walking / flashlight bobbing animation

    Now the flashlight looks fine in a screenshot, but if you walk throughout the world, it will feel very static and unnatural. If a person is actually walking through the forest, there will be a slight bob as you walk, and if someone is actually holding a flash light, it won't be stable the entire time because your hand would move. We can solve both of these problems by writing yet another script. We perform the following steps:

  39. Create a new folder called Scripts. Inside this folder, create a new C# script called BobbingAnimation.
  40. Open the newly created script and use the following code inside it:
    using UnityEngine;
    
    using System.Collections;
    
     
    
    /// <summary>
    
    /// Allows the attached object to bob up and down through 
    /// movement or
    
    /// by default.
    
    /// </summary>
    
    public class BobbingAnimation : MonoBehaviour
    
    {
    
      /// <summary>
    
      /// The elapsed time.
    
      /// </summary>
    
      private float elapsedTime;
    
     
    
      /// <summary>
    
      /// The starting y offset from the parent.
    
      /// </summary>
    
      private float startingY;
    
     
    
      /// <summary>
    
      /// The controller.
    
      /// </summary>
    
      private CharacterController controller;
    
     
    
      /// <summary>
    
      /// How far up and down the object will travel
    
      /// </summary>
    
      public float magnitude = .2f;
    
     
    
      /// <summary>
    
      /// How often the object will move up and down
    
      /// </summary>
    
      public float frequency = 10;
    
     
    
      /// <summary>
    
      /// Do you always want the object to bob up and down or 
      /// with movement?
    
      /// </summary>
    
      public bool alwaysBob = false;
    
     
    
      /// <summary>
    
      /// Start this instance.
    
      /// </summary>
    
      void Start ()
    
      {
    
        startingY = transform.localPosition.y;
    
        controller = GetComponent<CharacterController> ();
    
      }
    
     
    
      /// <summary>
    
      /// Update this instance.
    
      /// </summary>
    
      void Update ()
    
      {     
    
        // Only increment elapsedTime if you want the player to 
        // bob, keeping it the same will keep it still
    
        if(alwaysBob)
    
        {
    
          elapsedTime += Time.deltaTime;
    
        }
    
        else
    
        {
    
          if((Input.GetAxis("Horizontal") != 0.0f) || 
    (Input.GetAxis("Vertical")  != 0.0f) )
    
            elapsedTime += Time.deltaTime;
    
        }
    
       
    
        float yOffset = Mathf.Sin(elapsedTime * frequency) * 
    magnitude;
    
     
    
        //If we can't find the player controller or we're 
        // jumping, we shouldn't be bobbing
    
        if(controller && !controller.isGrounded)
    
        {
    
          return;
    
        }
    
     
    
        //Set our position
    
        Vector3 pos = transform.position;
    
       
    
        pos.y = transform.parent.transform.position.y + 
                startingY + yOffset;
    
       
    
        transform.position = pos;
    
       
    
      }
    
    }
    • The preceding code will tweak the object it's attached to so that it will bob up and down whenever the player is moving along the x or y axis. I've also added a variable called alwaysBob, which, when true, will make the object always bob.
    • Math is a game developer's best friend, and here we are using sin (pronounced sine). Taking the sin of an angle number gives you the ratio of the length of the opposite side of the angle to the length of the hypotenuse
      of a right-angled triangle.
    • If that didn't make any sense to you, don't worry. The neat feature of sin is that as the number it takes gets larger, it will continuously give us a value between 0 and 1 that will go up and down forever, giving us a smooth repetitive oscillation.

      For more information on sine waves, visit
      http://en.wikipedia.org/wiki/Sine_wave.

    • While we're using the sin just for the player's movement and the flashlight, this could be used in a lot of effects, such as having save points/portals bob up and down, or any kind of object you would want to have slight movement or some special FX.
  41. Next, attach the BobbingAnimation component to the Main Camera object, leaving all the values with the defaults.
  42. After this, attach the BobbingAnimation component to the spotlight as well. With the spotlight selected, turn the Always Bob option on and change the Magnitude value to .05 and the Frequency value to 3. The effects are shown in the following screenshot:

Summary

To learn more about FPS game, the following books published by Packt Publishing (https://www.packtpub.com/) are recommended:

Building an FPS Game with Unity (https://www.packtpub.com/game-development/building-fps-game-unity)

Resources for Article:

 


Further resources on this subject:


You've been reading an excerpt of:

Unity Game Development Blueprints

Explore Title
comments powered by Disqus