Chapter 13: Effects, Testing, Performance, and Alt Controls

In this final chapter, we are going to go through the process of checking, supporting, polishing, and preparing our game so that it's built and ready to be played on a device, making it platform-independent. Because our game will be ready to be played on various devices, we need the game to support as many screen ratios as possible. Back in Chapter 8, Adding Custom Fonts and UI, we made our game's UI support various screen ratios. The game, however, was built purposely for a 1,920 x 1,080 resolution, as discussed in Chapter 2, Adding and Manipulating Objects.

In this chapter, we will make our game run at different screen ratios to support the use of mobile devices. This will involve changing Unity's Canvas scale and updating our Player script controls to update its screen boundaries, touch screen capability, and our ability to tap to move our ship. Furthermore, we will make our game aware that it is being played on a mobile device, and we'll make some changes, such as removing the AD button in the shop, as adverts aren't supported on PC devices.

The PC version of Killer Wave will have more polished effects applied, such as post-processing, which will basically make our game more pretty with effects such as motion blur, chromatic aberration, color grading, and a few more effects on top. We will also be looking at reflection probes to create a mirrored effect for some of our art assets in the level3 scene.

In this chapter, we'll be covering the following topics:

  • Applying physics with RigidBody
  • Customizing for different platforms
  • Preparing to build Killer Wave for mobile
  • Applying PC visual improvements
  • Adding global illumination and other settings
  • Building and testing our game

The next section will specify the exam objectives that will be covered in this chapter.

Core exam skills being covered in this chapter

The following are the core exam skills that will be covered in this chapter:

Programming core interactions:

  • Implement and configure game object behavior and physics.
  • Implement and configure input and controls.
  • Implement and configure camera views and movement.

Working in the art pipeline:

  • Understand materials, textures, and shaders, and write scripts that interact with Unity's rendering API.
  • Understand lighting, and write scripts that interact with Unity's lighting API.

Optimizing for performance and platforms:

  • Evaluate errors and performance issues using tools such as the Unity Profiler.
  • Identify optimizations to address requirements for specific build platforms and/or hardware configurations.

Working in professional software development teams:

  • Demonstrate knowledge of developer testing and its impact on the software development process, including the Unity Profiler and traditional debugging and testing techniques.
  • Recognize techniques for structuring scripts for modularity, readability, and reusability.

Technical requirements

The project content for this chapter can be found at https://github.com/PacktPublishing/Unity-Certified-Programmer-Exam-Guide-Second-Edition/tree/main/Chapter_13.

You can download the entirety of each chapter's project files at https://github.com/PacktPublishing/Unity-Certified-Programmer-Exam-Guide-Second-Edition.

All the content for this chapter is held in this chapter's unitypackage file. This file includes a Complete folder, which holds all of the work we'll carry out in this chapter. So, if at any point you need some reference material or extra guidance, check it out.

Check out the following video to see the Code in Action: https://bit.ly/3rYA6k4.

Applying physics with RigidBody

Throughout this book, we have used colliders and trigger boxes to detect hits from a bullet or a selection made in the first rendition of our shop. We have also referred to applying a RigidBody component to some of these game objects with colliders to ensure that a collision is detected. We haven't made use of Rigidbody any other way so far. However, in this section, we are going to make more use of Rigidbody by making a collision happen – the blocks will collapse by our level3 boss game object going through them.

The following image shows the cargo art assets being smashed out of the way by applying and tweaking Rigidbody components, which is what we will achieve in this section:

Figure 13.1 – Boxes go flying when hit thanks to Unity's Rigidbody Component

Figure 13.1 – Boxes go flying when hit thanks to Unity's Rigidbody Component

Let's make a start by setting up our level3 scene with some pre-made assets:

  1. In the Project window, navigate to the Assets/Scene folder.
  2. Double-click the level3 scene to open it.
  3. In the Project window, drag and drop physicsBarrier from Assets/Prefab into the Hierarchy window.
  4. Select the physicsBarrier game object in the Hierarchy window and make sure its Transform Position and Rotation property values in the Inspector window are set to zero. Note that Scale should be 1 on all axes.

The following screenshot shows physicsBarrier in the level3 scene. Note the green outline, which shows that this is our series of box colliders, which will contain our physics.

Figure 13.2 – The wireframe is our collision area for our boxes

Figure 13.2 – The wireframe is our collision area for our boxes

  1. In the Hierarchy window, expand physicsBarrier to show its three children game objects.
  2. Select all three of these child objects and set their Rigidbody component so that Is Kinematic is ticked.
  3. The following screenshot shows all three game objects selected and the Rigidbody settings being updated:
Figure 13.3 – All 'physicsBarrier' gameobject children have a Rigidbody with Is Kinematic marked as true

Figure 13.3 – All 'physicsBarrier' gameobject children have a Rigidbody with Is Kinematic marked as true

Is Kinematic will ensure that these three game objects aren't affected by the physics in the scene. Even if we did tick the Use Gravity box, the game objects won't begin to fall when the scene starts as expected. So, whatever happens in our scene regarding collisions, these three game objects will remain still and solid so that they cage all of the physics engine's reactions.

Further Information

With a game object selected that holds a Rigidbody component, the following properties will alter the game object's behavior when it's manipulated by Unity's physics engine:

Mass: The game object's mass in kilograms (Default value: 1)

Drag: The air resistance, with zero being no resistance (Default value: 0)

Angular Drag: Air resistance based on rotation (Default value: 0.05)

More information about Rigidbody and its properties can be found here: https://docs.unity3d.com/ScriptReference/Rigidbody.html.

Now, we can bring our cargo boxes into the scene.

  1. In the Project window, drag and drop the cargoBulk prefab from Assets /Prefab into the Hierarchy window. As with the physicsBarrier prefab, make sure that the Transform property values are set to their default values.
  2. The cargoBulk prefab should be in place and look like the one shown in the following screenshot:
Figure 13.4 – The wall of boxes

Figure 13.4 – The wall of boxes

To reinforce cargoBulk so that it collapses at the right time, a script needs to be applied called TurnOnPhysics. This will set all of the cargo game objects from Is Kinematic that are true to false after 38 seconds, (feel free to open the TurnOnPhysics script and adjust 38 to a different number in the Update function) which is the time the boss is due to crash through the cargo boxes.

physicsBarrier and cargoBulk and their children game objects are all set as colliders. Currently, our boss is set as a trigger for when they are shot by the player. However, we don't want it to be a trigger here, as the boss will move through the cargo boxes like a ghost.

We can make boss start as a non-trigger and then, at the end of the level, turn its trigger on with the use of Timeline. To alter the Is Trigger tick box, we need to do the following:

  1. Select the Timeline game object in the Hierarchy window.
  2. Right-click the boss Timeline track asset, and from the dropdown, select Edit in Animation Window.

The following screenshot shows where to right-click and load the Animation window:

Figure 13.5 – Load the Animation Window to update the 'boss' game object animation

Figure 13.5 – Load the Animation Window to update the 'boss' game object animation

Our Animation window appears along with the keyframes from the boss game object that we placed in the previous chapter. We can add two keyframes to this window to turn it on and then off with the Is Trigger box. To do this, follow these steps:

  1. Drag Animation Indicator to the beginning of the animation track in the Animation window.
  2. Click the record button.
  3. In the Hierarchy window, select the boss game object and select Is Trigger to be unchecked in the Sphere Collider component in the Inspector window.
  4. Back in the Animation window, drag Animation Indicator all the way to frame 1193 (this will be the part where the boss game object has already burst through the boxes).
  5. Select the Is Trigger box in the Inspector window so that it's ticked.
  6. Finally, back in the Animation window, press record to turn it off and close the Animation window.
  7. Save the scene and press Play in the Unity Editor to play level3.

However, after doing this, something doesn't seem right. By the time we reach the end of the level, the boxes have already collapsed and when the boss game object collides with them, the boxes appear to float away. This is because the game objects in our scene aren't scaled to real-world size, but the gravity is. To make things look heavier, we can change the gravity of the project, as follows:

  1. At the top of the Unity Editor, go to Edit | Project Settings | Physics.

Here, we have Physics Manager, which is where the gravity has been set to its default world scale.

  1. Change the Y value of Gravity from -9.81 to -1000.
  2. Another potential issue could be that the boss goes right through the cargo boxes? To fix this, change the boss GameObject's Update Mode from Normal to Animate Physics. and make sure that Apply Root Motion is unchecked. Finally, because your boss is colliding with boxes, be sure it has a Rigidbody with Is Kinematic ticked.

    Further Information

    Your project's gravity can also be changed through scripting, as shown here: https://docs.unity3d.com/ScriptReference/Physics-gravity.html.

  3. Save the scene again. Now, if we press Play, our cargo boxes will remain, and our boss game object will burst through them, as shown in the following screenshot:
Figure 13.6 – The 'boss' game object colliding with the boxes

Figure 13.6 – The 'boss' game object colliding with the boxes

Further Information

Physics Manager contains global settings for your project's physics. One of the many useful settings at the bottom of Physics Manager is Layer Collision Matrix. This holds all the names of the layers in your project that can and cannot collide with each other. If you would like to know more about Layer Collision Matrix, check out the following link: https://docs.unity3d.com/Manual/LayerBasedCollision.html.

If you aren't happy with the way the cargo game objects react when they're hit by the boss game object, tweak its Rigidbody property values (including the ones mentioned in the first tip, earlier in this section).

Every collider can have a physics material applied to it, which will affect an object's bounciness and friction.

