Chapter 1: Setting Up and Structuring Our Project

For some time, Unity has been issuing exams that cover a range of different skills for people who are either graduates, self-taught, or are classed as veterans in their field.

If we check the prerequisites on Unity's website (https://unity.com/products/unity-certifications/professional-programmer), they tell us that this exam isn't for absolute beginners and you need at least 2 years of experience working with Unity and computer programming, including C#. This book will take you through the process of becoming as familiar as possible with Unity and its services, to the point where it might feel like a beginners' course; however, I expect you to know the fundamentals of C# programming, such as what an if statement is, what a function does, and what a class represents. If you don't, I would recommend reading Harrison Ferrone's Learning C# by Developing Games with Unity 2020 book first (https://www.packtpub.com/product/learning-c-by-developing-games-with-unity-2020-fifth-edition/9781800207806). Be aware that this exam is based on Unity 2020 LTS. This is the second edition of the Unity Professional Programmer exam. You will gain no real benefit following this book installing Unity 2021 and upwards. If anything, you run the risk of becoming disconnected from the learning process of this book as the Editor and general functionality may differ.

As you can imagine, it is sometimes difficult to gauge what level a programmer is at with their experience. Imagine what it's like for an employer to recruit someone. Often, a programmer is judged by their portfolio, but what happens if you're a graduate without one or you lack a large quantity of work because you've been too busy studying? Perhaps you've been a programmer for years but can't show any recent work due to signing non-disclosure agreements? Some employers might look at your CV and not even look at your portfolio as the qualifications just don't look impressive enough. The tests a potential employer can put a developer through can also be unbalanced, unfair, unrealistic, and not challenging enough; it's likely that the employer has grabbed a programmer's questionnaire template off the internet to test you.

However, having qualifications from Unity itself sends a clear message that you've been tested and covered all the fields that acknowledge you as a certified Unity programmer. Even if you have a decent portfolio showing a level of standardization and focus, having qualifications from Unity can give you the edge over someone else in a job application.

This book serves two main purposes:

  • To take you through a fun, simple, side-scrolling shooter project with some downloadable art assets and sounds that will cover the core objectives in Unity's exam
  • To get you as ready for the exam as possible with regular testing and reviewing

So, if you feel like you don't need to carry out the project, skip to the very end of this book to try out the final mock test—actually, I recommend you do this now. Flick to the back of the book, take the test, and if you don't do as well as you planned (that is, score over 75%), at least you know you have something to learn, and working through the project might help. Don't take the exam too soon after taking the mock test if you aren't happy with your score—you will be going up against your own muscle memory, rather than the knowledge itself.

Unity has split the necessary areas of this exam into six core objectives. We will cover what these objectives are in this chapter before introducing our side-scrolling shooter project, which will cover the majority of the objectives. We will also cover specialized subjects outside of the project, such as networking, VR, and more, in the Appendix section of this book.

Throughout the following chapters, we will refresh ourselves with the general practices of coding—a bit like the dos and don'ts when coding a project. Then, we will get to grips with the genre of the game and, hopefully, get you thinking about how to set up a game framework. Finally, we will download and set up our empty project in Unity and learn about Unity services.

In this chapter, we will cover the following topics:

  • The six core objectives
  • Overview of design patterns
  • The SOLID principles
  • Designing the Killer Wave game
  • The Killer Wave game framework
  • Setting up Unity 2020 LTS
  • Setting up your Unity project

We won't be doing any coding in this chapter as our focus is on what Unity wants from you in the exam. We will discuss an overview of the methodology and structuring code with design patterns. You may feel tempted to skip some parts because you simply aren't interested, but remember the only reason I am mentioning the majority of this stuff is it's highly likely to come up in the exam. So, please don't feel like I'm punishing you on purpose!

The next section will detail the core objectives covered in this chapter.

The core exam skills covered in this chapter

Working in professional software development teams:

  • Setting up your Unity project
  • Recognize techniques for structuring scripts for modularity, readability, and reusability.

Technical requirements

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

The six core objectives

The exam will mainly focus on scripting and the use of Unity's Application Programming Interface (API), Animation Controller, particles, rendering, and more. The whole idea is to get you familiar with what Unity has to offer you as a programmer. Unity has categorized their exam into core sections, which is a nice way of separating the workload for the exam.

The six core objectives are as follows:

  • Programming core interactions
  • Working in the art pipeline
  • Developing application systems
  • Programming for scene and environment design
  • Optimizing performance and platforms
  • Working in professional software development teams

Let's look at these in more detail.

Programming core interactions

When we load up our first blank scene in Unity, we will be controlling objects (or, as Unity likes to call them, game objects), moving, rotating, and/or expanding them. Not only can you adjust or transform these game objects, but you can also give them components to make them behave like a camera, a light, and/or a piece of animation, and so on. Each one of these components will typically have properties and values. So, for example, a camera component will have properties adjusting its field of view, its background color, and a few other camera-related things. Another example of a component is Rigidbodies. A Rigidbody component is typically used when you want a collision to happen between two game objects. Or what would you want the game object to do when it makes contact with another game object? Will it blow up? Will it collect the other game object? Will it knock it out of the way where one has a greater force? Unity wants you to know how to use these components and game objects. They also want you to know how you can control these objects with a control pad or keyboard controls as if they are characters in a computer game. This may already sound daunting, but you don't need to be a math teacher to be successful (but it's great if you are!). What's so brilliant about Unity is that it does a lot of the hard work for you. All you need to know is what you want and how you want to use it.

