Unity For Software Developers
- Descrição
- Currículo
- FAQ
- Revisões
Welcome to Unity For Software Developers, the only course you need to learn how to apply your skills as a developer to making games with Unity. This course is created by Charles Amat, host of the Infallible Code YouTube channel where over 61,000 devs learn how to program games with Unity!
This course assumes that as a developer your time is valuable and seeks to present its subject matter in a clear and concise presentation over the course of just under three hours allowing you to skip the fluff and get start quickly. This is not a course to learn what a variable or function is and if you have zero programming experience, you should study some programming fundamentals before taking this course.
-
The course is taught by Charles Amat who is a senior developer at Thousand Ant, a studio who develops Unity content for Unity Technologies themselves and creates educational material for companies like Microsoft and Google.
-
The course has been updated to be 2022 ready and you’ll be learning the latest tools and best practices for making games in Unity.
-
This course doesn’t cut any corners, there is a custom 3D demo project called “The Norsemen” including a rigged and animated character and dozens of 3d assets which you can use in your own prototypes.
-
The curriculum was written and developed by Charles together with Matt Schell, the former head of Online Evangelism for Unity Technologies who created many of the most popular Unity video tutorials on their own YouTube channel.
-
We’ve helped millions of learners learn how to program in Unity via our YouTube channel and many have gone on to change their lives by becoming professional game developers.
We’ll take you step-by-step through engaging video tutorials and teach you everything you need to know to apply your skills as a developer to making games in Unity.
The course includes over 3 hours of HD video tutorials and a custom made, exclusive 3D survival game demo with animated character and example source code.
Throughout this course, we cover a massive amount of tools and technologies, including:
-
An exclusive 3D viking survival example game “The Norseman” with art, animation and shaders using Unity’s Universal Render Pipeline
-
Unity with a focus on C# scripting
-
MonoBehaviours
-
ScriptableObjects
-
Script interactions
-
Profiling for performance
-
Managing your Unity project to build scalable games
-
Using Git version control with Unity
-
Namespaces
-
Assembly definitions
-
Custom Unity packages
-
Automated testing with play and edit mode tests.
-
Simple inventory system
-
Example combat implementation
By the end of this course, you will be well grounded in Unity’s technical fundamentals and ready to start making your own games.
Sign up today, and look forward to:
-
HD video lectures
-
Clean, well-structured example code
-
A high quality custom built 3D demo project
-
A downloadable local Git repository with each module as a separate branch
REMEMBER… we’re so confident that you’ll love this course that we’re offering a FULL money-back guarantee for 30 days! So it’s a complete no-brainer, sign up today with ZERO risk and EVERYTHING to gain.
So what are you waiting for? Click the buy now button and get started on your game development journey!
Who this course is for:
-
Software developers who want to learn Unity without having to cover basic programming concepts for beginners
-
If you want to learn modern Unity best practices designed for building scalable, clean projects and not game-jam example code
-
If you want to learn game development using professionally created art and animation instead of boxes and cubes
-
If you want to take ONE COURSE and learn everything you need to know to get started programming Unity games right away in a clean, concise, professional and well-structured course.
-
1IntroductionVídeo Aula
Introduction
Unity is one of the leading video game engines on the market
It’s been used to make tons of indie hits like Cuphead, Hollow Knight, and Kerbal Space Program
It’s also been used to create AAA titles like Hearthstone and Pokemon GO
Best of all, Unity is free to use and extremely easy to get started with
You can download it right now and have a working prototype in a couple of hours
That’s why so many professional software developers are trying to break into game development
C# — the programming language used in Unity — is easy to learn and you only need rudimentary development skills to
With a language as straightforward as C# and the programming skills needed to make development work your day job, it just makes to grab of a copy of Unity and make the game of your dreams
So why does it seem so hard to actually finish a game?
Unity — and game development, for that matter — has a unique learning curve
If you follow any of the multitude of tutorials on YouTube, you’ll be able to recreate some pretty impressive mechanics with very little effort
And if you combine enough of these mechanics into one project, you can put together something that feels pretty close to a finished game
But great games aren’t made from a few working mechanics
The elements that’ll make your game something worth playing will typically be born in the mid to late stages of your project
That’s because a large part of developing fun games is in the iteration of content and features based on the feedback from player testing
But pushing through the beginning phase of a project into the phases where iteration can take place can be extremely challenging
And once you’re there, it can be even harder to keep your project in a working state long enough to release it
That’s because, at the core, games are just like any other piece of software
All software projects start with a set of requirements that evolve and grow over time
This fact is what makes way for the one thing that plagues every software project from the start: Entropy — that gradual decline into disorder that kills many projects in their tracks (including my own)
The good news is that it doesn’t have to be that way
With a solid understanding of Unity’s scripting layer and the basics of how to organize your source code, you can create projects that are designed to be finished
And that’s exactly what I’m going to show you
In this course we’ll be creating a viking survival game
As we work through each feature and mechanic, I’ll give you the complete rundown on scripting in Unity so you can write code and implement game mechanics more effectively
Then I’m gonna show you how to organize your project so it’s easy to maintain and can scale to meet an ever changing set of requirements
Finally we’ll write some automated tests so we can be sure that our project always works and that we aren’t shipping a game full of bugs
The skills you learn from this course will help you become a more well-rounded game developer and give you the tools and confidence you need to finish your games
-
2Welcome to the CourseVídeo Aula
Meet Your Instructors
Welcome to the course and thank you for choosing us to invest in your game development career or hobby
My name is Charles and I’ll be your course instructor
I’ve been a professional software developer for over 10 years and a freelance/hobbyist game developer for about 6
I’m also the host of Infallible Code, a YouTube channel that I created to help other software developers translate their programming skills into making games
And my name is Matt Schell
I was head of online evangelism at Unity Technologies, the maker of the Unity game engine and worked there for six years on creating tutorial content. I've spent a lot of time thinking about how to teach people Unity well, and am bringing that expertise to bear on this course. I'll be working behind the scenes with Charles to make sure that this course is as good as it can be.
What to Expect From This Course
Over the course of the next 4 chapters we’ll be creating a Viking survival game
We’ll start by creating a brand new project from scratch
Then we’ll implement some basic mechanics like interacting with the environment and adding items to our player’s inventory
Once we’ve established some gameplay, we’ll reorganize our source code so it’s resilient to change and can scale with new requirements
Finally, once our project is solid we’ll write some automated tests to keep it that way
At the end of it, you’ll have a working survival game that you can play and share with your family/friends
You’ll also have a stronger understanding of how to approach game development in Unity and the tools and confidence you need to finish your games
How to Use This Course
First and foremost, we believe that hands on learning is crucial to owning the knowledge that we want to teach you
Therefore the finished project is available for download
You can grab it right now and play around with it
On top of the finished project, each section will also have a downloadable project file associated with it that places you exactly where you need to be to follow along with that section
These are super useful if you accidentally introduce a bug and need to get back on track
Alternatively, the finished project also has a local git repository
Each commit is associated with a section of the course
You can follow along by checking out each section
Or you can create branches and experiment with your own implementations and mechanics
-
3Setup Your EnvironmentVídeo Aula
Before we dive into the course content, we’ll need to set up our environment for Unity development.
That’ll include installing Unity Hub to manage our Unity installations, installing the version of Unity that we’ll be using throughout the course, and installing and configuring Visual Studio so we can write, debug, and unit test our code.
Head over to unity.com/download to grab a fresh copy of Unity Hub.
When you get there click on the “Download for Windows” button, or “Download other version” if you’re on another platform, to download the latest version.
Once it’s downloaded, run the installer, follow the prompts, and open Unity Hub on your Desktop.
Unity Hub is your launchpad into working with Unity.
The “Projects” tab keeps a running list of all of the active projects on your computer.
You can easily search for a specific project by name, and change the editor version or platform without having to open up Unity.
You can also open the project in your file explorer and add command line arguments
Like the “Projects” tab, the “Installs” tab keeps a running list of all the active Unity installs on your computer.
If there aren’t any listed, you can manually locate them on your hard drive or install an official release right from within the application.
For this course we’ll be using the latest version of 2020 LTS.
If you don’t have the latest version of 2020 LTS, go ahead and install it now.
For guaranteed compatibility with the course make sure to use the exact same version of the Unity editor we used which is Unity LTS 2020.3.22f1 Later versions should also work, but there may be differences or incompatibilities.
You can download this version from: https://unity3d.com/de/get-unity/download/archive
Next let’s install Visual Studio.
In many cases, you may be able to skip this step since Unity will install it automatically or you may already have it installed.
If not, go to visualstudio.microsoft.com and pick up a copy of the latest version.
The installer generally takes a minute or so to download the necessary files, but once it’s done you’ll be presented with a menu to select which features you’d like to include in your installation.
Scroll down to the Gaming section and tick the box titled “Game development with Unity”.
This will include a plugin that’ll allow Visual Studio to better integrate with Unity, which we’ll see as we move through this course.
Go ahead and click on “Install” and wait for it to finish.
If you already had Visual Studio installed but aren’t sure if you included the “Game development with Unity” package, there’s a way to install the integration after the fact.
First open up Visual Studio and select “Continue without code” on the launchpad screen.
Then click “Tools” in the top navbar and select “Get Tools and Features”.
This will bring up the menu to select which features you’d like to include in your installation.
Scroll down to make sure that the integration has been selected and install it if it isn’t.
-
4The Norseman DemoVídeo Aula
In this section we’ll be creating the base project that we’ll be working on for the rest of the course, the one that’ll eventually become the Norseman demo.
We’ll talk a little bit about how to follow along with this course using the downloadable project files and the local git repository that’s packaged with them.
Start by clicking the “New Project” button at the top right corner of the application.
Here we have a number of templates to choose from.
These templates are starting points for various types of projects.
When you choose one, your project will be created with a specific set of packages and will sometimes include custom settings, configuration files, and additional resources.
For our Noreseman demo we’ll go ahead and select the 3D core template.
With our template selected, let’s be sure that the Editor version is set to the latest version of 2020 LTS, and then let’s name our project.
Click the “Create Project” button and wait for the project to open up in Unity.
We need to make sure that Unity is using Visual Studio as it’s default script editor.
Click on “Edit” in the top navigation bar and select “Preferences” to open up the editor preferences window.
Then click on “External Tools” in the sidebar and make sure that the “External Script Editor” dropdown is set to the correct version of Visual Studio.
If it isn’t, click on it and either select Visual Studio or click “Browse” to locate it manually on your hard drive.
Next let’s set up the file structure for our project.
Many developers simply begin creating folders for each category of file right in the root of their Asset folder, which we can see here in the project window.
By default Unity places a Scenes folder in the root with the sample scene that we currently have open in the editor.
The problem with this approach is that many assets that you download from the asset store will also place their files in this root directory.
I tend to place all of my files in a completely separate folder called “_Project”.
Create a folder called "_Project"
And drag the Scenes folder into our new project root.
And while I encourage you to continue to build on this exact project, there will be a few times throughout the course where you’ll need to access our downloadable project files.
That’s because we are playing the role of the developer.
When that happens, you’ll need to download the correct project folder or check out the corresponding commit in order to access those changes.
And here’s how you do it.
At the beginning of each section, I’ll provide access to downloadable project files that reflect the state of the project for that given section.
That way you can easily follow along without having to worry about your project keeping up.
If you encounter bugs or fall behind on the hands-on portion of the course work, you’ll always be able to download a snapshot of the project at whichever section you’d like.
In addition to that, we have the entire project as a local git repository.
If you’re familiar with git, you can use the command line or the repository browser of your choice to review all of the commits to see how they line up with each section, and you can pull the one that corresponds to the section you’re currently on.
-
5The Demo Git RepositoryTexto
-
6Scripting OverviewVídeo Aula
The Unity engine is built with native C and C++ but it’s scripting layer uses .NET
.NET is an open source development platform for building apps
Applications that run on the .NET platform are built using one or more of the .NET implementations
E.g., Mono is an open source implementation of .NET[source]
Unity uses it’s own custom .NET implementation that supports .NET Framework 4.x and .NET Standard 2.1, which are both .NET platform API levels
C# is the primary programming language used to write scripts
Unity’s .NET implementation supports all of C# 8
When you build your project, Unity uses one of two compilation styles to compile your code. This is based on the scripting backend of your project:
Mono: uses just-in-time (JIT) compilation to compile your code into CIL that can be interpreted by each platform at runtime
CIL stands for “Common Intermediate Language”
The .NET runtime environment compiles CIL instructions into native code just in time for it to be executed
IL2CPP: uses ahead-of-time (AOT) compilation to compile your code into C++
In this course, we’ll be using the Mono scripting backend and the .NET 4.X version level of .NET
The compiler converts your C# code into CIL code that it compiles as one or more DLLs
Common Intermediate Language (CIL) code gets compiled into machine code at runtime so it can run on many different platforms
In .NET, DLLs represent assemblies, which are basically components that the.NET runtime knows how to execute
-
7Your First ScriptVídeo Aula
Your First Script
We’re going to start by creating a simple script to get our hands moving
We’ll review what we did in the next section
Give an overview of the project and the scene
We have a functional scene with some basic mechanics, but this is a survival game so the player needs to be able to carry items in an inventory
We’ll add this feature creating a new script and adding it to the scene
-
8Gameobjects & MonobehavioursVídeo Aula
What did we do in the previous section?
We created a C# class that extends the MonoBehaviour class
Classes that derive from MonoBehaviour are called Components
So we essentially created an Inventory component
Then we attached the Inventory Component to the Player GameObject
GameObjects are the building blocks of your scenes in Unity
They can represent characters, props, scenery, cameras, waypoints, and more
Each GameObject’s functionality is defined by the Components that are attached to it
Refer to the Player GameObject that outputs the contents of it’s inventory to the Console because of the Inventory Component
Every Gameobject has at bare minimum a Transform component with position rotation and scale that can’t be removed.
There are a couple of ways to execute code in Unity without attaching a component to a GameObject
E.g., RuntimeInitializeOnLoadMethodAttribute
But they’re recommended for very special use cases only, so we won’t be covering them in this course
MonoBehaviour is the base class from which every Unity script derives
It’s what allows you to attach your code to GameObjects
It gives your code access to Unity events that you can hook into
Refer to the Start method in the Inventory class that we created in the previous section
Mention that we’ll cover those events in a future section
When referring to MonoBehaviour-based classes I switch between two different terms:
Scripts when I’m referring to the code or talking about them in the code editor
Components when I’m working in the Unity editor
Open the example project in File Explorer and navigate to folders and open files that are relevant to the lessonNow that we have a better understanding of how Unity works, let’s give some more functionality to the player
We gave the player an inventory but they currently have no way to add items to it
Let’s write some logic to let the player interact with items in the environment
This will serve as a base for the mechanic of picking up items and adding them to the player’s inventory, which we’ll expand on in the next section
-
9Composition Vs InheritanceVídeo Aula
Unity’s Component-based approach to giving GameObjects functionality gives us the opportunity to take advantage of a concept called Composition, instead of, or in complement to, the pattern of Inheritance
Inheritance and Composition are techniques for establishing relationships between classes and objects
Inheritance is the mechanism of basing one class on another class
If you’re an Object-oriented programmer (OOP), you should already be familiar with using inheritance to structure your code into hierarchies
Our component classes inherit from MonoBehaviour
Composition is used to define a class as the sum of its parts
Behavior is created by composing a class from multiple objects
GameObjects are a sum of their components
While inheritance is a common approach to development, classes that are created through inheritance are considered tightly coupled to their parent classes
This is one factor that can lead to spaghetti code
Spaghetti code is basically messy code lacking the structure required to scale effectively
It tends to be problem in Game Development due to how often objects tend to need to collaborate with each other
That’s not to say that inheritance is bad
Inheritance and composition are compatible and complement each other
However, we are going to lean into using composition in an effort to combat spaghetti code in our project from the outset
Let’s review the composition vs inheritance concept using a simple example
Building on the code we’ve been working on, let’s implement some logic so that our player can add items from the environment into their inventory
-
10Anatomy of a MonoBehaviourVídeo Aula
Anatomy of a MonoBehaviour
Before we keep going, let’s pause to take a closer look at the anatomy of a MonoBehaviour
MonoBehaviours are different from POCOs in that they cannot be instantiated using “new Object” and also do not support constructors
They must be attached to GameObjects and once they are are affected by Unity’s callbacks
When you implement MonoBehaviour, you get access to methods that let you hook into Unity
You implement these methods and Unity calls them either once, during every frame, or when specific events occur (or when a criteria is met)
Visual Studio
Display the Inventory class
We’ve already used the Start method in our Inventory component
Start is only called one time, during the script initialization phase
Webpage
This flowchart represents the lifecycle of a MonoBehaviour
It’s split into sections based on Unity’s lifecycle
Initialization, Physics, Input Events, Game Logic, Scene Rendering, Gizmo Rendering, GUI Rendering, End of Frame, Pausing, Decommissioning
Here are the most common callbacks we’ll use:
Awake: Called once when the script instance is being loaded
Typically used to initialize variables or game state before the game starts. Runs before Start, often use to prepare references that will be used by other callbacks.
OnEnable: Called next, when a GameObject is enabled, which may happen multiple times in an objects lifecycle unlike Start and Awake.
Start:
Called after Awake
Update: Called every frame at a variable frame rate
FixedUpdate: Called at a fixed frame rate in lockstep with the physics simulation.
OnDisable: Called when a GameObject this component is attached to is disabled (can be called multiple times in objects life)
OnDestroy: Called right before an object is destroyed or de-instantiated, called only once.
Physics callbacks: We’ll discuss these later but are called by events in the physics system like collisions.
-
11Script InteractionsVídeo Aula
Now we know how MonoBehaviours work—but how can we get them to work together?
Some scripts can function in isolation (e.g., high-level managers or small helpers)
Most mechanics require two or more scripts to collaborate with one another
In this section, we’re gonna cover all the ways that MonoBehaviours can interact with one another
In our game, interactable GameObjects are composed of the Interactable component and a set of InteractionHandlers components
We’ll use this as an example to cover each method
Method 1: Editor Properties
Right now, the references to the handlers can be set from the editor
This is possible because Unity exposes public fields in the editor
You can also expose private fields in the editor by marking them with the [SerializeField] attribute.
Exposing a private field in the editor allows a reference to be set at edit-time by the user but no other class can modify the value.
This allows you to avoid making fields public just to be able to set them in the editor, keeping code cleaner
This is another technique you can use to avoid spaghetti code
In both cases, the type must be serializable. If it isn’t, Unity won’t expose them in the editor.
Serialization is the process of converting an object into a stream of bytes to store the object or transmit it to memory, a database, or a file. Its main purpose is to save the state of an object in order to be able to recreate it when needed. The reverse process is called deserialization.[Source]
You can enable serialization on classes and structs with the [Serializable] attribute
Only non-abstract, non-generic custom classes can be serialized
Method 2: GetComponent
If you want to access scripts programmatically, you can use the GetComponent methods that are a part of the Component class’s API[Source]
This can be a great way to set references we don’t want set from the editor
It can also be used to grab dynamic references to other components at runtime based on interactions that can’t be predefined at edit time, like getting a reference to an instantiated bullet or enemy
All methods return one or more components matching the declared type if attached (or null if not). Disabled components are returned, as well.
GetComponent: returns the first component that is found (order is undefined)
GetComponents: returns a list of components
GetComponentInChildren: returns the first component that is found in the GameObject or it’s children using depth first search
GetComponentsFromChildren: returns a list of components found on both the GameObject and any of its children (works recursively).
GetComponentInParent: same as GetComponentInChild except resources upwards
GetComponentsInParent: same as GetComponentsInChild except resources upwards
Method 3: Runtime Callbacks
Another way to access scripts at runtime is using physics-based methods and runtime callbacks
This is a good approach to use for mechanics that are based on interactions (e.g., a bullet hitting the player or an enemy)
This approach depends on Unity’s built-in Physics system so all GameObjects must have colliders
Physics-Based Methods
*Cast (e.g., Raycast & BoxCast): returns hit information that includes the collider that the shape cast collides with in the scene
Overlap* (e.g., OverlapBox & OverlapSphere): returns all colliders that overlap with the given shape
Runtime Callbacks
OnCollision* (e.g., OnCollisionEnter): called on a script when a collision is detected. The collider of the other GameObject is included in the method’s signature.
OnTrigger* (e.g., OnTriggerEnter): same as OnCollision* except used for triggers. The colliders must be configured as triggers.
-
12ScriptableObjectsVídeo Aula
Apart from the MonoBehaviour class, Unity provides another class to derive from called ScriptableObject
Scriptable objects act as data containers that can be used to store data independently of class instances[Source]
Scriptable objects are saved as assets that scripts can reference in their logic
Instances of scriptable objects are typically referred to as assets
To recap on terms, while in the Unity editor, we call MonoBehaviour-based classes “components” and ScriptableObject-based classes “assets”
They help avoid creating unnecessary copies of data that need to be accessed by multiple objects in the scene, which can reduce memory usage
They also help to decouple game logic from game data, which makes your code easier to scale and maintain
Scriptable objects can hold information like configurations, settings, and other game data
Let’s use scriptable objects to improve the maintainability and scalability of the inventory logic
The inventory references an array of strings that represent items
Magic strings are a code smell because they’re hard to keep track of and they’re prone to error
We’ll refactor the code to use scriptable objects instead of magic strings
-
13CoroutinesVídeo Aula
Coroutines
To briefly summarize what we’ve learned so far about scripting in Unity, Unity has complete control over the game loop which we can hook into using the Update methods of our MonoBehaviours
Most of the code we write will run once every frame
That means that any logic we write will need to execute within the span of a single frame
But what if you need to implement a behavior that can’t execute to completion in a single frame?
You need to track the time over which that behavior needs to execute
This can add unnecessary complexity to otherwise simple logic
As a simple example, let’s say we wanted to fade an object out when the player picks it up
Tutorial 1
This approach works but it requires an additional field and logic to track the progress of the effect
This increases the complexity of the script
It’s now responsible for (1) fading the object and (2) keeping track of time
This script is relatively simple so it isn’t very noticeable, but more complicated scripts will be much harder to work with
That’s where Coroutines come in!
A coroutine is a function that has the ability to pause execution and return control to Unity but then to continue where it left off on the following frame[source]
Tutorial 2
Unity provides a set of classes that all inherit from YieldInstruction which, when returned from a coroutine, tell Unity how long to wait before resuming execution
WaitForSeconds: suspends execution for the given about of seconds
WaitForFixedUpdate: waits until the next fixed frame rate update
WaitUntil: suspends execution until the supplied delegate evaluates to true
WaitWhile: suspends execution until the supplied delegate evaluates to false
-
14Unity Performance 101Vídeo Aula
Now that we’ve written some code, let’s talk about performance
If your game is slow, no one will play it, so you need to optimize your code to run well on your target platform(s)
This applies to other aspects of your game, as well—like 3D models and VFX—but we’re going to focus on code performance
Performance is important but don’t overdo it or optimize prematurely[Source]
In this section, we’re going to cover some factors related to both .NET and Unity that you should consider when you write game code
You need to know how to use the profiler before you can effectively optimize your code
The profiler is a tool that provides performance information about your game
You can run it in the editor to get an overview of resource allocation during development
Or you can connect it to devices on your network to see how your game performs on your target platform/device(s)
Let’s see the profiler in action
Our profiler window set up to show us the performance of our scripts, so let’s take a look some things you should consider when writing code in Unity
At a high level, the main things you want to keep in mind are expensive/long running logic, garbage collection, and Unity hot paths
We can use the Interactor class as an example
Right now our logic is well written and performant, however we could have written it in a different way
Let’s use the profiler data to get a better understanding of why our code is under performing
Expensive/Long Running Logic
This one is self explanatory—we only have a few milliseconds of computation time per frame, so use it wisely
Avoid expensive loops
Don’t search the scene
If you need to perform an expensive computation, try to pre-compute the values ahead of time or perform computations while the scene is loading
(i.e., In the Awake or Start methods)
Garbage Collection
The hierarchy view in the profiler has a row called “GC.Alloc” that takes up frame time and affects the GC Alloc column
GC.Alloc stands for garbage allocations, which is related to garbage collection in .NET
Garbage Collection is a form of memory management[source]
Your game only has a finite amount of memory to work with
The objects that your logic creates take up space on the computer or device that your game is running on
.NET has a built-in garbage collector that allocates and releases memory so you don’t have to[source]
Memory is allocated when a new object is created
Memory is released when existing objects become orphaned
Before we refactored our code, Interactor’s Update method was allocating and releasing memory for each of the 500 Interactables it was assigning to _interactable during each frame
This is bad because garbage collection is an expensive process
We can see this in the profiler data
It isn’t always obvious when memory is being allocated[source]
For example, LINQ extension methods tend to generate garbage and can cause GC frame rate spikes[source]
Let’s minimize garbage collection by replacing this LINQ-based approach with a simple for loop
Tutorial/Demonstration Steps
Replace _interactables.ToList().ForEach() with a for-loop
Switch back to Unity
Click Play and then pause the scene
Our logic is no longer allocating garbage!
...but it’s still running slow!
Unity Hot Paths
One of the easiest ways to optimize your code is to keep it out of Unity’s hot path
A hot path is where a program spends most of its execution time[source]
Unity’s hot path is basically all variations of Update
Some code is going to have to live in Unity’s hot path (so make sure it’s efficient!)
There are a few ways to keep your code out of Unity’s hot path
Start, Awake, OnEnable, OnDisable
Physics method (we already used OnTrigger*)
Coroutines
Coroutines are essentially functions that you can execute for multiple frames[source]
When you call a function, it runs to completion before returning
Coroutines have the ability to pause their execution, return control to Unity, and then continue where they left off on the following frame
Coroutines a feature of Unity
Let’s complete our refactor by moving our logic into a Coroutine and out of Unity’s hot path
Tutorial/Demonstration Steps
Implement a method called “FindNearestInteractable” that returns IEnumerator
Coroutines are iterator methods that Unity uses to step through—or enumerate over—your logic
IEnumerator is the base interface for all non-generic enumerators’
You can think of this method like a collection of objects
Add yield return new WaitForEndOfFrame() to FindNearestInteractable
When Unity iterates over this method, it will get an object that tells the engine to wait until the next frame before iterating again
Wrap the yield statement with a never ending while statement
We’re going to let this method run indefinitely
Wrap the yield statement with a for-loop of _interactables
Now we’re processing one interactable per frame
Copy the logic from Update to the for-loop
Introduce a local variable to hold a copy of WaitForEndOfFrame
Creating a new instance of WaitForEndOfFrame will generate needless garbage so let’s optimize this code by keeping a single local reference that’ll never be orphaned
Switch back to Unity
Click Play and then pause the scene
Now are logic is completely optimized
-
15Chapter 3: IntroVídeo Aula
-
16NamespacesVídeo Aula
Namespacing is a feature of the C# programming language and is primarily used to organize your classes into named collections[source]
In other words, a namespace declares a scope that contains a set of related objects[source]
You should already be familiar with the System, UnityEngine, and UnityEditor namespaces
System is a part of the .NET API and contains fundamental classes and base classes that define commonly-used value and reference data types, events and event handlers, interfaces, attributes, and processing exceptions[source]
Likewise, UnityEngine and UnityEditor contain fundamental classes that are used by Unity and the editor respectively
Namespaces control the scope of your class names so they can help prevent clashes between names[source]
You can create multiple classes with the same name as long as they’re in different namespaces
This is useful when you use a third-party plugin that declares a class with the same name as one in your project (assuming the plugin doesn’t use namespaces)
Besides helping to organize your code and avoid name clashes, namespaces also help you define System Boundaries within your code
A System Boundary is a conceptual line that places a barrier between a system and the rest of your code
In our case, a system refers to the set of classes that implement a concept or mechanic
For example, take the concept of interactions which is made up of the following:
Interactor
Interactable
InteractionHandler
To include a class in a namespace, use the namespace keyword
A namespace can be a single world (e.g., Game) but generally consist of multiple words that are delimited with periods (e.g., Game.Inventory or Game.Player)
To reference a class from another namespace, use the using keyword
-
17AssembliesVídeo Aula
An Assembly is the compiled output of your code, and typically comes in the form of a DLL or EXE file—it’s the smallest unit of deployment for any .NET project[source]
By default, when you build your Unity project, your scripts are compiled into an assembly file called Assembly-CSharp.dll
You can see this in both your Visual Studio solution and in your game’s build folder
Editor scripts live in the Assembly-CSharp-Editor assembly which does not get included in the build
Like namespaces, assemblies can be used as an organizational tool and to set up system boundaries that are much more difficult to cross
If you want to include a namespace that isn’t a part of the current assembly, you have to add a reference to the assembly that the other namespace belongs to
Assemblies can overcomplicate a simple project if you aren’t careful, but they’re an important tool in improving the scalability of your project
Using assemblies can also speed up your development workflow
When you modify a script (i.e., change the code), Unity has to recompile every other class that lives in the same assembly as that script
A project with dozens of scripts in the same assembly will take a longer time to recompile
If you separate your scripts into multiple assemblies, Unity will only have to recompile a subset of your entire project each time you make a change
In Unity, you define assemblies using Assembly Definitions
To add a script to an assembly, create an Assembly Definition in the same folder as the script
Unity automatically associates scripts with assemblies based on the folder structure
-
18Custom Unity PackagesVídeo Aula
Each feature of the Unity engine comes in the form of package[source]
A package is a container that stores various features or assets
Packages can contain the following:
C# Scripts
Assemblies
Native Plugins
Models, textures, animations and audio clips, and other assets
Unity’s built-in packages include the particle system, physics, terrain, audio, and UI (to name just a few)
Packages are also referred to as dependencies
Each Unity project depends on its own set of packages
For example, a mobile game depends on different packages than a VR game
Packages can depend on other packages, which creates a dependency graph that Unity has to manage
Packages are managed at the project level by the Unity Package Manager
The Unity Package Manager, or just “package manager”, is the official package management system for Unity
The package manager is responsible for loading existing packages, installing new packages, and resolving the entire dependency graph for your project
When you open a project in Unity, the package manager reads the Project Manifest to figure out which packages to load in the project[source]
The Project Manifest is a JSON file that both keeps track of your project’s dependencies and acts as a configuration file for the package manager
The benefit of this package based approach is that it’s easier to manage the versions, dependencies, as well as the distribution of individual features
As a developer, you can create your own custom packages to manage features that you’d like to share across multiple projects
-
19Chapter 4: IntroductionVídeo Aula
The Importance of Automated Testing
Testing is an important part of making games
Every time you press Play and verify that your game is working the way you expect it to you’re performing a test
But performing tests manually is time consuming and prone to human error
For example, to test our interaction code I need to start the scene, wait for it to load, and then find something to interact with
That only takes about a minute and may not seem that bad but it actually wastes a lot of time in the long run
Now imagine testing something that’s harder to set up, like an interaction that only happens during a boss fight
That’s where automated testing comes in
Automated testing, or test automation, is the use of software separate from the software being tested to automate a human-driven manual process of reviewing and validating that software [source]
In other words, it’s offloading manual testing to a computer so you don’t have to do it
This is super valuable because…
Your computer can perform tests much faster than you can
It can perform the same test a hundred times and always produce the same result
Once your tests are defined they’ll be a part of your code forever so you don’t have to remember which ones to run or how to perform them
That last point is critical to help guarding against regressions
A regression is a type of bug where a feature that was working before stops working [source]
Regressions are particularly insidious because they tend to go undetected until the worst possible moment.
Automated Testing in Unity
Unity has a built-in, automated testing solution called the Unity Test Framework, or UTF
It’s also referred to as the “Unity Test Runner”
UTF lets you test your code in both Edit Mode and Play Mode, and also on target platforms (e.g., Standalone, Android, iOS, etc.) [source]
Under the covers, UTF uses a Unity integration of NUnit version 3.5 [source]
NUnit is an open-source unit testing framework for .Net languages
It has everything you need to create and run automated tests
At their core, tests are just methods that you mark with one of two attributes
The [Test] attribute is a part of the standard NUnit library and is the primary way of creating a unit test
I use this as often as I can because it’s simple and runs fast
The [UnityTest] attribute is an addition to the standard NUnit library and creates a test that can skip frames as well as leverage some of Unity’s other features
I use this only when I need to use special yield instructions in Edit Mode or if I need to skip frames or wait a certain amount of time in Play Mode
What Do Automated Tests Look Like?
Let’s take a look at some examples from our project: Example Code
What We’ll Be Covering
There’s a lot to cover when it comes to automated testing
I.e., the difference between unit, integration, and functional tests
But in this course, we’re just gonna focus on the different types of tests you can write for your games in Unity (Edit Mode and Play Mode)
-
20Preparing Your Project for TestingVídeo Aula
Preparing Your Project For Testing
Adding new tests to your project is simple but we need to do a little prep work
In order for Unity to be able to recognize and run our tests, we need to create a test assembly
A test assembly is just a regular assembly that has a reference to the Unity test runner and the NUnit framework
The test assemblies for PlayMode and EditMode tests have slight differences
We can create our test assembly by hand, but it’s much easier to just let Unity generate it
Now that we have an idea of how to set up our tests, let’s take a closer look at the two types of automated tests in Unity: PlayMode and EditMode tests
-
21EditMode TestsVídeo Aula
EditMode tests (also known as Editor tests) only run in the Unity editor and have access to both your game code and the editor code
To create an EditMode test all we have to do is add a method to a class that’s associated with an EditMode test assembly and mark it with the [Test] or [UnityTest] attributes
Just like with PlayMode tests, EditMode test methods marked with the [UnityTest] attribute must return an IEnumerator and have access to special yield instructions
The difference is that EditMode test code runs in the EditorApplication.update callback loop as opposed to the game loop
EditMode tests are just fine for testing most of your game code, but can also be used to test custom Editor extensions
I.e., custom inspectors, editor windows, and property drawers
-
22PlayMode TestsVídeo Aula
PlayMode tests are designed to exercise your game code
To create a PlayMode test all we have to do is add a method to a class that’s associated with a PlayMode test assembly and mark it with the [Test] or [UnityTest] attributes
Test methods marked with the [UnityTest] attribute return an IEnumartor because Unity runs them as coroutines
This is useful when you need to wait for the next frame or a certain amount of time while the test is running
E.g., WaitForFixedUpdate and WaitForSeconds
These types of tests are slower and should be used less often to verify critical behaviour that can only be tested in your running game
Play Mode tests can be run as a standalone in a Player or inside the Editor using the Test Runner Window
To run Play Mode tests in a Player, click the “Run all in player” button in the Test Runner Window
Unity will build and run your tests on the currently active target platform and display the test results in the Editor UI