Creating and applying a physics material can be done in three steps:

  1. In the Project window, right-click and select Create | Physic Material.
  2. Select New Physic Material and change its property values in the Inspector window (you can also rename the file so that it represents what physical material you're trying to achieve).
  3. Select a game object with a collider. Then, click the remote button next to the Material field and select New Physic Material.
Figure 13.7 – Creating a Physic Material, updating its properties, and adding the material to a Box Collider

Figure 13.7 – Creating a Physic Material, updating its properties, and adding the material to a Box Collider

Further Information

More information about Physic Material can be found at https://docs.unity3d.com/Manual/class-PhysicMaterial.html.

Our game now has some physics effects applied to it. Now, each time the boss crashes through the cubes, the reaction will be different each time and not like a fixed animation. This is because all the movement is based on the Unity engine's physics.

Now, let's move on and make our game more customized for multiple platforms.

Customizing for different platforms

Throughout this book, we have been developing and playing our game in the Unity Editor. In this section, we are going to start making some considerations regarding what will differ between the Android and PC versions of our game. For example, mobile devices have a touchscreen, so it would be useful if our game could detect that it's being played on a mobile device and, therefore, implement the correct controls.

Also, our game has been developed with a strict 1,920 x 1,080 resolution; we have introduced flexibility with the shop scene's UI and ensured that it accommodates various aspect ratios. In this section, we will go further and make our game support various aspect ratios.

Let's get started and modify our Player script so that it supports touchscreen movement and fires on mobile devices.

Navigating and firing the player's ship with the touchscreen

In this section, we are going to revisit the Player script and add some functionality so that if and when our game is ported to an Android device, the player has touchscreen capabilities.

To allow our player to auto-fire and navigate to a touch position, we need to do the following:

  1. In the Project window, navigate to the Assets/Script folder and open the Player script.

At the top of the Player script, we are going to add some new variables to support the new control system.

  1. Add the following code, along with the rest of the variables, to the Player script:

    Vector3 direction;

    Rigidbody rb;

    public static bool mobile = false;

The direction variable will hold the player's touchscreen location; rb will hold a Rigidbody reference for our player's ship so that it can access other properties within, and the mobile variable is simply a static switch that lets the rest of the game know the player's controls.

We need to make the game recognize which platform the game is running on so that it can implement the player's mobile controls. Unity has a platform-dependent compilation that lets us choose from a list of directives so that we can determine what platform the game is running on.

  1. Scroll down to the Start function in the Player script and add the following code inside the Start function's scope:

    mobile = false;

    #if UNITY_ANDROID && !UNITY_EDITOR

        mobile = true;

        InvokeRepeating("Attack",0,0.3f);

        rb = GetComponent<Rigidbody>();

        #endif

Within the Start function, we set our mobile bool variable to false. Then, we run a platform defined directives check to see whether we are running an Android device and not using the Unity Editor.

Further Information

If you would like to find out more about other platform-dependent compilations, check out the following link:

https://docs.unity3d.com/Manual/PlatformDependentCompilation.html.

If we are using an Android device, we fall into the scope of this special type of if statement and do the following:

  • We set the bool mobile variable to true.
  • Make our Attack method get called every 0.3 seconds with Unity's own InvokeRepeating function, which acts as an auto-fire tool.
  • Assign the player_ship game object's Rigidbody to the rb variables.
  • Finally, we close the if statement.

To make our InvokeRepeating method fire a bullet with the use of the Attack method at 0.3 seconds, we need to modify the Attack method's if statement.

  1. Scroll down to the Attack method in the Player script and replace the if statement with the following:

      if (Input.GetButtonDown("Fire1") || mobile)

By adding the mobile variable to the if statement's condition, we can check whether the player is pressing the fire button or whether the mobile bool variable is set to true.

Now, we need to add more functionality to the Update function within our Player script, which includes two new methods we haven't coded in yet but will after the following code block.

  1. Replace the current Update function in the Player script and its content with the following code so that it supports PC and mobile controls:

    void Update ()

    {

       if(Time.timeScale == 1)

        {

          PlayersSpeedWithCamera();        

          if (mobile)

           {

             MobileControls();

           }

           else

           {

             Movement();

             Attack();

           }

         }

      }

Our refreshed Update function contains the following:

  • An if statement to check whether the game has been paused. If it has, we bypass the rest of the Update content. If you want to find out more about pausing the game, check out Chapter 10, Pausing the Game, Altering Sound, and a Mock Test.
  • Within the if statement, we run a new method called PlayersSpeedWithCamera, which will contain code we have already coded. We're simply moving the code into the method so that it covers PC and mobile controls for when the camera has speed applied to it.
  • Then, we have a second if statement that checks whether the mobile bool variable is set to true or false. If true, we run our MobileControls method; otherwise, our PC Movement and Attack methods will run.
  • As mentioned previously, we have two new methods (PlayersSpeedWithCamera and MobileControls). The first method is a simple cut and paste of code from the current Movement method, which we want to accommodate for PC and mobile controls. The second method will cover touch controls for when the player places their finger on the screen and the player_ship game object moves to that location.
  1. So, let's start with the PlayersSpeedWithCamera method first. Still in the Player script, scroll down to the Movement method and select and cut the first if statement. The following is the code that I want you to cut:

    if(camTravelSpeed > 1)

       {

           transform.position += Vector3.right * Time.                  

               deltaTime* camTravelSpeed;

          movingScreen += Time.deltaTime * camTravelSpeed;

       }

  2. Then, create a new method in the Player script called PlayersSpeedWithCamera and paste the previous if statement code block inside the scope of the PlayersSpeedWithCamera method.

Now, the content of the PlayersSpeedWithCamera method will run for mobile and standalone platforms. If you would like to refresh yourself on the details of the camera's travel speed, take a look at , NavMesh, Timeline, and a Mock Test.

Now, let's take a look at the second method called MobileControls, which can be found in the Player script.

  1. Write the following method inside the Player script so that the player can navigate player_ship around the screen:

        void MobileControls()

        {

            if (Input.touchCount > 0)

            {

                Touch touch = Input.GetTouch(0);

                Vector3 touchPosition = Camera.main.                ScreenToWorldPoint(new Vector3(touch.                    position.x,touch.position.y,300));

                touchPosition.z = 0;

                direction = (touchPosition - transform                 .position);

                rb.velocity = new Vector3(direction.x,                 direction.y,0)* 5;

                direction.x += movingScreen;

              

                if (touch.phase == TouchPhase.Ended)

                {

                    rb.velocity = Vector3.zero;

                }

            }

        }

Keep in mind that the MobileControls method is called on every frame in the Update function. Inside the MobileControls method, we do the following:

  • Run an if statement to check whether there has been more than one touch on the screen of the device. If a finger has touched the screen, we fall into the if statement's scope.
  • We assign a touch to a touch variable.

    Further Information

    If you would like to know more about the Touch struct and its other properties, such as deltaPosition, which is useful for measuring swipe gestures, take a look at https://docs.unity3d.com/ScriptReference/Touch.html.

  • Next, we take a ready-made function from Unity to convert the screen's touch position and store it in a world space position.

    Further Information

    If you would like to know more about converting a point into world space, check out the following link: https://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html.

  • Because we aren't affecting the player ship's z axis, we set touchPosition on the Z axis to zero.
  • Store the Vector3 position of touchPosition, minus the Vector3 position of the player's ship.
  • Send the player_ship game object to the Vector3 position that is stored in direction. Multiply it by 5 to make it move slightly faster.
  • Apply whatever value is in the movingScreen variable to the direction x position.
  • Finally, if the state of the touch phase has ended (a finger taken off the screen), apply a zero value to the rb velocity variable.

So, now, the player's ship automatically fires and can move around the screen thanks to its Rigidbody component. Now, we need to make it that when either level ends, we stop the player from firing automatically and Rigidbody no longer has an effect on the player's movement. Otherwise, when the level ends, the player's ship won't stop firing, running the risk of not being able to animate out of the level.

To fix our player from continuously shooting and being able to be moved at the end of the level, we need to do the following:

  1. In the Project window, navigate to the Assets/Script folder and open the ScenesManager script.
  2. Inside the ScenesManager script, scroll down to the if statement that checks whether the game has ended (!gameEnding) and add the following line of code within its if statement:

         if (!gameEnding)

          {

            gameEndine = true;

    StartCoroutine(MusicVolume(MusicMode.fadeDown));

            GameObject player = GameObject.Find("Player");                     // ADD THIS CODE

            player.GetComponent<Rigidbody>().isKinematic = true;               // ADD THIS CODE

            Player.mobile = false;                                          // ADD THIS CODE

            CancelInvoke();                                                 // ADD THIS CODE

            if (SceneManager.GetActiveScene().name != "level3")

In the previous code block, we have added four new lines of code that will do the following:

  • Cache a reference from our player_ship game object
  • Access the player_ship Rigidbody component and set isKinematic to true
  • Set the mobile bool static variable to false
  • Run Unity's CancelInvoke function to stop all invokes running in our scene (stops auto-fire)
  1. Save the ScenesManager script.

Now, we need to go into Input Manager and look at the Fire1 button. Here, the left mouse button is set to the Alt Positive Button property. To fix this in the Unity Editor, do the following:

  1. Go to Edit | Project Settings | Input Manager.
  2. Set Alt Positive Button to mouse 0.

Our game is now self-aware of what device it will run on, and if the device does run on a mobile Android device, the touch controls will be implemented.

Now, let's widen the support for our game and ensure our game covers various screen ratios and screen boundaries on either platform.

Extending screen ratio support

In this section, we are going to do two things. The first is to make it that no matter what aspect ratio our game is running at, our player will be able to fly around. The second is to make sure that the Text UI isn't affected by the different screen ratios.

So, let's start with our first task of making our game support multiple screen ratios during levels.

In the Project window, navigate to the Assets/Script folder and open the Player script. Then, follow these steps:

  1. At the top of the script, where the variables are, comment out the width and height floats; we are going to replace them:

        // float width;

        // float height;

  2. Add the following GameObject array to hold our new points:

    GameObject[] screenPoints = new GameObject[2];

The array we've just added will hold two points to represent our screen's boundaries.

  1. Next, in the Player script's Start function, we need to comment out the following:

      // height = 1/(Camera.main.WorldToViewportPoint(new

            Vector3(1,1,0)).y - .5f);

      // width = 1/(Camera.main.WorldToViewportPoint(new

            Vector3(1,1,0)).x - .5f);

      // movingScreen = width;

  2. Add the following method name:

    CalculateBoundaries();