To pass the exam, you need to know how to do the following:

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

Let's move on to the second Unity exam core objective—the art.

Working in the art pipeline

As you know, this is a programming exam, so why do we have an exam objective that refers to art? Well, as a programmer, it's highly likely that you will be manipulating game objects to do the things mentioned in the exam objectives. You might not just move something around—you may also want to change a game object's color. For example, instead of having a car game object that's dull and flat, you may want it to be shiny and reflective with a gold tint. For this to happen, a game object typically has a material assigned to it that you can apply maps with. These maps can contain colors, marks, and dents.

All these maps and their properties will alter, change, or enhance your game object to what is known as a pipeline, which is the process of your game object becoming something more than its original form. If you want the game object's car wheels to turn around, then how can you do that? You may not have an animator to do this. You also may be asked to animate a scene's lighting in the code and not manually tweak its properties. You're not expected to be a master at animation or lighting, but Unity wants you to know the basics. It might not be the artist's job to include snow or rain in your game, and it's likely that you will have to use a particle system to create these effects. How will you change its properties to change from a light drizzle to a thunderstorm in code? If you don't know, don't worry—you will be introduced to these components and their properties soon.

To pass the exam, you also need to know how to do the following:

  • 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
  • Understand two-dimensional and three-dimensional animation and write scripts that interact with Unity's animation API
  • Understand particle systems and effects and write scripts that interact with Unity's particle system API

Let's now move on to the third Unity exam core objective, where we focus on interfaces, storing data, and being aware of multiplayer functionality.

Developing application systems

I wouldn't say that this is a core objective as such; it's more of a cluster of things Unity has tied into one bundle and labeled it "core." So, let's break this down and work out what they want from us. Developing application systems is focused on how Unity communicates with the user and stores their information. This is where a User Interface (UI) needs to contain the right guidance and information; but also, from a technical point of view, it needs to be positioned correctly no matter what ratio the screen size is. UI can also be used in-game in the form of a minimap guiding the player through a maze, showing them where enemies are. UI can also be used for advertising and displaying information from a different computer server online. When information is taken from the player, how sensitive is this information? Should it be stored locally with low security? Do we need encryption? Should it be stored in a different file format online? Finally, Unity is currently getting rid of their multiplayer network system, called UNet, and replacing it with something brand-spanking new. This means we only need to be aware of Unity's network and prepare for a few general networking exam questions.

To pass the exam, you need to know how to do the following:

  • Interpret scripts for application interface flow such as menu systems, UI navigation, and application settings
  • Interpret scripts for user-controlled customization, such as character creators, inventories, storefronts, and in-app purchases
  • Analyze scripts for user progression features, such as scoring, leveling, and in-game economies, by utilizing technologies such as Unity Analytics and PlayerPrefs
  • Analyze scripts for two-dimensional overlays, such as Heads-Up Displays (HUDs), minimaps, and advertisements
  • Identify scripts for saving and retrieving application and user data
  • Recognize and evaluate the impact of networking and multiplayer functionality

Let's move on to the fourth Unity exam core objective, where we'll focus again on game objects.

Programming for the scene and environment design

This core exam objective sounds similar to the first core objective, where we introduced the game object; however, this time we are concentrating more on the management of the object. When is a game object made? How is it made? How do we get rid of it when we don't need it anymore? Should we destroy it? Or do we label it as destroyed but store it elsewhere in the scene to save memory? We can also look at few common components, such as the Nav Mesh Agent, which is used typically for artificial intelligence, and understand what a game object would do if, for example, it's a character that knows when to patrol, chase an enemy, or hide. We will also need to know about the audio component and mixer, how we can manipulate them, and how to create echo effects. Yet again, we have a situation as with the animation and art—we don't need to be amazing at these skills, we just need to know that they exist.

To pass the exam, you need to know how to do the following:

  • Determine scripts for implementing audio assets
  • Identify methods for implementing game object instantiation, destruction, and management
  • Determine scripts for pathfinding with the Unity navigation system

Let's move on to the fifth Unity exam core objective, which is about knowing what to do when you've broken something and how to check performance issues.

Optimizing performance and platforms

Any programmer will encounter problems, and it's sometimes helpful to know about the problem before you have to solve it. This Unity exam core objective is about tracking and fixing your own issues. Sometimes, you will need to step through your code to find a game-breaking bug, or you might want to know why a game is stuttering at a certain point when it is played. This is where you would use one of Unity's handy tools, such as the profiler, to monitor performance. You will be able to strip back the components to see whether you're dealing with a physics issue or whether your second scene is taking a long time to load, for example. Being able to solve your own problems with Unity's tools is the key point of this core objective. Other examples of issues that Unity wants you to think about are, for example, if you are going to build a virtual reality app, where would the UI be placed, if at all? Do you need to be more aware of your frames per second? These are the types of questions we will cover in the book.

To pass the exam, you need to know how to do the following:

  • 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.
  • Determine common UI affordances and optimizations for XR platforms.

Let's now move on to your sixth and final Unity exam core objective, working with people.

