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://certification.unity.com/products/certified-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 understand 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'sLearning C# by Developing Games with Unity 2019book first (https://www.packtpub.com/gb/game-development/learning-c-developing-games-unity-2019-fourth-edition). Be aware that this exam is based on Unity 2017.3 and it hasn't been updated since it's launch, but it's definitely the best place to start if you are working with the fundamentals of Unity.
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 upour 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 2017.3
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 that it's highly likely it will 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:
- Recognize concepts associated with the uses and impacts of version control using technology such as Unity Collaborate.
- Recognize techniques for structuring scripts for modularity, readability, and reusability.
Check out the following video to see the Code in Action: https://bit.ly/2VjmVtL.
The six core objectives
The exam will mainlyfocus on scripting and the use of Unity'sApplication 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 up 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 or light. Each component will have a list of properties and a camera that you can zoom in and out, change the focal length, and edit the details. Another component is "physics"—what happens if one game object collides with another? What would you want the game object to do? Will it blow up? Will it collect the other game object? Will it knock it out of the way? 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 cargame 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 have 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 less common components, such as 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 is, 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 onto 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 book their work in and book it out. 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. Unity also has its own version that they would really like you to use. We will be covering Unity Collaborate in this chapter, which is a program that lets you book your work in, book it out, alter it, make some mistakes, and fix it all in the end.
To pass the exam, you need to know how to do the following:
- Recognize concepts associated with the uses and impacts of version control using technology such as Unity Collaborate
- 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 obviouslybe 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, 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 on to compare in the exam. The first pattern is Builder, so let's check it out.
The first design pattern from the gang of four is the Builder design pattern. This design is typically used to create alterations on an object instead of repeating code. For example, if you have a car, you might want to install a different engine, paint it a different color, or install a sat-nav. The Builder design takes care of these alterations.
The following diagram shows how the Builder design pattern works:
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.
The Singleton design pattern isn't really much of a pattern as such, but more 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. There is only one type of Singleton script; it exists in your Unity scene and never gets removed. If it does get removed or it doesn'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 why it's called Singleton because there should be only one of its type.
So, this sounds like a good design pattern. However, it is argued that a 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, a 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:
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.
The Abstract Factory pattern is designed to cover common traits that multiple objects share. For example, if I wanted 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:
The next design pattern is Prototype. This is useful for creating clones of an existing object.
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:
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 amount of game objects to save system resources.
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:
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.
This pattern is oftenimplemented 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 monobehaviour, 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 introduces flexibility with your code without having a knock-on effect on other properties.
The following diagram shows how Dependency Injection simply supplies one object to another:
Elements of this design are implemented in the project and are referenced as a Dependency Injection pattern in practice.
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 into 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, so consider them a guideline to 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—your SOLID principles. These principles are guidelines that remind OOP programmers of what you should be thinking about when coding your projects. They outline what you should and shouldn't be doing with your code. Yes, you could ignore 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 notfollow 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 we 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 onto the "O" in SOLID—the open/closed principle.
Scripting should be open to being extended but closed for modification.
Create a class that supports extra work applied to it without having to constantly revisit and modify your original class. For example, if I had a spaceship that fires a bullet and I wanted to add different types of weapons, I want to avoid adding any more to the original script. If I wanted 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. Also, if the class is encouraged to grow and cater to all these weapons, you will start violating thesingleresponsibilityprinciple.
Let's now move onto 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, you would still have to implement them 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 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 brief for making Killer Wave.
Game design brief
Title: Killer Wave
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 amount 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-looking 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 the surroundings of 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 code is 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.
To start off, we will break down what we are going to need for the game. The first things I tend to think of is 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:
- SceneManagerwill globally tell all the classes what scene the user is on (for example, the title screen, level 1, the menu screen, and so on).
- GameManagercommunicates with all the game objects and communicates with other managers; it is in charge of the game's loop process.
- ScoreManagerreads and writes the score data when offline and updates the score UI.
- PlayerShipBuildreceives and sets customization settings to PlayerSpawner.
- EnemySpawneris similar to PlayerSpawner but it can manage all different types of enemies.
- Enemyrefers 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.
- EnemyBullettravels at a set rate and removes the player after a set time or if it makes contact with the scenery.
- PlayerSpawnerlaunches the player in a certain location of the screen and keeps its hierarchy in order.
- Playerfires bullets, receives input controls from the user, and is removed if contact is made with the scenery, enemy, or enemies' bullets.
- PlayerBullettravels at a set rate, removes and damages the enemy, and removes itself after a set time or if it makes contact with the scenery.
- ShopPiecehandles the content of the player's ship upgrade selections.
- SOShopSelectionholds 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.
- IActorTemplateisn'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.
- Additional enemy/player behavior: It is possible to have an enemy that might require more functionality than it has already been given. The same applies to the player. As a precaution, I have sketched in additional classes that are responsible for the extra rotation of the ship, extra particle effects, extra guns, and more.
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://subscription.packtpub.com/book/application_development/9781789809770/1/ch01lvl1sec12/understanding-behavioral-uml-diagrams). 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:
Each gray box represents a class that is mentioned in the preceding list; the lines between each box indicate the inheritance of that class. ThePlayerSpawnerclass, 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 weare 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 2017.3. 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 havea free account with them and a copy of Unity installed. If not, here is the license activation guide from their 2017.3 documentation: https://docs.unity3d.com/2017.3/Documentation/Manual/LicensesAndActivation.html
Once you have created a free account, you can now download the Unity Hub. This will hold a reference to the version of Unity you have installed and also our projects.
You can download and install the Unity Hub from here: https://unity3d.com/get-unity/download
Once you have done that, we can grab a free copy of Unity 2017.3
You can download Unity 2017.3 from their archives:
- Go to https://unity3d.com/get-unity/download/archive.
- Click on the Unity 2017.x tab
- Scroll down until you see Unity 2017.3.0, then click on the Unity Hub button to the right of it.
- Follow the rest of the instructions to download Unity 2017.3.
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 one of two from its 2017 installation menu. It is recommended that you install Microsoft Visual Studio Community 2017 out of the two as MonoDevelop is phased out from the later versions of Unity. All our scripting will take place in this application. The following screenshot shows the recommended IDE selected:
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 2017.3, 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 let's sign in, if you haven't already:
- The following screenshot shows you where to sign-in on Unity Hub:
- 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:
- From the dropdown, you should see a copy of Unity 2017.3, which we installed from the archive link in the previous section. Select Unity 2017.3.
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 Unity editor starts in a two-dimensional view.
Let's create our Unity project:
- Select 3D.
- Give your project a name. I'm calling mine KillerWave.
- Add a location where you want the Unity project to be stored.
- Click Create:
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 press the 2D button at the top of the Scene window, as in the following screenshot:
After pressing Create, you are presented with the Unity editor.
Next, we will talk about version control and introduce Unity's Collaborate system. Please go through this section, as it's highly likely it will be in your exam.
Collaborate is a form of version control, which means multiple people can work on the same project at the same time. It's similar to Git, Perforce, and Mercurial. All project files are stored locally but can then be pushed to an online server (the cloud) where all members of the project can pull your changes to their local machine and vice versa.
Similar to other types of version control, Collaborate has the following features:
- Add: Include your local files to the project to be pushed onto the cloud.
- Conflict Resolution: Change or update yours or someone else's scene file or code when work is merged together.
- History: Go back to a previous push to amend an issue.
- Publish: Push your work onto the cloud for everyone in the project to share.
- Pull: Pull work from the cloud to your local machine.
Collaborate also has a repository, whichis where your project is stored.
Let's move on and set up a Collaborate project in Unity.
Setting up Collaborate
To set up Collaborate for our project, follow these steps:
- Make sure you have signed in to your Unity account, as mentioned previously.
- Open the Services tab. You can do this by clicking on Windows and then Services, or you can click on the cloud in the top-right corner of the editor:
- Click on the Create button.
- With the Services tab open, change theCollaborate option to ON:
- Notice how at the top of the Unity editor, the Collab tab has a green circle with a white tick:
- Click on it and it will let you know whether you are up to date and whether there are any files that need publishing. It also tells you whether anyone on your project has published anything.
- Next, save your scene. Name it testLevel.
- Notice how your saved scene has a blue square with a plus sign. This indicates that you have a file that you can publish to the cloud:
- The Collab tab at the top has also changed from a green circle with a white tick to a blue square with a white arrow pointing upward. This means you have a new file that can be pushed to the cloud. As with any version control software, multiple files can be published in one go; you don't need to push each file individually.
- Click on the Collab tab.
- Click in the Describe your changes box here and as it prompts, provide a description. Then, click Publish now!, as in the following screenshot:
- The file will push to the cloud and your Collab tab will go back to the green circle with a white tick.
Congratulations, you have created and pushed your first change to Collaborate. This is the most common use of making a change—giving it a name and clicking Publish Now! to save your changes. Let's continue with the other features of Collaborate. Next, we will look at files that aren't of concern to us and can be left out of the project.
Ignoring files and folders
Collaborate creates a file that contains a list of file types and folders that you are likely not going to want to push to the cloud. For example, an Editor folder containing files specifically for your editor might not need to be shared with other members of the project:
- The ignore file is located outside of the Assets folder. It's default name will be .collabignore.
- Locate it and open it in a text editor to view the files and folders it's currently ignoring.
- If you wish to add more file types to ignore, you can, but I wouldn't recommend doing so unless you are sure you don't want to update specific file types.
- Close the text editor.
Let's keep going and look at what to do when we make a mistake and we need to revert the changes. We all do this!
Imagine if we made a mistake in a project—for example, we deleted the testLevel.unity file and pushed it on to the cloud. This can be amended by doing the following:
- Go to the Services tab (the cloud button in the top-right corner of the editor).
- Select Collaborate.
- Under CollabHistory, click on Open the history panel.
- You will be presented with your pushes with the description you named when it was done and how many files were pushed. Also, a drop-down symbol will show the filenames that were pushed:
- Click the Restore button to bring back testLevel.unity. Any changes that haven't been published will be removed.
Now that you know how to revert your mistakes, let's now go in a little deeper and check our account to find out further information about our project with the Unity dashboard.
With your Unity account, you have access to more information about your Collaborate 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 Collaborate projects. Here is how you access the dashboard:
- Click on the Go to Dashboard link in the top-right corner of the Services window:
- Within the Unity Dashboard browser, you will be presented with a series of options and details specifically to do with Collaborate, Analytics, remote settings (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:
The preceding screenshot shows the Settings tab is open and Users (on the left-hand side of the screen) is where team members can be added/removed and given certain levels of access relating to the project. We don't need to go into any further detail about this, but you just need to be aware of where these extra editions are based.
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 justabout getting cubes moving and jumping and firing other cubes 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.
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. We also know how to use Unity's own version control platform, Collaborate, and we know that we can build our projects in the cloud, which is ideal for team projects and multi-platform projects.
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.