The method we've just entered does not exist yet, so let's add this new method now.

  1. Still in the Player script, add the following method and its content to create our new screen's boundaries:

        void CalculateBoundaries()

        {

            screenPoints[0] = new GameObject("p1");

            screenPoints[1] = new GameObject("p2");

            Vector3 v1 = Camera.main.ViewportToWorldPoint  

                (new Vector3(0, 1, 300));

            Vector3 v2 = Camera.main.ViewportToWorldPoint             (new Vector3(1, 0, 300));

            screenPoints[0].transform.position = v1;

            screenPoints[1].transform.position = v2;

            screenPoints[0].transform.SetParent(this.    transform.parent);

            screenPoints[1].transform.SetParent(this.    transform.parent);

            movingScreen = screenPoints[1].transform.    position.x;

        }

So, let's go through the steps of the CalculateBoundaries method and see what it does to our game:

  1. First, it creates two new game objects and names them "p1" and "p2".
  2. We then make use of the ViewportToWorldPoint function, which will give us our game's world space positions for our screen's boundaries.
  3. Then, we apply our new Vector3 variables, v1 and v2, to our array of game object positions – that is, "p1" and "p2".
  4. Now that "p1" and "p2" represent the boundaries, we need to make them children of the Player script, which will update their Transform Position values.
  5. Finally, we update the movingScreen float value with our screenPoint value for when the game has a moving camera.

Continuing with the Player script, we now need to update the Movement method's directional conditions so that they support our new game boundaries.

  1. Scroll down to the Movement method and replace all four of the old if statements with the new ones:

    //OLD

    if (transform.localPosition.x < width + width/0.9f)

    //NEW

    if (transform.localPosition.x < (screenPoints[1].transform.localPosition.x - screenPoints[1].transform.localPosition.x/30f)+movingScreen)

    //OLD

    if (transform.localPosition.x > width + width/6)

    //NEW

    if (transform.localPosition.x > (screenPoints[0].transform.localPosition.x + screenPoints[0].transform.localPosition.x/30f)+movingScreen)

    //OLD

    if (transform.localPosition.y > -height/3f)

    //NEW

    if (transform.localPosition.y > (screenPoints[1].transform.localPosition.y - screenPoints[1].transform.localPosition.y/3f))

    //OLD

    if (transform.localPosition.y < height/2.5f)

    //NEW

    if (transform.localPosition.y < (screenPoints[0].transform.localPosition.y - screenPoints[0].transform.localPosition.y/5f))

Each of the new if statements in the previous lines of code will hold the same purpose of taking the value from the p1 or p2 game objects to get a restriction of the boundaries of the screen. This ensures that the player ship doesn't go too far out of view.

The following screenshot shows the level1 scene, with p1 and p2 representing the new gameplay boundaries in a different resolution from the usual 1,920 x 1,080 to show the flexibility that our gameplay boundary now has:

Figure 13.8 – Our new gameplay boundaries

Figure 13.8 – Our new gameplay boundaries

Lastly, we need to update our PlayerSpeedWithCamera method and set the movingScreen variable to zero if the game camera isn't moving to the right.

  1. Inside the Player script, go to the PlayersSpeedWithCamera method and add the following else condition:

        else

            {

                movingScreen = 0;

    }

  2. Save the Player script.

Now, let's move on and look at the second part of this fix. Here, even though the gameplay window now supports various aspect ratios, some images and text will struggle to look cosmetically pleasing. The following screenshots show what would happen to our game's pause screen if we changed the typical 1,920 x 1,080 resolution:

Figure 13.9 – Pause Screen difference in alternative ratios

Figure 13.9 – Pause Screen difference in alternative ratios

As you can see, the text and images lose their scale when they're in different aspect ratios. We can fix this by doing the following:

  1. In the Project window, navigate to the Assets/Scene folder and double-click the level1 scene.
  2. Select the Canvas game object in the Hierarchy window. Then, in the Inspector window, change UI Scale Mode in Canvas Scaler to Scale With Screen Size, as shown in the following screenshot:
Figure 13.10 – Updating the Canvas Scaler | Scale Mode

Figure 13.10 – Updating the Canvas Scaler | Scale Mode

  1. Change the Reference Resolution property to X: 1920 and Y: 1080.

Now, our Game window, when shown at various screen sizes, will look more in proportion.

Figure 13.11 – Our Pause Screen looks more uniform in the other ratios

Figure 13.11 – Our Pause Screen looks more uniform in the other ratios

  1. Save the level1 scene and update Canvas Scaler for all the scenes in the project.

With that, we've made our game more compatible in that it supports various aspect ratios for platforms other than a standard 1,920 x 1,080 resolution. Also, our game controls are self-aware of whether the game's being played on a PC or Android device. We also made use of the Touch struct to move our player around the scene.

In the next section, we are going to finalize our game for mobile before adding extra effects and general polish for the PC build.

Preparing to build Killer Wave for mobile

In this section, we will be finalizing our version of Killer Wave for Android. Before we build our game to Android, we need to apply some fixes that will only be necessary for the Android build.

The fixes we will be applying in this section are as follows:

  • Adjusting the lighting so that it suits our Android device
  • Making it that when pressing the pause button, our ship doesn't move to its location
  • Making it that our game stays in landscape mode
  • Stopping the screen from dimming when the device hasn't been touched for a while
  • Setting the game textures to a lower resolution
  • Adding a prefab explosion to enemies and players

After we've applied these minor fixes, we will build the game for our Android device.

So, let's get started with our first task by altering the lighting.

Setting up the lighting for Killer Waves for Android

Each scene that contains a 3D model will require lighting to be generated. The Unity Editor's lighting will differ from the lighting provided on an Android device.

With the current default lighting settings applied, the following screenshot shows the difference between both platforms. The image on the left was taken on a PC, while the one on the right was taken from a mobile device:

Figure 13.12 – The difference in lighting between platforms

Figure 13.12 – The difference in lighting between platforms

So, let's adjust the lighting so that both platforms have a similar level of brightness and contrast:

  1. At the top of the Unity Editor, go to Window | Lighting | Settings.
  2. Press the Environment button at the top of the Lighting window and apply the following values:
Figure 13.13 – The updated values for the "Lighting" windows properties

Figure 13.13 – The updated values for the "Lighting" windows properties

  1. Next click on the Scene tab. At the top of the window click on the New Lighting Settings button. Untick Realtime Global Illumination and Baked Global Illumination.

We will cover these two settings when we apply visual improvements, but for now, Realtime Global Illumination affects the indirect lighting that's applied to other objects to help create a more realistic, soft-colored light. Baked Global Illumination will have lights stuck on 3D assets to give the appearance of light shining on a surface, but the majority of our lights move, so this will not work as a baked light.

The following screenshots now show that the PC and mobile versions are starting to look similar:

Figure 13.14 – PC versus Mobile lighting now looks similar

Figure 13.14 – PC versus Mobile lighting now looks similar

  1. Now, we need to enable and adjust the emission of the following enemy materials in the Project window under Assets/Material:
    • basicEnemyShip_Inner: Emission ticked, Color: 993600 (Hex), and Intensity: 0.6
    • basicEnemyShip_Outer: Emission ticked, Color: 4C0000(Hex), and Intensity: 0.3
    • darkRed: Emission ticked, Color: 801616(Hex), and Intensity: 0.5

We explained how to change the emission of a material back in Chapter 2, Adding and Manipulating Objects. Changing these values will give us the following output:

Figure 13.15 – PC versus Mobile; both lighting and colors look near enough the same

Figure 13.15 – PC versus Mobile; both lighting and colors look near enough the same

Our game now looks nice and bright on either platform. Next, we'll fix the small issue with pausing the mobile version of the game.

Stopping involuntary player controls

When it comes to playing the game on a mobile device, we will want to press the pause button. But if and when we do, the game will also consider the press as a movement command, and the player's ship will move into the top-left corner where the press was made.

So, to fix this minor issue, we will apply an extra condition to our MobileControls method, as follows:

  1. In the Project window, navigate to the Assets/Script folder and open the Player script.
  2. Inside the Player script, scroll down to the MobileControls method and replace the current if statement condition with the following one:

    if (Input.touchCount > 0  &&

       EventSystem.current.currentSelectedGameObject == null)

The preceding code block will run a check to see whether a finger is touching the screen as before but will also check that there isn't a game object in the location when being pressed. If any of these conditions aren't met, then the player will not move.

  1. Finally, to import EventSystem, scroll to the top of the Player script and add the following namespace:

    using UnityEngine.EventSystems;

  2. Save the Player script.

In the next section, we will do some final texture optimizations and apply a ready-made and well-earned explosion prefab.

Final optimizations for Killer Wave

In this section, we will be adding some optimization to our mobile version of the game by reducing the size of the textures. We will also add explosions to our enemies and player.

Let's start by reducing our textures and compressing them.

Reducing texture sizes and compression

To reduce the size of the .apk file that gets installed on Android devices, as well as the overall performance increase, we can reduce the size of the textures of our game through Unity and also apply compression, which lowers the size even more.

The trick is to reduce the size of the texture but not too much; otherwise, the textures themselves will begin to blur and look cheap.