Working in professional software development teams

Working with others in a professional environment and sharing and working with each others' code can be tricky if a decent structure isn't in place. Things such as version control can help, where each member can "push" their work to Unity's server (or the cloud as it's known in general terms) for others to share and work from. Some users might work remotely, or you could all work remotely. There are different types of version control; the most typical one used is called git.

To pass the exam, you need to know how to do the following:

  • 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

That's it! If you know the content of these six objective cores, you will pass. This book will cover all of these problems and issues within the project that we will be talking about later on in this chapter. How will you know whether you've successfully met your objectives? I will be throwing questions at you every few chapters to see how you are getting on. If you fail or don't do too well, then I see that as a good thing because you'll know exactly what you need to focus on and revisit before taking the exam.

Anyway, this is all to come. Next, I want to talk about design patterns. Given that we are coding, it's a good idea to talk about structuring code, following decent methods, and not creating code that can get tangled into a mess if there isn't enough planning in place.

Overview of design patterns

At the beginning of this book, I mentioned that I will cover as much of Unity as possible, even though it is expected that you have been using Unity for at least 2 years before taking the exam. With regard to the fundamentals of programming, we will obviously be applying C# code. So, I expect that you are familiar with things such as functions, methods, if statements, classes, inheritance, polymorphism, and so on. I will explain what I'm doing and what you should be doing for each bit of code I present, but I won't be going through the basics of each segment of code.

Design patterns are typical solutions to problems you are likely going to come across, and if you have a pattern that can solve a problem, then you should use it. Creating applications yourself, with your own workflow is great, but if you can explain an issue to another programmer using design pattern terms, it shows that you know what you are talking about and if they are a good programmer, they'll likely know what you are talking about as well. The more patterns you know, the more flexible and standardized your code will be, and you are likely going to need more than one pattern. Otherwise, you'll be forcing your code down a structure that might not suit it and this will just cause problems.

The batch of 23 design patterns that are considered to be the foundation of all patterns was created by the gang of four. If you want to check out who the gang are and all of their 23 patterns, then go to https://www.packtpub.com/gb/application-development/hands-design-patterns-c-and-net-core. All of these patterns are divided into three categories—creational, structural, and behavioral:

  • Creational: These patterns are designed to deal with the creation of objects—how and where an object is made.
  • Structural: These patterns are built to show the relationships between entities.
  • Behavioral: These patterns are designed to deal with how objects communicate with each other.

Ideally, after you pass your exam, try and visit more patterns. Get used to them as it will help you with your future roles. If you are interested in learning more about C# and design patterns, I recommend reading Hands-On Design Patterns with C# and .NET Core (https://www.packtpub.com/application-development/hands-design-patterns-c-and-net-core). This book isn't based on Unity but on C# .NET core, which means it contains coding libraries that overlap with Unity's. Unity contains elements of .NET and the more advanced you become as a programmer, the more you will inevitably start dipping into .NET. However, that is beyond the scope of this book. Let's return to our overview of some of the design patterns that you may be questioned about in the exam. The first pattern is Builder, so let's check it out.

Builder

The first design pattern from the gang of four is the Builder design pattern. This design is typically used to make alterations to an object. If you can imagine a series of specifications to create a custom spaceship, we would (or not) need windows, thrusters, wings, lasers, missiles, and whatever else. Putting this down in code could easily get too busy and end up with something bad such as a list of parameters in a constructor.

The following code is an example of a poorly built spaceship with a bloated number of parameters in its instance:

SpaceShip spaceShipWithGuns = new SpaceShip(true, false, null, null, 8, true, null);

Another nightmare could be a series of subclasses where each possible combination is made for each spaceship:

public class SpaceShipWithBoosters : SpaceShip

{

       //Making a ship with boosters…

}

public class SpaceShipWithOneBoosterAndAWindow : SpaceShip

{

      //Making a ship with one booster and a window…

}

Both of these examples we don't want to do. Our code will bloat and in the long run, will be more difficult for us or anyone else to maintain.

The Builder design pattern will typically hold an interface with all the different parts for your spaceship (boosters, weapons, and so on) methods.

When it comes to making the ship, we will have a class that will inherit the methods from the interface and each method can take values to specify whether the ship has missiles or windows, and if so how many of them.

The following diagram shows how the Builder design pattern works:

Figure 1.1 – Builder design pattern

Figure 1.1 – Builder design pattern

Further Information

If you would like to know more about the Builder pattern with regards to its code, you can go to the following link and install a demo of the code running in Unity:

https://github.com/PacktPublishing/Unity-Certified-Programmer-Exam-Guide-Second-Edition/tree/main/Patterns

Let's now move on to the next design pattern—Singleton—where we can have a control point from which the majority of your code sends and receives data.

Singleton

The Singleton design pattern isn't really much of a pattern as such, but more of a common practice that some programmers love or hate, or both! I'll explain why shortly.

The Singleton pattern acts as the core location that code will likely come from and go to. Our primary thought with Singleton is there is only one of its kind, for example, one game manager script, one level manager script, one audio manager: not multiples of the same instance. These types of scripts will exist in your Unity scene and likely will never get removed. If they do get removed or don't exist, then one—and only one—is instantiated. You can use the Singleton pattern for a manager type of object that overlooks a game, or it could hold what level the player is on, how much time is left in the level, what types of enemies will be used in this level, and so on. It's a central common point that the game will not want to forget or have multiple versions of. Like all design patterns, it makes sense that it's called Singleton because there should be only one of its instances.