In this section, we will be reducing the texture sizes of the following:

  • PlayerShip and its extras (shop upgrades and thrusters)
  • The background wallpaper texture of the stars in our two levels
  • Shop button icons

Let's start by selecting and reducing the player ship's texture sizes and compressing them:

  1. In the Project window, navigate to the Assets/Texture folder.
  2. Select all of the following filenames:
    • playerShip_diff
    • playerShip_em
    • playerShip_met
    • playerShip_nrm
    • playerShip_oc
  3. All these files have a texture size of 512 x 512, so let's reduce them to 256 x 256, compress them, and turn off any filtering by setting them to the values shown in the following screenshot of the Inspector window:
Figure 13.16 – Reduce the texture size from 512 x 512 to 256 x 256

Figure 13.16 – Reduce the texture size from 512 x 512 to 256 x 256

  1. Do the same to the following textures, all of which can be in the same folder. However, this time, set the texture size from 1,024 x 1,024 all the way down to 64 x 64:
    • b. Shot_diff
    • b. Shot_nrm
    • c. Bomb_diff
    • c. Bomb_nrm

Continue doing this for the rest of the textures, and see what the results look like in the game by playing between the shop and level1 scenes. Do this at your own discretion.

Further Information

If you would like to know more about the textures that get imported into a project and how to adjust their quality levels, check out the following link: https://docs.unity3d.com/Manual/ImportingTextures.html.

Now, let's move on and add a ready-made particle explosion to each of our players and enemies by making some minor scripting tweaks.

Adding explosions to our players and enemies

The time has come to add a prefab explosion to our game objects to represent their destruction and their general effect on the boss when they are being shot at. We covered particle systems back in Chapter 4, Applying Art, Animation, and Particles. Here, we will apply some scripting so that when a Die method is called, we will instantiate our explode prefab.

To instantiate the explode prefab when an enemy dies, we need to do the following:

  1. In the Project window, navigate to the Assets/Script folder and open the EnemyWave script.
  2. Inside the Die method, replace its content with the following to instantiate the explode game object:

    GameObject explode =

       GameObject.Instantiate(Resources.Load("explode"))

           as GameObject;

    explode.transform.position = this.gameObject.transform.position;

    Destroy(this.gameObject);

In the previous code block, we added two extra lines above the current Destroy function. We covered this in detail in Chapter 2, Adding and Manipulating Objects. The two extra lines do the following:

  • When the Die method runs, it will create the explode prefab from Assets/Prefab.
  • The position of the explode instance is updated with the same location as the enemies.
  1. Save the EnemyWave script and repeat this process for the EnemyFlee and BossScript scripts.

Finally, for our Player, we will add something similar but also add a delay for when player_ship gets destroyed so that we can see the explosion before we reload the scene again.

  1. Still in the same Project window, open the Player script, scroll down to the Die method, and replace its content with the following:

        GameObject explode =

          GameObject.Instantiate(Resources.Load("Prefab/explode"))

            as GameObject;

        explode.transform.position = this.gameObject.transform.position;

        GameManager.Instance.LifeLost();

        Destroy(this.gameObject);

In the previous code, we have updated the player's Die method so that it creates a prefab explosion and houses its position where the player's position is.

However, we need to add a delay in the GameManager script where the previous code block was introduced.

  1. Save the Player script before continuing with the GameManager script.
  2. Open the GameManager script so that you can add a delay to the scene when it's updated.
  3. In the GameManager script, scroll down to the LifeLost method, select its content, Cut it (cut, not Delete, as we are going to paste it somewhere else), and replace the LifeLost method with the following code:

    StartCoroutine(DelayedLifeLost());

Here, we are delaying the content from our LifeLost method. However, here, we will be using StartCoroutine to create the delay, as shown in the previous line of code.

  1. Next, we will paste the content from the original LifeLost method inside the following code block:

      IEnumerator DelayedLifeLost()

      {

        yield return new WaitForSeconds(2);

    // PASTE LIFELOST CONTENT HERE

      }

In the preceding code block, we have added IEnumerator. This will be executed from StartCoroutine, along with a 2-second wait. If your IEnumerator has an error underlined in the IDE. Add the library using System.Collections; at the top of the script.

Paste in the LifeLost content we cut earlier and then save the GameManager script.

The following screenshot shows our game object with particle explosions applied:

Figure 13.17 – Particle Effects

Figure 13.17 – Particle Effects

Now, the time has come to create a build of our Android platform.

Setting up the build settings for Android

In this section, we are going to set up our Player Settings and build our Unity Project for an Android device. For testing purposes, I will be using a fairly old tablet and a recent phone to see whether there are any differences in terms of the setup between the two devices.

Before setting up our Player Settings, ensure you have copies of the Java Development Kit and Android SDK installed. To check this, do the following:

  1. At the top of the Unity Editor, go to Edit | Preferences.
  2. Then, click on External Tools in the Unity Preferences window.
  3. The following screenshot shows these two development kits, along with Download buttons for them. If you don't have either, these can be installed via the Unity Hub, which we covered in Chapter 1, Setting Up and Structuring Our Project.
Figure 13.18 – Both Development Kits are installed

Figure 13.18 – Both Development Kits are installed

Further Information

If you require any more specific information about the development kit installation process, check out the following link: https://docs.unity3d.com/Manual/Preferences.html.

Now, let's continue to Player Settings and set up our game:

  1. At the top of the Unity Editor, go to File | Build Settings….
  2. Make sure you have all of the scenes set up in Scenes In Build.
  3. Select Android from the Platform list and click Switch Platform.
Figure 13.19 – In Build Settings, select "Android" and then "Switch Platform"

Figure 13.19 – In Build Settings, select "Android" and then "Switch Platform"

  1. Click Player Settings... to move on to the next stage of setting up for Android.
  2. In the Inspector window, at the top of the window, update the Company Name and Product Name fields to whatever you wish.
  3. Select the Resolution and Presentation tab and untick Portrait and Portrait Upside Down.
  4. Select the Other Settings tab.
  5. Scroll down to the Identification section. In the following screenshot, you will see the Package Name field is filled out with our company name and product name (com.Packt.KillerWave):
Figure 13.20 – Adding our package name in the 'Identification' section (Player Settings)

Figure 13.20 – Adding our package name in the 'Identification' section (Player Settings)

  1. Also, set Minimum API Level to 23 or above if your device can handle it. If it can't, when we go to build, you will receive an error in the Console window regarding changing the Minimum API Level value.
  2. Go back to the Build Settings window and click the Build button.
  3. You will be asked to give apk a name and location. Pick wherever and whatever you want to name the file and click Save.

    Tips

    If you get a Gradle build failed error, try changing Build System in the Build Settings window to Internal.

  4. Finally, ensure you have your Android device in USB debugging mode and copy apk over to the device.
  5. Go to the location where apk has been copied on the device and select it to install and run it.

    Tip

    When testing the game on an Android device, you may find it distracting that your device's brightness dims when the screen isn't being touched.

    We can fix this by adding the following code, ideally in the Awake function of the GameManager script, as this relates to the game's overall interaction:

    #if UNITY_ANDROID

    Screen.sleepTimeout = SleepTimeout.NeverSleep;

    #endif

This brings us to the end of building our game for mobile. In this section, we covered setting up our lighting settings so that they matched what we were seeing in the Unity Editor. After that, we cleared up some small fixes so that we wouldn't unintentionally move the player ship to where the pause button is when we press it on our device. We also reduced the size of our apk by reducing the size of the textures for our game. This also helps with the performance of Android devices when they're playing our game. Then, we added our explode prefab and made some fixes to our script to instantiate our explosions in the right place at the right time.

Finally, we went through the procedure of setting up our Unity build file and copied it over to the Android device so that it can be installed and run.

Congratulations if you have made it this far, built the game, and everything works as expected! If not, or you met some issues along the way, don't worry – other Unity users will have had similar problems, and the solutions to them aren't too hard to find with some Googling. Now, we will start bug-testing our game.

Figure 13.21 – Killer Wave running on an old tablet

Figure 13.21 – Killer Wave running on an old tablet

In the next section, we'll apply polish and shine to our PC version.

Applying PC visual improvements

In this section, we are going to focus on the PC version, where we will have more leg room to apply effects, as it's likely the PC playing this game will be more powerful than a mobile device.

We will cover things such as post-processing, where we can create pretty effects to make our game shine even more. We can do this by applying effects such as blur motion, blurring to the edges of the screen, bending the screen to give it a dome screen effect, and altering the coloring.

We'll also be taking a look at lighting and reflections so that we have a slightly modified shop scene that will hold multiple lights and make the game stand out more. In the level3 scene, we will be adding reflective assets to show off the use of these reflection probes on our art assets.

Let's start by discussing post-processing.

Post-processing

In this section, we will be installing and applying post-processing effects to our game. This will provide us with effects that are used in films, such as film grain, chromatic abbreviation, color grading, and lens distortion. Let's make a start by installing this package into our project.

Installing post-processing

Post Processing is installed via the Package Manager directly into our project. In the previous chapter, we installed Default Playables in a similar way. This time, we won't be going to the Asset Store; we can download and install Post Processing from Packages: Unity Registry.

The following steps will take you through the process of installing Post Processing in the project:

  1. In the Unity Editor at the top, click Window | Package Manager.
  2. At the top-left corner of the Package Manager window, change its dropdown to Packages: Unity Registry.
  3. A long list of packages will be displayed; from the list, either scroll down and select Post Processing or select the search bar at the top-right corner and type Post Processing into it.
  4. Finally, click Install at the bottom-right corner.
  5. The following screenshot shows Package Manager with Post Processing selected:
Figure 13.22 – The Package Manager with Post Processing selected to install

Figure 13.22 – The Package Manager with Post Processing selected to install

  1. At the top of the Unity Editor, go to File | Build Settings....
  2. Select PC, Mac & Linux Standalone, followed by Switch Platform.

Our Unity project now has post-processing installed. With that, we can begin preparing some scenes for our standalone game.

Preparing and applying post-processing to our title and level scenes

In this section, we are going to make some changes to our title scene so that it supports our image and text being affected by post-processing. By the end of this section, our title scene will look more impressive, as shown in the following screenshots:

Figure 13.23 – Difference between post-processing and not

Figure 13.23 – Difference between post-processing and not

To apply post-processing to our title scene, we need to do the following:

  1. In the Project window, navigate to Assets/Scene and open title.

We now need to change some property values in the Canvas game object so that the post-processing changes come from the camera's feed, not just the Canvas itself.

  1. In the Hierarchy window, select the Canvas game object.
  2. In the Inspector window, change the Canvas component property's Render Mode option to Screen Space - Camera.
  3. Drag Main Camera from the Hierarchy window into the Render Camera property field.

Next, we will add two post-processing components to our Main Camera game object.

  1. Select Main Camera in the Hierarchy window.
  2. Click the Add Component button in the Inspector window.
  3. Type Post Process Layer into the drop-down list. When you see its name in the list, select it.
  4. In the Post Process Layer component, change the Layer property value to Everything. This means it will affect all the layers in the scene. This normally isn't recommended, but because there isn't very much in our scene, there isn't a lot to affect.

    Tip

    If you want to change the Post Processing Layer component from Everything to something else, you will need to create a new layer at the top-right of the Inspector window, as we did in Chapter 2, Adding and Manipulating Objects. Give it a name such as PostProcessing and change Everything to PostProcessing to remove the warning message in the Post Processing Layer component.

  5. Click the Add Component button again and type Post Process Volume until you see it on the list. Then, select it.
  6. At the top of the Post Process Volume component, tick the Is Global box.
  7. In the Project window, drag and drop the TEXT asset from the Assets/Scene folder into the Profile parameter in the Inspector window.
  8. The Game window will have the Profile post-processing effect applied to it, which may or may not be too extreme for you. We can set Weight from 1 all the way down to 0. I'm setting mine to 0.6.

The following screenshot shows our title scene Game window, along with the two Post Process Layer and Post Process Volume components and the highlighted areas mentioned in the previous steps for reference:

Figure 13.24 – Post Processing components (on the Main Camera game object) with the property values changed

Figure 13.24 – Post Processing components (on the Main Camera game object) with the property values changed

  1. Save the scene.
  2. Repeat steps 2–12 for the shop scene, but instead of applying the TEXT post-processing profile, use SHOP instead. The following screenshot shows the final result this has on the shop scene before and after post-processing has been applied (with the Weight property set to 1), also if your camera background isn't set to black. Change it to black now.:
Figure 13.25 – Post-processing effects applied and not applied to our shop scene

Figure 13.25 – Post-processing effects applied and not applied to our shop scene

  1. Now, repeat steps 2–13 for the gameOver scene. The end result should look similar to the following:
Figure 13.26 – The Game Over screen with Post Processing Effects applied

Figure 13.26 – The Game Over screen with Post Processing Effects applied

  1. Repeat steps 5–13, but instead of applying the TEXT post-processing profile, add the DEFAULT post-processing profile.

The following image shows an example of the level3 scene with and without the DEFAULT post-processing profile applied:

Figure 13.27 – Game screens with no post-processing applied and post-processing applied

Figure 13.27 – Game screens with no post-processing applied and post-processing applied

That's all of the scenes we need to implement for a post-processing profile. In the next section, we will briefly go through each of the effects that we have and can apply.

Post-processing effects (overrides)

In this section, we are briefly going to discuss the effects the post-processing package offers us. By the end of this section, you will be more familiar with the effects and be able to make your own post-processing profile.

Now that we've seen what post-processing does to our game, we can talk about each of the effects. Let's start by loading up the title scene and altering what we have:

  1. In the Project window, navigate to the Assets/Scene folder and load up the title scene.
  2. Select Main Camera in the Hierarchy window.

Our main focus for this section will be the Overrides section in the Post-process Volume component:

Figure 13.28 – The 'Bloom', 'Chromatic Aberration', and 'Color Grading' locations in the Post Process Volume Component

Figure 13.28 – The 'Bloom', 'Chromatic Aberration', and 'Color Grading' locations in the Post Process Volume Component

So, let's go through some of these Overrides for Post Process Volume in the Inspector window. Then, I will provide a link that I encourage you to explore so that you can play around with some of the values.

Bloom

This effect creates fringes of light extending from the borders of bright areas in an image.

We can extend the content by selecting the arrow to the left of the Bloom tick box (at the top-left corner in the following screenshot):

Figure 13.29 – Setting the Bloom property values

Figure 13.29 – Setting the Bloom property values

In the preceding screenshot, we have turned all of the properties on. Simply deselect and select each property to see what influences (if any) are made to each of the properties. Also, try and change some of the values. Use the preceding screenshot as a fallback if you feel you have gone too far with the effect.

An interesting property to take a look at here is the Threshold property, where, if we lower its value to under 1.14, the bloom effect will increase. However, if we make the value too low, we can overcook it and destroy the look of our game, as shown in the following:

Figure 13.30 – The 'Threshold' property levels

Figure 13.30 – The 'Threshold' property levels

Hopefully, I have made you curious enough to continue playing and experimenting with the bloom effect.

Further Information

More information about the Bloom effect can be found at https://docs.unity3d.com/Packages/[email protected]/manual/Bloom.html.

Next, we'll look at Chromatic Aberration.

Chromatic Aberration

This effect mimics what a real-world camera produces when its lens fails to join all the colors at the same point.

The following screenshot shows our current settings:

Figure 13.31 – Setting the Chromatic Aberration property values

Figure 13.31 – Setting the Chromatic Aberration property values

This effect is more noticeable around the edges of the Game window. As an example, in the following screenshots, I have moved the image and its text up so that we can see these two components begin to warp more obviously:

Figure 13.32 – 'Chromatic Aberration' – off versus on

Figure 13.32 – 'Chromatic Aberration' – off versus on

Further Information

More information about the Chromatic Aberration effect can be found at https://docs.unity3d.com/Packages/[email protected]/manual/Chromatic-Aberration.html.

Next, we'll look at the final effect we applied to our title scene – Color Grading.

Color Grading

This effect alters the color and luminance of the final image that Unity produces. Color Grading has the biggest range of properties throughout all of the post-processing effects. I've split these properties up into bulleted segments:

  • Mode:
Figure 13.33 – Setting the 'Color Grading' override values

Figure 13.33 – Setting the 'Color Grading' override values

Here, we have a choice of three-color grading modes so that we can alter the camera's final image. In the preceding screenshot, Unity gave us a warning regarding changing ColorSpace from Gamma to Linear. If you want to do this, it can be changed in Edit | Project Settings | Player | Player Settings | Other Settings.

  • Tonemapping:
Figure 13.34 – Tonemapping

Figure 13.34 – Tonemapping

This hosts a selection of tonemapping algorithms that we can use at the end of the color grading process.

  • White Balance:
Figure 13.35 – White Balance

Figure 13.35 – White Balance

This alters the temperature and tint of the final picture.

  • Tone:
Figure 13.36 – Tone

Figure 13.36 – Tone

Here, you can adjust the Saturation, Contrast, Hue Shift, Color filter, and Post-exposure (EV) options, which, similar to the Bloom effect's Threshold property, can easily be overcooked and provide some powerfully bright or dark results.

  • Channel Mixer:
Figure 13.37 – Channel Mixer

Figure 13.37 – Channel Mixer

This changes each overall image's RGB channel.

  • Trackballs:
Figure 13.38 – Trackballs

Figure 13.38 – Trackballs

Here, the three trackballs (Lift adjusts dark tones, Gamma adjusts mid-tones, and Gain adjusts highlights) affect the overall hue of the final image.

  • Grading Curves:
Figure 13.39 – Grading Curves

Figure 13.39 – Grading Curves

Grading Curves is an advanced way to adjust specific ranges in hue, saturation, or luminosity in the final image.

Further Information

More information about the Color Grading effect can be found at https://docs.unity3d.com/Packages/[email protected]/manual/Color-Grading.html.

That concludes our look at all three of the post-processing overrides for the title scene. If you would like to know more about the rest of the effects that are available, check out the following link, where you can read up on the other 11 effects that can be applied to a Unity scene: https://docs.unity3d.com/Packages/[email protected]/manual/index.html.

Anti-aliasing modes

In this section, we are going to view the different types of anti-aliasing in the Post Process Layer component. As you may know, anti-aliasing smooths the rough edges of game objects in our game to get rid of staircase effects. Unity offers three different algorithms that smooth edges.

The following modes are offered:

  • Fast Approximate Anti-Aliasing (FXAA): This is typically used with mobile platforms due to its quick algorithm. It is the most efficient technique but doesn't support motion vectors.
  • Subpixel Morphological Anti-Aliasing (SMAA): This is high-quality but is more demanding in terms of system performance.
  • Temporal Anti-Aliasing (TAA): An advanced, high-demanding technique that uses motion vectors (a motion vector is a key element in the motion estimation process).

The following screenshots show the player's ship with different anti-aliasing techniques applied to it:

Figure 13.40 – Visual differences with anti-aliasing modes

Figure 13.40 – Visual differences with anti-aliasing modes

As you can see, the purpose of anti-aliasing is to take off jagged edges, but with our game, these edges aren't as noticeable, since it's full of dark backgrounds.

Further Information

If you would like to apply anti-aliasing and want to find out more, check out the following link: https://docs.unity3d.com/Manual/PostProcessing-Antialiasing.html.