So, this sounds like a good design pattern. However, it is argued that the Singleton pattern holds too much control over the rest of the project's code and can also jeopardize other design patterns, especially if you have a system that depends on things being in a particular order. Also, it goes against the SOLID principles—the guide on how code should be treated—which I'll cover later on in this chapter. The single responsibility principle, in short, means a script shouldn't contain more than what it's originally built for. As you can imagine, the Singleton pattern can easily get complicated as it carries multiple responsibilities. The success of design patterns is heavily dependent on what a designer feels comfortable with; it also depends on what is required for the project. In any case, Singleton is still a popular pattern, and we will use it in this project.

Coming back to the definition of Singleton, we can describe it as a pattern that ensures a class has only one instance and provides a global point of access to it.

The following diagram shows how the Singleton design pattern works:

Figure 1.2 – Singleton design pattern

Figure 1.2 – Singleton design pattern

Further Information

If you would like to know more about the Singleton pattern with regards to its code, you can go to the following link and install a demo of the code running in Unity:

https://github.com/PacktPublishing/Unity-Certified-Programmer-Exam-Guide-Second-Edition/tree/main/Patterns

Let's move on to the next design pattern, Abstract Factory, which focuses on making a mold of common traits that can be given extra features later.

Abstract Factory

The Abstract Factory pattern is designed to cover common traits that multiple objects share. For example, if I want to make enemies attack your player, I want all the enemies to have a health bar, and I also want them to take damage from your player. With Abstract Factory, I can create a mold, so no matter what enemy is created, they will have these two properties, instead of having to create them each time for each enemy. This design makes things easier and more uniform for your project.

The following diagram shows how the Abstract Factory design pattern works:

Figure 1.3 – Abstract Factory design pattern

Figure 1.3 – Abstract Factory design pattern

Further Information

If you would like to know more about the Abstract Factory pattern with regards to its code, you can go to the following link and install a demo of the code running in Unity:

https://github.com/PacktPublishing/Unity-Certified-Programmer-Exam-Guide-Second-Edition/tree/main/Patterns

The next design pattern is Prototype. This is useful for creating clones of an existing object.

Prototype 