Next, we'll look at creating and applying our own post-processing profiles, which we created at the start of the Applying PC visual improvements section.

Creating and applying post-processing profiles

In the final section on post-processing, we will discuss creating a post-processing profile. From there, you can (if you want to – I encourage you to) create your own profile and apply it to the Post Process Volume component in the Inspector window. Finally, you will be able to add/remove your own effects to alter the final look of the standalone game.

So, to create and add our own effects, I suggest that we go back to a scene that we have already prepared – the title scene:

  1. In the Project window, navigate back to Assets/Scene and open the title scene.
  2. Select the Main Camera game object in the Hierarchy window.
  3. Press the New button inside the Post Process Volume component (as shown in the following screenshot):
Figure 13.41 – Creating a new post-processing profile

Figure 13.41 – Creating a new post-processing profile

  1. To add your own post-processing effects, click the Add effect... button (as shown in the preceding screenshot) at the bottom of the Post Process Volume component and select an effect from the drop-down list.
  2. Once you have applied the effect, click All to turn all the properties on (as shown in the following screenshot):
Figure 13.42 – Turning all the properties on

Figure 13.42 – Turning all the properties on

  1. If you want to remove the effect, click in the top-right corner of the effect (above the Off button) and select Remove from the drop-down list (as shown in the preceding screenshot).
  2. It's as simple as that! If you want to see where the file is located, click on the PostProcessProfile field, as shown in the following screenshot:
Figure 13.43 – Applying and locating the post-processing profile

Figure 13.43 – Applying and locating the post-processing profile

  1. The location will ping yellow in the Project window (as shown in the preceding screenshot), which is also where you can rename the file to something that resembles the use of the profile (right-click the file and select Rename from the dropdown).
  2. If you don't like what you've created, you can delete the PostProcessProfile file from the Project window and click the small remote button to the right of the Profile parameter in Post Process Volume to add the TEXT profile once more (or whichever profile you want).

This was an extensive overview of the post-processing package that Unity has to offer. In this section, we imported our Unity package and added post-processing components to each of our game scenes. From there, we applied ready-made profiles to customize the scenes' post-processing effects. We then lightly reviewed some of the effects that can be added to the Post Process Volume component, which was already in our scenes.

We ended this section by altering our scene's anti-aliasing properties. With this, we took the rough edges off our art assets.

I encourage you to make your own profiles, but if you feel like you need more profiles to play around with, you can purchase a compilation of profiles from the Asset Store for a small price.

In the next section, we are going to take a look at the lighting settings and apply some global illumination, lighting, and fog to our shop scene.

Adding global illumination and other settings

In this section, we are going to give our shop scene a background by adding art assets from the level3 scene and adding a red emission material.

Unity is currently working on a new global illumination lighting package, which means this version we are using will be eventually phased out. The good news is that it will be supported during 2020 LTS.

We will activate the scene's real-time global illumination, which is where the red emission material will glow on the surface of the corridor. We will also be adding extra lights to our shop display and the player ship to make it stand out more. Finally, we will add some black fog to create some darkness creeping around the glowing lights.

The following screenshots show a comparison between the shop scene before and after we complete this section:

Figure 13.44 – Global illumination/Lighting/Fog – off versus on

Figure 13.44 – Global illumination/Lighting/Fog – off versus on

So, let's start this section off by adding the art assets that we are going to use for the shop scene.

Adding art assets to our shop scene

In this section, we are going to drag and drop some pre-made art assets into our shop scene. From there, we can continue setting up our Lighting settings.

To apply the art assets to our shop scene, we need to do the following:

  1. First, load up the shop scene itself from the Project window by going to Assets/Scene. Then, double-click the shop scene.
  2. In the Project settings, navigate to the Assets/Prefab folder.
  3. Drag and drop the Environment prefab into the Hierarchy window.

The scene, when viewed from the Game window, will look as follows:

Figure 13.45 – Current look of our shop scene

Figure 13.45 – Current look of our shop scene

The art assets that we have brought into the shop scene should be marked as static. Specifically, it's Contribute GI that needs to be marked so that we can generate the lights we need from our red emission strips, as shown in the preceding screenshot.

  1. The following screenshot shows the Inspector window with the Environment game object (and all its children) marked as Static:
Figure 13.46 – The 'Environment' game object and its children marked as static

Figure 13.46 – The 'Environment' game object and its children marked as static

Further Information

If we did have moving game objects in the scene that we wanted to be affected by the lighting of the scene, we would need to add Light Probes to update any indirect colors on that moving game object.

If you would like to know more about Light Probes, check out https://docs.unity3d.com/Manual/LightProbes.html.

Now, we need to disable any kind of light we currently have in our scene so that we don't dilute the effect we are trying to achieve:

  1. If the Hierarchy window contains Directional Light, select it and press delete on your keyboard.

Now, we can set up our Lighting settings so that they support Realtime Global Illumination. To do that, we need to access our Lighting window and enter some values.

  1. If the Lighting window hasn't loaded, in the Unity Editor, at the top of the screen, select Window | Rendering | Lighting.
  2. Select the Scene button in the Lighting window. Now, let's start turning off all Environment lights. Set your Environment settings to the ones shown in the following screenshot:
Figure 13.47 – The 'Lighting' window and its updated property values in the 'Scene' tab

Figure 13.47 – The 'Lighting' window and its updated property values in the 'Scene' tab

  1. As shown in the preceding screenshot, we have knocked out any kind of light that our scene might have had. Now, we can go back to the Scene tab and turn Realtime Global Illumination on, which is just below the Environment segment of the Lighting window. If all settings are grayed out, we need to create a New Lighting Settings at the top-right of the Scene tab.
Figure 13.48 – Tick 'Realtime Global Illumination'

Figure 13.48 – Tick 'Realtime Global Illumination'

  1. Make sure Baked Global Illumination is unticked, as we don't want our lights to be computed at runtime. This is because it uses up RAM and HDD/SSD space.

Still inside the Lighting window's settings, we can lower some of the Lightmapping Settings values so that the map isn't as detailed and is also quicker to generate light on slower systems.

  1. Leave Lightmapping Settings at its default values, as shown in the following screenshot:
Figure 13.49 – Update the 'Lightmapping Settings' property values to the ones shown here

Figure 13.49 – Update the 'Lightmapping Settings' property values to the ones shown here

  1. At the bottom of the Lighting window, make sure Auto Generate is unticked and click the Generate Lighting button.
  2. Wait for the blue bar at the bottom-right corner of the Unity Editor to complete and disappear.

We will be presented with the following output in the Game window:

Figure 13.50 – Our 'Game' window shows our shop scene is washed out in a strong light

Figure 13.50 – Our 'Game' window shows our shop scene is washed out in a strong light

Further Information

We can (if we want to) check the indirect lighting that we have created from our current Lighting settings by selecting the Shaded button below the Scene tab and selecting Indirect from the dropdown (don't forget to change it back to Shaded once you're done).

Our shop scene looks overly bright red and has drowned the scene out. However, we nearly have what we want. Now, we can turn on some fog from the Lighting window to create a dark alley with the red emission bleeding through.

  1. To add fog to the shop scene, in our Lighting window, near the bottom, we need to apply the following values:
Figure 13.51 – The 'Fog' settings property values

Figure 13.51 – The 'Fog' settings property values

Our Game window will now have faded darkness in the background of our shop scene, as shown in the following screenshot:

Figure 13.52 – The 'Game' window with a black fog background

Figure 13.52 – The 'Game' window with a black fog background

  1. The final touch is to drag and drop the shopLights prefab from Assets/Prefab into the Hierarchy window to light up the player ship:
Figure 13.53 – Small light added to the player ship

Figure 13.53 – Small light added to the player ship

  1. Save the shop scene.

With that, we have successfully removed the default lighting from our shop scene and applied Realtime Global Illumination from the emission material and added darkness (fog) to our shop scene's background.

In the next section, we will be discussing and implementing a small section of our level3 scene so that we can start adding art assets with reflections.

Reflection probe

In this section, we are going to introduce the final art asset for our game. This asset will reflect the environment in the scene, as shown by the two-sphere statues in the following screenshot:

Figure 13.54 – Reflective orbs in the background

Figure 13.54 – Reflective orbs in the background

You can imagine how useful it would be to have a material that reflects its surroundings like a mirror. We are going to add the shinySphere art asset to our level3 scene and calibrate its property values to get a decent result without affecting our system's resources.

So, let's start by loading up the level3 scene:

  1. In the Project window, navigate to the Assets/Scene folder and double-click on the level3 scene.

Now, we are going to place our shinySphere asset in the scene.

  1. In the Project window, navigate to the Assets/Prefab folder.
  2. Drag shinySphere into the Hierarchy window.
  3. Select the shinySphere asset in the Hierarchy window and make sure that its Transform values are set as shown in the following screenshot:
Figure 13.55 – The 'shinySphere' Transform property values

Figure 13.55 – The 'shinySphere' Transform property values

The shinySphere game object should now be in a location next to the cargo blocks at the end of the level, as shown in the following screenshot:

Figure 13.56 – The placement of the 'shinySphere' game object

Figure 13.56 – The placement of the 'shinySphere' game object

Before we add the second shinySphere game object, let's add a Reflection Probe component to this game object, as follows:

  1. In the Hierarchy window, expand the shinySphere game object and select the spheres child game object.
  2. Right-click the spheres game object in the Hierarchy window and select Light | Reflection Probe.
  3. The spheres game object now has a child game object called Reflection Probe. Select this game object.
  4. In the Inspector window, we have the Reflection Probe component, along with its values. First, let's change the Type values to the ones shown in the following screenshot to make our game object reflect its environment:
Figure 13.57 – The 'Type' values updated to the ones shown here to create a reflection

Figure 13.57 – The 'Type' values updated to the ones shown here to create a reflection

Our shinySphere game object will now update its reflection on every frame.

  1. Next, we will alter the Runtime settings values to increase the accuracy of the reflection. If the Box Projection is grayed out, switch from Android to PC, Mac & Linux Standalone build in Build Settings. Use the values shown in the following screenshot:
Figure 13.58 – Increasing the accuracy reflection in 'Runtime Settings'

Figure 13.58 – Increasing the accuracy reflection in 'Runtime Settings'

Further Information

Box Projection will help improve the accuracy of the reflections given in the environment. If you would like to know more, check out the following link: https://docs.unity3d.com/Manual/AdvancedRefProbe.html.

  1. The last property values to update can be found in Cubemap capture settings. Changing these values will change the final look of the reflections (simply estimate what color the Background property should be so that it suits your scene):
Figure 13.59 – The 'Cubemap capture settings' property values updated to the ones shown here

Figure 13.59 – The 'Cubemap capture settings' property values updated to the ones shown here

The reflection probe can create performance issues if it's not used carefully, depending on the platform the game is being pointed toward. For example, with the previous settings, a higher resolution will show a clearer reflection but will obviously require more resources.

Further Information

For more information about reflection probes and their performance, check out the following link: https://docs.unity3d.com/Manual/RefProbePerformance.html.

To duplicate the shinySphere game object in our level3 scene, we need to do the following:

  1. Select the shinySphere game object in the Hierarchy window and click Overrides | Apply All at the top-right corner of the Inspector window to update the prefab.
  2. To copy and paste the shinySphere game object, right-click shinySphere in the Hierarchy window and select Copy from the drop-down list.
  3. Right-click in the Hierarchy window (in an open space, near the bottom) and select Paste from the drop-down list.
  4. Finally, move the shinySphere game object to the right of the x axis.
  5. Save the scene.

The following screenshot shows the two shinySphere game objects reflecting the environment:

Figure 13.60 – Both 'shinySphere' game objects with reflections

Figure 13.60 – Both 'shinySphere' game objects with reflections

If, in any other future Unity Projects, you are required to create a shiny surface, marble floor, a brand-new shiny car, and so on, making use of a reflection probe would cover these requirements.

With that, we have reached the point where our game is complete, and we've covered everything specified in the Game Design Document. Now would be a good time to build our standalone version of the game and see how well it runs. Are there any bugs? How are we going to test our game? Let's move on and see how we can tackle such issues.

Building and testing our game

We have reached the point where we can build and run our game instead of just testing our game's scenes in the Unity Editor. This section will be about not only building the game, as we did earlier for the Android version of the game, but also to see whether we have any bugs with our final build. We will also look for any potential issues along the way by using performance spikes in the profiler.

Let's start building our game and see how well it runs before we do any tests.

To build our game for a PC, we need to do the following:

  1. At the top of the Unity Editor, go to File | Build Settings...
  2. Make sure all the scenes are in the Scenes In Build list and in the correct order.
  3. Platform should be set to PC, Mac & Linux Standalone. If not, select it and select the Switch Platform button.

Next, we need to add the aspect ratios that this game is intended for in the Player Settings... window:

  1. Select the Player tab.
  2. In the Inspector window, expand the Resolution and Presentation content.
  3. Expand the Supported Aspect Ratios content.

Deselect the aspect ratios shown in the following screenshot:

Figure 13.61 – Select the 16:10 and 16:9 aspect ratios (typical widescreen ratios)

Figure 13.61 – Select the 16:10 and 16:9 aspect ratios (typical widescreen ratios)

  1. Back in the Build Settings window, press the Build button.

The following screenshot shows these references highlighted:

Figure 13.62 – All game scenes added and in order (Scenes In Build), 'PC, Mac & Linux Standalone' selected in the 'Platform' settings, and 'Build' clicked

Figure 13.62 – All game scenes added and in order (Scenes In Build), 'PC, Mac & Linux Standalone' selected in the 'Platform' settings, and 'Build' clicked

  1. In the Windows Explorer window that appears, select a location where you wish to install the game and click the Save button.
  2. Once the game has been built, run its .exe file.

Now, let's fix any potential issues that may arise in our game.

Tackling bugs

Imagine we have sent our game off to be bug-tested and get a response from several bug testers questioning bugs, the game's UI, and the performance of the game.

The following sections contain four reports that I want you to read and think about. We will go through the answers near the end of this chapter.

Let's start with the first bug report.

Bug report – Standalone AD button

It has been reported that when our bug tester plays the PC version of the game, they can't watch an advert in the shop scene.

How can we resolve this issue?

The following screenshot shows the AD button in the shop scene:

Figure 13.63 – The AD and Start buttons from the shop scene

Figure 13.63 – The AD and Start buttons from the shop scene

Hint: Do we need the AD button in the standalone version of the shop scene? Is it supported by Unity?

Bug report – Resetting the player's lives

A second report has been given to us, suggesting that when the game is completed, the player's lives don't reset.

Why is this happening and how do we fix this issue?

The following screenshot shows the player's lives counter on level 1:

Figure 13.64 – Player's Lives

Figure 13.64 – Player's Lives

Hint: Does this happen when you quit the game through the pause screen? Do the player's lives reset when all their lives are lost?

Bug report – Slower systems on level 3

When the Android version is played on slower systems, it has been reported that level 3 runs slower than levels 1 and 2.

What amendments can be made, if any, to fix this problem?

The following screenshot shows where the game slows down:

Figure 13.65 – Halfway through Level 3

Figure 13.65 – Halfway through Level 3

Hint: What changes can be made that won't upset standalone or more powerful performing Android devices?

Bug report – Sometimes, the game ends too quickly

Some bug testers have reported that, when starting a game, it ends earlier than intended, with the player ship animating out of the screen.

Why is this happening and how can this be amended?

The following screenshot shows the tail end of the player ship's thrusters as it leaves the level too soon:

Figure 13.66 – Player has left too early

Figure 13.66 – Player has left too early

Hint: Which level does this happen on? Does it happen in the Unity Editor? Does it happen all the time? If not, what are you doing and what's different?

You may be able to solve some of these questions by Googling key problems. Others are more specific, and you may need to add Debug.Log() to parts of your code holding variable names so that you can see what's changed after a certain point in the game. For example, does GameManager.playerLives debug a different value than it should at certain points in the game? If you're using Microsoft Visual Studio as your IDE, you may want to start adding breakpoints and step through your code to see what changes. If you don't know what breakpoints are, I suggest that you check out the following link: https://docs.microsoft.com/en-us/visualstudio/debugger/using-breakpoints?view=vs-2019.

To potentially help with these performance issues, we are going to check out the Profiler tool and see how it can help us with checking the performance of our game.

Understanding the Profiler tools

In this section, we will be checking out one of the Unity Editor's tools – Profiler. This handy tool will show us where our game may spike in demands for system resources and/or show where our game is using too many resources at once.

Let's open the Profiler window and see its default layout before going into any more detail about it:

  1. At the top of the Unity Editor, select Window | Profiler.

The Profiler window behaves like any other new window in Unity. Typically, Profiler should run well in fullscreen mode on a second screen. Otherwise, dock Profiler down with Console, as shown in the following screenshot:

Figure 13.67 – The 'Profiler' window