This is another simple pattern that carries some similarities to the Abstract Factory pattern, except this pattern creates a clone of the object it's attached to. So, this is less of a factory and more like a daisy chain creating itself. Another way this could be looked at, without going into too much detail, is that it mimics Unity's own prefab system (https://docs.unity3d.com/Manual/Prefabs.html). With Unity's prefab system, you can drag and drop one game object to instantiate another. The difference with Prototype is that this is achieved through code and because of this, we could—if we wanted to—add even more code to make this pattern more intelligent compared to just instantiating an object alone.

A good example of using this design pattern is something such as an enemy spawner in a game. If we had a small army of the same enemies rushing to the player coming from the same point, then this would work well.

The following diagram shows how the Prototype design pattern works:

Figure 1.4 – Prototype design pattern

Figure 1.4 – Prototype design pattern

Further Information

If you would like to know more about the Prototype pattern with regards to its code, you can go to the following link and install a demo of the code running in Unity:

https://github.com/PacktPublishing/Unity-Certified-Programmer-Exam-Guide-Second-Edition/tree/main/Patterns

Let's move on to the next design pattern—Object Pool, which, this time, isn't from the gang of four but is worth mentioning as it is common and should be implemented when dealing with a large number of game objects to save system resources.

Object Pool

This design pattern is more of a good practice tool, rather than an actual design pattern; however, it's recognized like one. Let's jump into an example to explain.

Imagine you are creating a game for a mobile device, and you want your game to support as many types of mobile devices as possible, even the really old phones that aren't very powerful. Your game consists of lots of bullets being fired across the screen. A typical way of making bullets fire would be to instantiate them, and when they leave the screen or hit an enemy, the bullet plays an exploding animation, makes a sound, and then destroys itself as it isn't required anymore. This applies to every bullet fired. Well, what if I told you all that you needed was 10 bullets in total and none of these bullets would be destroyed? This is the idea behind Object Pool; the bullets can be outside the game view where the player can't see them. When the player fires the bullet, the first bullet is moved into position next to the player, then when the bullet makes contact, it plays its exploding animation, makes its sound, and moves off the screen with the other nine bullets. This saves your mobile device resources as it's only dealing with 10 bullets, or however many the player can fire on the screen, at once.

The following diagram shows how the Object Pool design pattern works:

Figure 1.5 – Object Pool design pattern

Figure 1.5 – Object Pool design pattern

Further Information

If you would like to know more about Object Pool with regards to its code, you can go to the following link and install a demo of the code running in Unity:

https://github.com/PacktPublishing/Unity-Certified-Programmer-Exam-Guide-Second-Edition/tree/main/Patterns

Let's move on to the last design pattern, which is also not from the gang of four but again is common enough to talk about.

Dependency Injection

This pattern is often implemented with general C# applications and website development where you have the option of using constructors to set up each class. Unity doesn't really like using these constructors (https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors) due to inheriting monobehaviour (which comes automatically with every newly created Unity script—see https://docs.unity3d.com/ScriptReference/MonoBehaviour.html for more information). You can, of course, remove monobehavior, but then you start losing a large amount of functionality with Unity. But the point of Dependency Injection is that you can have classes to do different things because they have received data from abstraction.

I have seen this design pattern mentioned in the exam, so I'll give you a brief overview of this design and its relationship with Unity from my perspective. Even though you will see more of an emulated version of the design, it would be good to mimic it for Unity projects. It's about understanding how far you can spread your code into separate dependencies, driving each class instead of clustering a bunch of properties into one script. The benefit of doing something like this is it introduces flexibility into your code without having a knock-on effect on other properties.

The following diagram shows how Dependency Injection simply supplies one object to another:

Figure 1.6 – Dependency Injection design pattern

Figure 1.6 – Dependency Injection design pattern

Elements of this design are implemented in the project and are referred to as the Dependency Injection pattern, but in practice, we also cover the Dependency inversion principle in the SOLID principles in the next section.

This was a sample of all the many design patterns out there that can make you stand out from the rest of the Unity programmers. From my experience at university and from progressing through Unity programmer roles, these patterns aren't used enough. However, if you understand them (as you will in these projects), log them so you don't forget, and whenever you start or join a project, think of what patterns go with the roles you choose or are given. It's very tempting to just jump in and start coding, but this is where you might run into dead ends or oversized classes.

Let's move on and look at the SOLID principles of coding. I have mentioned them briefly a couple of times – consider them a guideline for what makes a good programmer.

The SOLID principles

When you are planning and coding your projects within Unity as an Object-Oriented Programming (OOP) practitioner—programming that is based on objects containing data—patterns are a great way of making things uniform, saving time, and, hopefully, relating to other programmers who share the same patterns with you.

However, you won't always have a design pattern for all of your projects and it may not be practical to try and force plans that simply aren't practical. If we brush the design patterns to one side, there is an even deeper methodology to programming—the SOLID principles. These principles are guidelines that remind OOP programmers what they should be thinking about when coding projects. They outline what you should and shouldn't be doing with your code. Yes, you could ignore the SOLID principles, and even ignore design patterns, but difficulties will occur and increase the risk of you coding yourself into a dead end and creating multiple errors when you change a single line of code. You'll have colleagues scratching their heads not knowing what your code is doing, as well as inefficient classes and methods that potentially slow down your system—the list goes on. It's very easy to not follow a plan and be keen to just get the job done. Eventually, this will haunt you and you will have to accept that you need a plan and you need to follow rules, especially if your project expands, even if it's just you coding the project.

The five SOLID principles are as follows:

  • Single responsibility principle
  • Open/closed principle
  • Liskov substitution principle
  • Interface segregation principle
  • Dependency inversion principle

Let's look at each one in more detail, starting with the "S" in SOLID—the single responsibility principle.

Single responsibility principle

A class should only have a single purpose; changes to the class should be specific to affect the specification of the class alone.

This means that we should keep classes simple and not give our classes multiple roles. If you have a class that handles bullets, don't let any extra features fall into it; save them for another class. A common problem that programmers come across is making a class that constantly grows and mutates. This will eventually create problems and typically results in refactoring code, especially if you want to add something specific to your class, which can have an effect on the other properties tied to it.

Let's now move on to the "O" in SOLID—the open/closed principle.

Open/closed principle

Scripting should be open to being extended but closed for modification.

Create a class that supports extra work being applied to it without having to constantly revisit and modify your original class. For example, if I have a spaceship that fires a bullet and I want to add different types of weapons, I want to avoid adding any more to the original script. If I want to add 50 weapons, my original script would simply keep growing to an unwieldy size. Ideally, this weapon script should be able to receive an extension that can swap out what weapon is fired, so even if I had 50 weapons, the script wouldn't need to change; it would just swap out the weapon from the extension. Something such as an interface (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface) or an abstract class (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract) that receives the weapon type would work well with this. If the class is encouraged to grow and cater to all these weapons, you will start violating the single responsibility principle.

Let's now move on to the "L" in SOLID—the Liskov substitution principle.

Liskov substitution principle

Content in objects should have the ability to be replaced with an instance of a subtype without altering the base of the object itself.

If a class inherits from another class, the inherited class should be able to access the original base class as if it was the original class. But what does that mean? So, in theory, the child class should be able to be used in the same manner as the parent class.

The main benefit of this is you can have a class with a method containing values that can be overridden for a particular object. For example, if a car is factory-made, its default color when leaving the factory is white. Several of these white cars can be sprayed with different colors even though it is the same car; the color is being overridden by another factory.

By default, a base class could, for example, return a default value, while a child class using the same method could override it for its own. If this principle was ignored, you will likely end up using a lot of if statements to cover each child's class method, which would then involve expanding code, which then violates the two previous principles we spoke about.

Let's now move on to the "I" in SOLID—the interface segregation principle.

Interface segregation principle

Specific interfaces are better than one general interface.

This one is fairly simple—when implementing interfaces, try to keep them light and interchangeable with other classes and methods, as opposed to having one huge interface that will likely be redundant to the specific class you are inheriting from. For example, an interface can contain variables for health points, defense, strength, and so on. If I was going to apply this to a character, this would make sense, but if I also applied it to an apple, it wouldn't so much. However, I would still have to implement it on the apple as it's an interface.

Let's now move on to the "D" in SOLID—the dependency inversion principle.

Dependency inversion principle

Lean on abstractions and not concretions.

Abstract classes can be used to cover a general field of classes, which is ideal for something such as a gun script. You can have multiple different types of guns with different shot powers, bullet counts, and so on. Otherwise, you will rely on the specific gun class, which can then lead to multiple variants and class calls to that specific gun class. Abstraction means that no matter how many gun classes there are, it won't affect other scripts catering for all the variants.

In summary, the SOLID principles encourage you to cut up your code into segments and remove expanding classes. It encourages you to look for other ways of writing your code instead of creating a chain reaction when a new piece of code is written.

So, when it comes to a project, if you ignore the SOLID principles and design patterns, you will survive but you will be creating a mold of what your next project will be like. Eventually, it will turn into a bad habit and it'll become more difficult to retrain yourself. Speaking of projects, let's check out the game design brief for the game we are going to make—Killer Wave!

Designing the Killer Wave game

This will be our prototype/demo for a futuristic classic side-scrolling shooter, where we get to power up the ship and destroy the enemies that come at the player in a killer wave! We have spoken about design patterns and solid principles, and we are going to examine them in more detail, including all of the six core objectives for the Unity programmer exam. We will go through structuring the game, breaking it up into a framework of segments. We need to understand the relationship between each class and know how to expand our code without it upsetting what we've already written.

We will cover particle effects with an environment of stars whizzing past and ship thrusters with multiple particle colors. We will animate enemy ships and use Unity's own API to animate our environment scene. The list is quite long, but if we go through this project, we will not only be ready to tackle the Unity programmer exam, but we will also be ready to expand on this project and take on other projects with the correct approach; so, let's check out the following set of instructions (or a brief would describe it better) for making Killer Wave.

Game design brief

Title: Killer Wave

Genre: Side-scrolling shooter

Platform: PC/Mobile

Target audience: Age 10+

Game concept: In space with enemies rushing past the player, players need to shoot and destroy as many enemies as possible within a limited number of lives before the end of the level. Enemies come in two forms—wave and flee. The third level will feature a large flying-robot boss that the player will chase off.

Game flow and mechanics: The player will be in a small spaceship that can be controlled with the keyboard/joypad cursor controls and fired with the Ctrl or Command key from its position and can travel right. The level will end when the player has traveled to the end of the stage from left to right.

Constraints: The player has three lives when the game is not connected to the internet. The player will be contained within the screen boundaries.

Visuals: HUD—in-game score, in-game lives, game title, level title, game-over title.

Enemy wave: Featured in all three levels. These enemies will be instantiated to travel in a sine-wave pattern moving at a slow rate from the right to the left of the screen. The enemy will fly independently or within a group of the same enemy type, creating a trail.

Enemy flees: This enemy will be placed in dotted areas of the third level. Their behavior will move away from the player if in range. If the range is lost, the enemy remains still. If contact is made with the player, the player will lose health and the enemy will die.

Enemy boss: The boss is seen during the third level and greets the player, only to then zoom off out of the screen view with the player automatically chasing them.

We now have a taste of what the game will be like. As a programmer, we need to think not only about how the game is made but also how to expand on it. We need to think about how to structure the levels and how we structure the enemies. How do we do this? Do we need to consider changing the design of each level on the fly without slowing down development? If you can think of all the things involved in how a game is going to be made and what parts need breaking down, you'll save yourself a lot of time in development. We are next going to talk about the structure of the game.

The Killer Wave game framework

We now roughly know what type of game we're going to make. Don't worry too much about the exact details as it will not affect the development phase. Our main focus will be the framework of the game; we'll focus on cosmetics in a later chapter.

It's very easy to jump into game development and make it up as you go along—sometimes, that's half of the fun. But when it comes to the fundamentals of creating any application, we need to know where to throw our creativity and logic by sticking to a particular development process. Ideally, you need a framework.

Before I carry on presuming you know what a framework is, let's just consider it as an overall blueprint—a plan of how all our pieces of code are going to talk to each other. Frameworks are similar to design patterns—the plan of the code is set out and ideally shouldn't be expanded on because we're sticking to a plan.

Yes, we know some design patterns, but if the overall flow and direction of our code are lacking scope, we are likely going to run into issues with working ourselves into a dead end. Sometimes, developers think that because they've learned a single framework, they can use it to build any application and they use it with every project.

This, of course, is not how we should do it. The more we know about our patterns, the easier the flow of the code will be when it comes to extending our overall master plan or the game's framework.

There are hundreds of ways of making this demo with multiple patterns and frameworks. The one we will follow here is my version, but if you have a better one or one you feel more comfortable with, go for it. As long as you understand the process described in the upcoming chapters and you make use of Unity's APIs on the way, I would encourage you to do this; otherwise, just follow along with our examples.

So, with that said, let's move on to our framework for the game.

Framework

To start off, we will break down what we are going to need for the game. The first things I tend to think of are the player, what the player does, and what's going to interact with our player. We also know that there will be a list of enemies. Finally, the game will likely have multiple scenes, so we need to think about how each individual asset will be set up within each disposable scene. As always, things need breaking down into classes and we need to plan the importance of how classes are connected to each other. The following is how I've broken down the game design brief into separate classes.

These are the class responsibilities:

  • SceneManager will globally tell all the classes what scene the user is on (for example, the title screen, level 1, the menu screen, and so on).
  • GameManager communicates with all the game objects and communicates with other managers; it is in charge of the game's loop process.
  • ScoreManager reads and writes the score data when offline and updates the score UI.
  • PlayerShipBuild receives and sets customization settings to PlayerSpawner.
  • EnemySpawner is similar to PlayerSpawner but it can manage all different types of enemies.
  • Enemy refers to multiple enemy classes—for example, if an enemy that shoots is made, it will go in this location of the framework. If an enemy moves or acts differently, it will also be put into the same allocation.
  • EnemyBullet travels at a set rate and removes itself after a set time or if it makes contact with the scenery.
  • PlayerSpawner launches the player in a certain location of the screen and keeps its hierarchy in order.
  • Player fires bullets, receives input controls from the user, and is removed if contact is made with the scenery, enemy, or enemies' bullets.
  • PlayerBullet travels at a set rate, removes and damages the enemy, and removes itself after a set time or if it makes contact with the scenery.
  • ShopPiece handles the content of the player's ship upgrade selections.
  • SOShopSelection holds the data types that are used in each grid selection in the shop menu.
  • SOActorModel holds the common variables for each class it is connected to. As an example, all moving objects have a speed setting; this includes player bullets, enemy bullets, enemy ships, and so on.
  • IActorTemplate isn't a class but an interface. An interface works a bit like a contract to whatever it is connected to. For example, this interface wants the class connected to it to have functions titled Attack(), Die(), and so on. The class must include these functions, even if they are empty. You should, hopefully, already know what an interface is; we will be using them frequently in this book. For more information about interfaces, check out https://learn.unity.com/tutorial/interfaces.

The following diagram shows the visual relationship between each class that we have just listed. These diagrams are typically called Unified Model Language (UML) (https://www.c-sharpcorner.com/UploadFile/nipuntomar/uml-diagrams-part-1/). We could have used a more detailed diagram than the following one, but for the purpose of keeping things as simple as possible, we will just refer to the classes with boxes and names.

Some of you may find this shell-looking framework complex, but both sides mirror each other and control the responsibilities of either game object separately. Let's have a look at this in more detail:

Figure 1.7 – Killer Wave's UML

Figure 1.7 – Killer Wave's UML

Each gray box represents a class that is mentioned in the preceding list; the lines between each box indicate their dependency on the class. The PlayerSpawner class, for example, will need to be coupled with the GameManager class to notify it of what is happening to the Player class; the Player class will need to send and receive information such as lives, enemy kill count, and other stats to the GameManager class directly. If we want to move our score over to be stored on the device, then we can link this to our ScoreManager class. The main takeaway from this diagram is that if a line is connected to either box, there will be communication between the classes.

UMLs are not a prime focus for the exam, but they should be mentioned at this stage given that we are creating a plan for the game. I personally like creating UMLs, in a way; as long as the flow of the game is understood, we shouldn't worry about finalizing every detail.

So, now we have an idea of how the game works, how we are going to break it up into segments, and how segments are related to each other. The next step is to prepare our version of Unity and start planning how to bring the game over to this piece of software.

Setting up Unity

Unity typically brings out a new version of their software every 2 weeks. You might expect this to cause problems with keeping up to date with the latest version for the exam. To date, Unity doesn't update their exams annually, so the exam and our project relate to Unity 2020 LTS. Unity will always keep updating and introducing new components and features with their future releases, but the prime fundamentals should remain the same.

This book is designed for users who have been using Unity for at least 2 years, so I'll assume you at least have a free account with them, and a copy of Unity installed. If not, here is the license activation guide from their 2020 LTS documentation: https://docs.unity3d.com/2020.2/Documentation/Manual/LicensesAndActivation.html.

Once you have created a free account, you can download the Unity Hub. This will hold a reference to the version of Unity you have installed and also your projects.

You can download and install the Unity Hub from here: https://unity3d.com/get-unity/download.

Once you have done that, you can grab a free copy of Unity 2020 LTS.

You can download Unity 2020 LTS from their archives:

  1. Go to https://unity3d.com/unity/qa/lts-releases.
  2. Click on either of the LTS Release 2020 links from the list.
  3. Then click on the Unity Hub button from the scrolling window.
  4. Follow the rest of the instructions to download Unity 2020 LTS.

It's worth noting, at this point, that when going through the installation procedure, you should be sure to have an IDE installed. If you don't, Unity recommends downloading Microsoft Visual Studio Community 2019. All our scripting will take place in this application. The following screenshot shows the recommended IDE selected:

Figure 1.8 – Select Microsoft Visual Studio Community 2019 from the Unity Hub and if you are planning on installing an Android version of the game, tick all three boxes next to the *

Figure 1.8 – Select Microsoft Visual Studio Community 2019 from the Unity Hub and if you are planning on installing an Android version of the game, tick all three boxes next to the *

Information Note

If you plan to install any Unity project on a mobile phone, tablet, and so on, then make sure you select the relevant support files. In this book, we will lightly cover the Android version. Our prime focus will be running our game in the Unity Editor.

Once you have installed Unity, you can run the Unity Hub program.

Starting our project through Unity Hub

At this point, you have installed Unity 2020 LTS, registered as a Unity user, and have a shortcut to run the Unity Hub program.

Unity Hub is mainly used to keep a collection of the different versions of Unity installed, as well as a list of the projects that are on your system and in the cloud with Unity's own cloud storage software.

When you run Unity Hub, please make sure you are signed in as a registered user, as discussed in the previous section.

Load up Unity Hub and sign in, if you haven't already:

  1. The following screenshot shows you where to sign in on Unity Hub:
Figure 1.9 – Sign in to your Unity account

Figure 1.9 – Sign in to your Unity account

  1. Once signed in, go to the Projects tab (denoted with 1 in the following screenshot) at the top left of Unity Hub and select the down arrow next to New (denoted with 2) to pick the version of Unity to run this project, as shown:
Figure 1.10 – Create a new project in the Unity HUB

Figure 1.10 – Create a new project in the Unity HUB

  1. From the dropdown, you should see a copy of Unity 2020 LTS, which we installed from the archive link in the previous section. Select Unity 2020 LTS.

The last screen before the Unity Editor is launched is a selection between two templates:

  • 3D: The Unity Editor starts in a three-dimensional view.
  • 2D: The UnityEditor starts in a two-dimensional view.

Let's create our Unity project:

  1. Select 3D.
  2. Give your project a name. I'm calling mine KillerWave.
  3. Add a location where you want the Unity project to be stored.
  4. Click Create project:
Figure 1.11 – Select a 3D project template with a name and location to create a project. Be sure you have Unity 2020 LTS selected at the top of the Hub window

Figure 1.11 – Select a 3D project template with a name and location to create a project. Be sure you have Unity 2020 LTS selected at the top of the Hub window

It doesn't really matter which of the templates you pick, as once the Unity Editor loads, all that we need to do to change between 2D and 3D is press 2 on our keyboard, or click the 2D button at the top of the Scene window, as in the following screenshot:

Figure 1.12 – 2D and 3D mode in the Unity Editor

Figure 1.12 – 2D and 3D mode in the Unity Editor

After clicking Create project, you are presented with the Unity Editor.

Next, we will remove Unity's current folder setup and scene and replace it with our own by follow these steps:

  1. In the Project window, select the Scenes folder and press delete on your keyboard.

A window will appear asking to confirm deleting the scene.

  1. Click on Delete.
  2. At the top of the Unity Editor, select File | Save As...
  3. Be sure your project is being saved in your project's Assets folder.
  4. Name the scene testLevel.
  5. Click on Save.

Let's now go in a little deeper and check our account to find out more information about our project by using the Unity Dashboard.

The dashboard

With your Unity account, you have access to more information about your account and other services, such as Cloud Build. In a potential exam question, you may be asked what and where the dashboard is and where you would find details about your projects. Here is how you access the dashboard:

  1. Click on the Dashboard link in the top-right corner of the Services window:
Figure 1.20 – Location of the Dashboard link

Figure 1.13 – Location of the Dashboard link

  1. Within the Unity Dashboard browser, you will be presented with a series of options and details specifically to do with Analytics (in Chapter 11, Storing Data and Audio Mixer, we discuss storing/manipulating online data), cloud building (briefly mentioned in the following information box), and more:

Figure 1.14 – Unity Dashboard with Project Members highlighted

This is the Unity Dashboard where Unity has multiple services to help your game become more popular with your audience. We can monitor players' performance and look for any issues within our game. Without getting too distracted with the Unity dashboard as a whole, we are automatically loaded into our project (Killer Wave). Here, we can check useful things such as who is working on the project, and can add/remove members.

Cloud Build

Build your pushed projects online for multiple platforms (for example, Android, iOS, PC, and so on). This saves you and others in your team the hassle of switching platforms, building on a local machine, and waiting until you can start using your Unity project again. If developers in the same team are all building slightly different versions of the same build, this can be inefficient and cause issues. With Cloud Build, you are given a build number, which helps you keep tabs on the current version build.

Wow, we have covered a lot and it's only Chapter 1! You have covered some of the most important stuff that isn't common knowledge when it comes to being a Unity developer. When I started as a developer, I thought it was just about getting cubes moving and jumping and firing other cubes and then prettying them up. In some ways, it is, but we need to make sure we avoid a lack of structure in Unity projects as things can fall apart quickly without it, especially when it comes to expanding a project. We will dig deeper into all of the things we have mentioned in this chapter, but for now, let's just recap what we have covered.

Summary

In this chapter, you were introduced to the six core objectives of the exam. You may have skipped on to the final mock exam and scored well, and you may want to increase your score and carry on with the project that we are gearing ourselves up for. With regards to the project, we have an idea of a few design patterns that we can implement as the project goes on (such as Singleton for manager scripts) and these patterns will be built within the game framework. We know what the SOLID principles are, and we mustn't forget them as our project expands.

In the next chapter, we are going to start setting up our camera and light in the testLevel scene. We'll also bring in our player ship and hook it up with some controls so that we can move and shoot bullets. The first enemy will be imported with its own wave attack pattern. We will also be looking into what scriptable objects are and how they can benefit programmers and designers.

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

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