Figure 13.67 – The 'Profiler' window

  1. At the top of the Unity Editor, press the Play button. After about 5 seconds (roughly), press the Pause button (it doesn't matter which scene is running).

The Profiler window will come alive, showing a graph and a table of information. This will be split into four sections, as shown in the following screenshot:

Figure 13.68 – Sections of the 'Profiler' window

Figure 13.68 – Sections of the 'Profiler' window

Let's take a look at these sections in more depth:

  1. Profiler Modules – A breakdown of modules that give measurements for each property that can be added.
Figure 13.69 – Profiler Modules

Figure 13.69 – Profiler Modules

  1. Profiler Controls – Navigation of controls to move through frames.
  2. Frame Chart – In this section, we can click and scrub (drag) the mouse to see an indicator on the area. The Module Details Panel will list an update on what resources are being used during play mode (depending on which module is selected).
  3. Module Details Panel – Selecting each profiler module will give further details in the module details panel. For example, if CPU Usage is selected, there will be an "Overview" with an individual breakdown of which resources are used the most. If GPU Usage is selected, we are given two different types of Hierarchy panels (Hierarchy and Hierarchy Raw). We'll explain more about a scenario using the profiler and the module details panel next.

Let's take a further look at the profiler and how to diagnose a performance spike.

The following screenshot shows a highlighted spike (denoted by i), along with the indicator. We can uncheck each of the properties within the "GPU Usage" module (denoted by ii) to see what is causing the spike in the Frame Chart. Also, update the Module Details Panel (denoted by iii) list to show what's causing the performance spike.

 

Figure 13.70 – 'Profiler' showing signs of a performance spike while the game is running

Figure 13.70 – 'Profiler' showing signs of a performance spike while the game is running

In the Module Details Panel window (the "Hierarchy" section), at the top of the list, we have the culprit of what's causing the spike, UpdateDepthTexture.

With a quick Google search, we can see why this is happening and whether there is anything we can do to fix the issue. According to a topic on the Unity forums, this issue is caused by the profiler itself, which is fine, as we won't be requiring the profiler in the final build. Try to reproduce spikes, cross-compare, and check more than one answer to verify as much as possible that your spike relates. It's likely you will find a way to minimize/remove the issue.

Another way of checking this, and one that will possibly solve the issue, is to run our game outside of the Unity Editor to remove any resources being used up. One way of tackling this is to build and run (denoted by iii) our game as a standalone (denoted by i) Development Build and auto-connect it to the Profiler window (denoted by ii), as shown in the following screenshots:

Figure 13.71 – Killer Wave running with 'Profiler' outside of the Unity Editor

Figure 13.71 – Killer Wave running with 'Profiler' outside of the Unity Editor

As you can see, we no longer have this resource issue showing up in our Development Build (denoted by * in the preceding screenshot).

Further Information

If you would like to know more about the Profiler window, check out the following link: https://docs.unity3d.com/Manual/Profiler.html.

As we have seen, the Profiler window is a helpful tool that helps us rectify any issues with memory leaks, garbage collection, and any other possible issues.

Now, we'll look at our last Unity tool, which we can use to see how the graphics pipeline is being used to display our game.

Frame Debugger

Frame Debugger can be used to show how each frame is created for our game in the Unity Editor. This can help us with any potential shader issues regarding how a piece of art is displayed. However, this is also a healthy reminder of how a scene is brought together and challenges potentially any unnecessary effects/materials used.

To access the Frame Debugger tool, do the following:

  1. At the top of the Unity Editor, select Window | Frame Debugger.

Our Frame Debug window will appear.

  1. Now, let's load up our title scene from the Project window (Assets/Scene).
  2. Click on the Enable button at the top of the Frame Debug window to see how the frame is created.
  3. The Frame Debug window will come alive and show us a list of tools and properties being implemented.
  4. With the Game window in view, scroll the slider (highlighted in the following screenshot) in the Frame Debug window from the right slowly to the left to see how this frame is created.

The following screenshots show the Frame Debug window with the Enable button highlighted, along with three steps (4, 8, and 26):

Figure 13.72 – The 'Frame Debugger' tool going through each step of your game

Figure 13.72 – The 'Frame Debugger' tool going through each step of your game

Note that step 4 shows the image that has been applied to the Bloom texture to create the shiny glow in step 26.

After going through each of these steps and seeing all the maps, render targets, and all the other necessary steps to make a frame, it's also possible to select draw calls (a call to the graphics card) from the Frame Debug window, which will highlight the game object it's referring to.

In the following screenshots, we have the shop scene with a total of 47 steps, as shown at the top of Frame Debug. If one of the draw calls is selected within the Frame Debug window (the middle highlighted rectangle), it will ping which game object it is referring to in the Hierarchy window, as shown on the left-hand side:

Figure 13.72 – The 'Frame Debugger' tool going through each step of your game

Figure 13.73 – Frame Debugger showing which game object it's referring to

Further Information

If you would like to find out more about Frame Debugger and its capabilities, check out the following link: https://docs.unity3d.com/Manual/FrameDebugger.html.

Hopefully, you will be able to make great use of Frame Debugger and debug any graphical issues and understand the graphical pipeline more with Unity.

Before we summarize this chapter, we are going to go through each of the four bug reports from our game's bug testers.

Tackling bugs – answers

As programmers, we need to, for example, follow a value through a series of steps to see whether it's the reason why code is not doing what it's supposed to do. However, there are also different methods for carrying out testing, and it's also good to think about checking your or someone else's code after an update has been applied to the project's code.

As a programmer, you will likely hear of different types of methodology that are carried out and how much of a project's code should be tested.

Here are the more popular types of tests you will carry out on your own and other projects:

  • Unit: A unit test is typically the first test that's carried out whenever a new piece of code has been added to a project before you carry out further testing on a larger scale. These tests can be as small as checking a for loop or a method to make sure a small block of code is working correctly.
  • Integration: This type of test is used when multiple sections of code (which could be from other programmers) are brought together and tested to see whether any issues occur when the game is running.
  • Smoke: These are tests that are carried out to determine whether the current build is stable. This type of test helps bug testers decide whether to proceed with further tests. Smoke tests should be minimal and frequent between builds.
  • Regression: When adding code to a project, there is always a chance that the existing code may clash with the new code that's been added. Here, you check the existing code to make sure that a change or addition hasn't created errors. These tests can be run manually for small projects or a suite of tests each time an update has been implemented for larger projects.
  • System: Typically, a system test would be conducted after an integration test to check the project code as a whole for any defects and general code behavior.

Testing often helps you to keep track of a project overall and not be solely focused on one part of it. This is also why it's important to have some kind of plan; for example, we have our Game Design Brief. We could also be even more technical and have a UML diagram to help us see the connections between our scripts. So, we shouldn't think any differently about coding. Now that we have our code, we can hopefully improve it, make it more efficient, and remind ourselves of the SOLID principles.

Speaking of bug-testing, have you thought of any solutions to the four bug reports that were made for our game back in the Tackling bugs section? Hopefully, you have, as we are going to go through each of them now.

Bug report – "Standalone AD button" solution

As you may recall, we have our shop scene, which features an AD button. When pressed, the player will watch an advert and receive shop credits as a reward. This works fine in the mobile version of the game, but it had been reported that this button does not work on the standalone version.

The short answer to this is that Unity doesn't support adverts for standalone builds. This leaves us either looking for a solution to have an advert in our game or turning off the AD button game object, either through scripting or manually through the Hierarchy window. Either way, this is a simple quick fix, as removing the AD button will automatically make the Start button resize, thanks to Vertical Layout Group. Some redesign would need to be implemented to solve this issue, rather than it being solely a programmer problem:

Figure 13.74 – The Shop button layout without the AD button

Figure 13.74 – The Shop button layout without the AD button

Bug report – "Resetting the player's lives" solution

To make the player's lives reset correctly, we need to apply a fix in the TitleComponent script so that when our game restarts back at the beginning from either quitting or the player losing all of their lives, GameManager.playerLives is reset back to 3.

In the TitleComponent script, add the following code to reset the player's lives back to 3:

  void Start()

  {

    if (GameManager.playerLives <= 2)

        GameManager.playerLives = 3;

  }

Save the TitleComponent script.

Bug report – "Slower systems on level 3" solution

The benefit of having multiple devices to run a series of tests is vital. If your game supports a low spec device, then you are also appealing to a wider audience. Reports for our game are coming in stating that the device struggles with lower-powered devices. To fix this, you need to ensure the following:

  • Post-processing is disabled.
  • Fewer enemies are in the levels on the screen at once. You can do this by changing the speed of EnemySpawner in the Inspector window.
  • Remove any global illumination from scenes and apply basic lighting.
  • Remove additional backgrounds from the shop scene.
  • Change the CameraMovement script's Start function. Invoke from a 6-second wait to 7 seconds to give the device more time to load.

Bug report – "Sometimes, the game ends too quickly" solution

It has been reported that levels finish earlier than they should do, so instead of a level lasting 25 seconds, it has been reported to last only 5–10 seconds.

This is happening because the BeginGame method in the ScenesManager script is not resetting the gameTimer variable back to zero. Follow these steps to fix this bug:

  1. Open the ScenesManager script.
  2. Scroll down to the BeginGame method, and at the top of the method, add the following line:

    gameTimer = 0;

  3. Save the ScenesManager script.

Test your code, keep revisiting it, and keep polishing it. Continue to look at other ways of improving your script. Accept that the first few lines of code aren't going to be your best and that it's okay to revisit and keep optimizing your code.

Further Information

If you would like to continue looking into how to improve the code for the game you've created, check out the following link from Unity: https://learn.unity.com/tutorial/fixing-performance-problems#5c7f8528edbc2a002053b595.

That brings us to the end of this section, where we built our standalone version of our game and looked at potential issues that we needed to overcome, which we picked up with our bug testers. After that, we looked at the Profiler window, which we can use to monitor the performance of our game, and Frame Debugger, which shows what steps are followed to make a frame. We then discussed how and when to test our game, before looking at the bugs we were issued and how to correct them.

Now, let's discuss this chapter as a whole.

Summary

This chapter was about taking the game we have been developing throughout this book and putting it together as it reached its end. We spoke about how we could push our game further by adding physics collisions other than bullets or buttons. We set up collisions that got us more involved with tweaking the Rigidbody component to make our game objects behave in different ways. We did this by adding drag and affecting our scene's gravity.

We then moved on and discussed how we could improve our game's screen ratio by updating its Canvas Scaler and how it would make our UI look more stable under different ratios. We also made our game-playing area more flexible under the different resolutions using different Unity functions, such as WorldToViewportPoint.

At this point, our mobile version was ready to be built and tested so that we could see how well it ran with updated touchscreen controls. We also looked into its optimization in terms of textures and compressed them to decrease the size of our game and make it run better overall.

After the mobile build, we looked at the PC version and made some more changes to improve the look of the game. We did this because the standalone machine was likely going to have a more powerful CPU, graphics card, memory, and so on. Then, we added effects such as post-processing to change the look and feel of our game to make it more polished. We continued adding more polish to our game by adding global illumination and fogging effects from our Lighting settings window. This made our materials shine red and bleed through the foggy darkness to give them more of a futuristic feel. We also added reflective statues to our end level. These made use of the reflection probe component. After that, we discussed how to optimize it in terms of the size of its reflective texture.

Finally, we looked into building and testing our standalone version and also introduced some bug-testing scenarios, where our bug testers found issues with things not working the way they should. We reviewed and addressed them together.

Making a game isn't easy, and there are many ways in which a game can be made. Someone will always have a better way than you and likely pick holes in it. However, as mentioned in this chapter, a game can be made in sweeps and improved at each sweep; the worst thing to do is to try and make a perfect game the first time around. If you think like that, you'll end up with no game at all.

Are you ready for the full mock test? You should be; see what you've remembered by reading (and hopefully recreating) this book. If there are any problems with the questions that you can't answer, there are reference numbers next to each question (example: CH1, meaning Chapter 1) to help jog your memory. This will all be explained thoroughly in the next chapter – enjoy it.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset