Unity learning path

This article gives beginners an overview of the “noob to pro” learning path to Unity. This list is a starting point for anyone, who has no prior knowledge of game engines or development environments.

If you already have Unity up and running and are familiar with the most basic things, skip ahead to the Learning Resources section.

Step 1 – Getting Unity and the right mindset

Download Unity 5 from here and install it.

Open Unity and select the Get started tab to view a quick introduction video.

Before diving into the editor, I recommend watching the Your First Game video series by Extra Credits to get first advice on how to start. Many of their tips can help beginners avoid common pitfalls and frustration.

Start small and build projects, which you can complete within a few days.

Step 2 – First steps in the editor

To get started in the editor, create a new Unity project.

Create your first project in Unity.
Create your first project in Unity.

 

You do not need to create a new folder for your project. Unity automatically creates one from the project name.

Next, you might want to chose a different window layout:

Unity window layouts.
Unity window layouts.

Select the Layout panel from the top right or hit Window > Layouts and then select 2 by 3. This view shows you the most typical window tabs in Unity.

What you are looking right now is all part of a Scene. At the moment, you haven’t saved your scene, therefore it it untitled. Take a look at the Unity application frame:

Untitled Unity scene in your project.
Unity application frame showing scene title, project name and build target.

 

Click File > Save Scene to save your scene and thereby creating your first Asset.

The Project panel shows you all assets that are currently stored in your project.

Unity's project view.
Unity’s project view.

 

Click the tab menu at the top right and select One Column Layout if you want to browser assets in tree view. All assets, including scenes, images, scenes, models, animations and scripts, are stored in a folder called Assets.

Now, select the Main Camera GameObject from the Hierarchy.

Unity's hierarchy panel.
Unity’s hierarchy panel.

 

The Hierarchy panel shows all GameObjects that are part of the current scene. In Unity, everything is a GameObject: models, scripts, lights, cameras, etc.

A GameObject alone does nothing at all. To have functionality, it must contain Components. You can view attached Components of any GameObject in the Inspector:

The Unity Inspector shows Components.
The Unity Inspector shows Components.

 

If you want to find out what a certain component does, click the blue book icon. This will take you straight to the corresponding page in the Unity manual.

The Unity Manual will be your main resource for learning everything you need to know about the game engine.

Step 3 – Using the official learning resources

Unity offers us great documentation to learn just about everything: the manual, the scripting reference, video tutorials and live trainings.

These pages and videos alone are more than you can ever read, so I will try and give you a guide where to begin:

After this introduction and some playing around you should be able to create scenes with simple objects.

From now on you will want to focus on specific topics, but to get started making your first game, you should learn about scripting:

My favorite tutorial:

 

Now you’re ready to start a real project:

Once you’re done or if you have problems, watch one of the scripting videos for detailed information about specific topics:

I encourage you to go through those videos in order, but also follow along with your own scripting experiments.

Put all beginner techniques to use in this great Unity project:

Finally, move away from noob topics and create your first intermediate game:

Step 4 – Pick your own topics from recommendations

Nobody can be good at everything, so after stepping from your beginner’s pedestal, you should focus on certain topics more than others. In any case, I still recommend to at least glance over all topics from the official Unity documentation, just so you know what exists..

Some of my personal favorites:

Step 5 – Beyond the basics

Up to this point, I’ve only linked resources which teach you how to use Unity, but not how to make real-world games. In fact, going from knowing how Unity components work to knowing how to make a great game is the difficult part.

Be aware that the nature of tutorials is to be concise, but real-world games are very complicated. You can only bridge this by creating your own projects and take away experience with every finished game.

You may also want to buy a book from a professional game developer and look at how they design their projects in the business world.

 

Creating timers in Unity

One of the most common things to do in game programming is to wait for a certain period of time before calling an event. In this article you will find several types of timers in Unity explained and when to use them.

Simple repeating timer in Update()

Let’s create the most basic timer that does something every x seconds:

  • waitTime means how long to wait in between action calls and can be overriden via the inspector.
  • timer is used to store the time that has passed.
  • Update() is called every frame, so we add our deltaTime to our timer in every Update() cycle. The property deltaTime returns how much time in seconds has passed since the last frame.
  • If our timer has risen above our waiting time, a method is called.
  • In place of the print() statement, you can call whatever action needs to repeat.
  • We restart the timer by resetting it to zero.

 

DeltaTime in Unity.
DeltaTime in Unity.

 

DeltaTime in Unity gives us the length of the previous frame, which if you’re running at 60 fps is 1/60 of a second, or about 0.016 seconds.

The basic timer shown above is easy and fast, but your code might end up being cluttered, because the timer is not sealed off in it’s own method.

Here’s another example, that can be turned on and off:

Toggle timer via Update()

 

First, OnTriggerEnter() is called, whenever our CannonBall enters the trigger area  of any GameObject tagged “Player”. This sets the boolean timerRunning true.

The Update() loop is checking every frame for timerRunning and when it becomes true, it calls the BombTimer method. Our timer waits for waitTime to pass and then does something.

Lastly, the timer resets itself until another Player trigger is entered.

Unity offers a few helper functions that can call methods after a period a time or repeat actions:

Destroy an object after x seconds

You can use the Destroy() method from MonoBehaviour and pass in a float parameter to delay it. Note, that you only want to call this method once, not in Update().

Invoking a method after x seconds or repeating it

The Invoke() method takes a method name as a string and the waitTime as a float parameter. This helper function is very convenient, because of it’s clean syntax, but be aware, that invoking methods via string is much slower than calling them directly. Only use this for testing or when performance isn’t an issue.

You can also use InvokeRepeating() to wait for a period of time and then repeat the method call every x seconds:

Again, the Invoke() methods are convenient but slow.

You can stop the Invoke() or InvokeRepeating() method by using CancelInvoke(“MethodName”).

Waiting timer in a Coroutine

Coroutines are incredibly cool and we can use them to create well-performing timers with clean syntax. A coroutine has the ability to pause and resume itself while running in your game.

Pay attention to the using statement that includes System.Collections; we need this to be able to use coroutines.

A coroutine returns a type of IEnumerator. It is not necessary to fully understand what this means, because we’re not making use of the return type with our timer.

Inside of a coroutine, you can pause it’s execution with the yield statement. The yield can return, for example, the WaitForSeconds() method, which waits for any number of seconds passed into it before continuing execution.

Be aware, that a coroutine must include at least one yield statement. If you do not want to wait for several seconds, you can yield return null to wait until the end of the frame like any standard method does. In this example, we could omit this last step, since we we’re already yielding earlier, but just for completeness, I included it.

To start a coroutine, use StartCoroutine() and be aware, that you should pass in a method call as a parameter, as it is much faster than using a string.

Repeating timer via recursive coroutine

This heading sounds complicated, but it actually isn’t. Just look at the code:

Only one line was added to make our coroutine repeat every three seconds. In line 17 HarmPlayer() calls itself, which is known as a recursive method call.

Many times, recursive methods can get very complicated and cause hard-to-understand problems, but in our case they work nice and easy: The method waits for a period of time, then performs the print() statement and finally calls itself again, therefore repeating the timer.

You can stop a coroutine with StopCoroutine(methodName ()) or cancel all running coroutines with StopAllCoroutines().

When to use coroutines over Update()

As you might be thinking, coroutines can replace your Update() loop. I suggest to use them whenever you need time-based functionality, but you want to keep your Update() clutter free.

Coroutines are ideal for timers, moving objects via script or lerping between values.

*lerping refers to Linear Interpolation. See the official Unity tutorial for more information.

 

Please leave me a comment, if you’d like to see more practical examples of timers or if you have any more questions.

 

Object linking – Unity assets

This is part 3 of the examples from Object linking and embedding – Smart workflows for game developers.

Assets in Unity are linked files. They all contain a reference to their original source file, enabling automatic updates, when changes are made.

To force asset update, right click on a file and select Reimport.

Unity reimport assets to force update.
Unity reimport assets to force update.

 

It is important to note, that there is more information to an asset than just the source file:

To every imported asset, there is a hidden .meta file which contains the link and saves changes made in the Inspector.

Unity creates a .meta file for every asset.
Unity creates a .meta file for every asset.

 

This .meta file is extremely important to Unity!

If the .meta file connection is somehow lost for an asset, you might not notice an error, but Unity will no longer update the file correctly. When working in a team this can lead to confusion and broken assets.

Here’s how to avoid problems:

  • Always import assets via the Unity Project pane
  • When making changes to files, have Unity open and save your project, so that the .meta files are updated as well
  • When working with version control, make the following adjustments in Edit > Project Settings > Editor:
Unity editor settings when working with version control.
Unity editor settings when working with version control.

This will show .meta files, which is vital when working with Subversion, Git, Mercurial or any other version control system.

When Unity imports an asset it creates a GUID (Globally Unique Identifier). This number represents the link between the editor and the source file. If you are working in a team with version control and somebody imports assets into the project via the operating system’s file browser instead of Unity, it might lead to conflicts.

Unity .meta file unique identifier.
Unity .meta file unique identifier.

 

Unity tip: It is possible to edit .meta files from the outside Unity, if you know, what you’re doing. You could do a search and replace text on multiple .meta files without opening up Unity. This can be helpful if you’re trying to fix a problem that resulted from merging .meta files in your version control system.

MonoDevelop’s Assembly Browser – Decompile managed plugins

MonoDevelop offers a great but often unnoticed feature for decompiling C# libraries: The Assembly Browser.

The Assembly Browser decompiles managed code and displays it in your MonoDevelop IDE.

Think of plugins from the Unity Asset Store or other third-party modules: Many tools come as a pre-compiled package, such as Dynamic Link Library (.DLL). While you can import and use these libraries easily in Unity, you can’t just open their files and look at the scripts underneath, or can you?

Let’s take a look under the hood of Unity and disassemble one of MonoBehaviour’s methods:

  1. Copy the code to a new C# script in Unity and open it in MonoDevelop.
  2. Place the text cursor within the method name Lerp and right-click Go to declaration or hit Cmd/Ctrl + Y.
Go to declaration of Mathf.Lerp().
Go to declaration of Mathf.Lerp().

When inspecting a MonoBehaviour method, this will take us to the Assembly Browser, since all Unity functions are part of our current Assembly.

Inspecting Mathf.Lerp with MonoDevelop's Assembly Browser.
Inspecting Mathf.Lerp with MonoDevelop’s Assembly Browser.

 

You’re not allowed to alter Unity methods directly, but via the Assembly Browser you can take a look at many implementations.

Inspecting the disassembled Mathf.Lerp(), you can see exactly how it works. This comes in handy when deciding on which implementation is the right for your project; sometimes the Unity MonoBehaviour methods might not be what you want.

Note, that the Assembly Browser only shows managed code.

In short: Managed code in Unity = C#

Managed code in Unity means C# and Java. These programming languages are easily decompiled by MonoDevelop, native code like C or C++, however, is not.

Since most of Unity’s inner workings are written in C++ or use other highly-optimized machine language libraries, there are many MonoBehaviour methods, which you can’t disassemble to their roots in MonoDevelop. Still, most of the time, the Assemble Browser will show you enough information to let you guess what is going on.

Here’s another example:

Vector3.Angle() in MonoDevelop's Assembly Browser.
Vector3.Angle() in MonoDevelop’s Assembly Browser.

Most functions from the Mathf or Vector3 class show us how they work in the Assembly Browser. I encourage you to occasionally look at the implementation of such methods when using them in your project. It can be incredibly helpful to understand the math behind these helpers, because one day you might want to use custom implementations that fit your needs exactly.

Disassembling third-party-plugins

Browsing through pre-compiled plugins from the Asset Store is just as simple as looking at MonoBehaviour methods:

  1. Open a Unity project and import a plugin.
  2. Open the project (Solution) in MonoDevelop by opening any script from the Unity editor or clicking Assets > Sync MonoDevelop Project.
  3. In MonoDevelop go to View > Solution to show the solution browser.
  4. A third-party plugin will show under References. Double click the file to open it in the Assembly Browser. Or just open View > Assembly Browser and find the plugin there.
  5. Make sure to set Visibility to All membersor else you will only see public variables.
  6. Methods and properties can usually be found in a main class with the same name as the plugin. (Look for the “C” on blue background icon to find classes.)

Use MonoDevelop’s Assembly Browser to decompile any managed library or plugin and learn from real-world examples!

Thank you for reading! I hope you found this quick tip inspiring.

Using Unity’s Debug Inspector

Unity’s debug option for the inspector is one of the small, but hugely important features. Here’s how to find it:

Normal Unity inspector.
Normal Unity inspector.

In the tab dropdown for the inspector chose the Debug option, or Normal to return to defaults.

Unity debug inspector.
Unity debug inspector.

Now the Inspector will show additional information, such as private variables from scripts like this:

Debug inspector showing private fields.
Debug Inspector showing private fields.

 

This is one of the easiest and most comfortable ways to inspect private fields from custom classes. Note, that inspector cannot show everything you might expect it to:

The Debug Inspector does not show properties or static variables.

Just to make sure: The Health field that is shown in the inspector is in fact our private variable health, not the property. Variable names are automatically capitalized and formatted in the inspector.

Quicktip: Use auto-implemented properties, if you don’t need additional code or special names for your backing fields. See this tutorial, if you need to freshen up on how properties work.

Here is the official C# documentation on auto-implemented properties.

Be aware that these “auto-props” will display with a particular name syntax in the debug inspector:

Auto-implemented property in the inspector.
Auto-implemented property in the inspector.

 

The Debug Inspector shows not only private fields on custom scripts, but detailed options for other components.

There are many ways to use the debug option to inspect hidden data or change advanced options on Unity components. Here are a few examples:

Inspector and project browser icons

The debug inspector also works when browsing assets in the project view. If you like, you can assign custom icons to your components. This can help your team to find certain important scripts more easily or if you’re developing your own custom component you might want to give it a branding.

Debug inspector icon field.
Debug inspector icon field.

 

Debug inspector fill in icon for script.
Debug inspector fill in icon for script.

 

Inspector with custom icon on script.
Inspector with custom icon on script.

Advanced animation options

There are several options hidden for animation clips, some of which can come in handy to change, such as the ability to switch to legacy animation, when not using Mecanim. You can also adjust options from this window, instead of switching to the Animation or Animator window (e.g. Sample Rate).

Advanced animation clip options.
Advanced animation clip options.

 

Compare objects by instance id

Sometimes you run into a problem, where an object’s instance ID can help you to debug your scene. (The instance ID is a unique identifier to any object in the scene.) Here is a simplified example to illustrate the use of instance IDs:

Often, you need scripts which persist between scenes, such as GameControllers or AudioManagers. If, for whatever reason, you want your manager class to be a MonoBehaviour that lives on a GameObject in the scene, you will have to make sure that there can only exist one instance of it during runtime (read up on the Singleton Pattern for more).

Usually there are ways to build objects in a way that they are true, problem-free singletons, but sometimes you’re stuck with a solution that is prone to errors:

Instance IDs in the debug inspector.
Instance IDs in the debug inspector.

 

Think of a case, when you have a GameController and due to human error there are multiple instances of it attached to GameObjects in the scene. Instance IDs can give you detailed information about which objects are involved when you run into problems:

Now, if you end up with multiple instances of the GameController, only the first one survives. Additionally, the instance IDs of both objects are printed out, to show you exactly which of the instances in the scene caused the problem.

As stated above, this example is purposely plain. Real-world scenarios, where instance IDs will save your life, are going to be complex and cumbersome to debug without the help of detailed object information.

These were only a few examples of how to make the most of the debug inspector in Unity. Keep your eyes open for hidden options and information that helps your work.

Event messaging in Unity – Creating a simple HUD

We can use delegates and events to create a messaging or broadcasting system that is much more robust and versatile than direct script communication via references.

Think of an event as a variable that is called like a static method. As soon as an event is raised from one script, we can listen to it from other scripts and perform corresponding actions. To do this, we want to subscribe another method to our event, which in turn is called. This functionality is given to us with delegates. A delegate holds a list of methods and when the delegate is called, all subscribing methods are called as well.

Best, we look at an example:

Creating a health display with events

This section will show you how to set up a HUD that displays the player’s health whenever it changes. Since there might be more objects that are interested in the player’s health, we will build an event system, that fires whenever the health changes and can be received by any number of other scripts easily.

  1. Create a Player C# script and attach it to a GameObject in the scene.
  2. Create a UI Text object on a Canvas in the scene. I’m using the Unity 4.6 upwards GUI system, but the old system or plain debug log messages will work fine for testing purposes.

Start with the player script:

Our player has a health variable that is going to be initialized in the Start() method. The UpdateHealth() method will be called to add or subtract from health and then call the appropriate event, which can be received by different listeners in the scene.

Next, add in a delegate and an event before line 7:

This is a typical delegate and event pair. Watch the official Unity tutorials on delegates and events for a detailed explanation.

In short: The event OnHealthUpdated is declared as static, so that we can call it from anywhere. It needs a type, which we declare with the delegate HealthUpdate. Note, that the type is HealthUpdate, but the actual delegate is a method, so it needs a return type of void and the parenthesis.

Let’s raise the OnHealthUpdated event in our player script:

If an event is raised without having subscribers, it will throw an error.

Before we call our event like a method we should include a null-check to avoid errors.

An event without subscribers returns null.

Be mindful of the parenthesis: the event itself is called OnHealthUpdated, but when we want to raise it, we use it like a method OnHealthUpdated().

Now that we have a player that raises an event as soon as its health is initialized, we can build the receiving end, the HUD script:

It is a good idea to subscribe to events only when an object is enabled, so we place our code in the OnEnable() method from MonoBehaviour. We can access our static event and assign a method from HUD to it with the += operator. This method can be any custom function that is already declared in your script, but it’s also very convenient to use auto completion and let MonoDevelop suggest an implementation (often called an EventHandler).

MonoDevelop auto implementation of event handlers.
MonoDevelop auto implementation of event handlers.

 

It’s time for our first test:

If you’ve done everything correctly (and both scripts are attached to GameObjects in the scene), the debug message will be printed to the console as soon as the player calls the HealthUpdated event.

Great, now there’s only one thing left to figure out: How to send parameters with events, so that our HUD knows what the player’s health is.

Change line 7 of the player script from:

to:

Now our delegate expects all subscribing methods to receive an integer parameter and we can send one from our event:

Adjust the HUD script to accept the incoming newHealth parameter:

One more important thing:

Whenever you subscribe a method to an event, be sure to unsubscribe it as well to prevent memory leaks and possibly errors.

That’s all there is to a basic messaging system! Events can be used for anything from updating stats over input to artificial intelligence. They can also include more interesting parameters like a reference to the event raising object, but that goes beyond this introduction.

Here are some more ideas how to continue:

Additional info: If you pay close attention to the console output from the last two scripts, you might notice, that the messages seem to come in the wrong order:

Debug messages are displayed in an incorrect order.
Debug messages are displayed in an incorrect order.

How can the event be received before it was fired? Of course, it can’t. Printing to the console is a very slow operation and due to many things going on at the same time, Debug.Log() might be too slow to accurately depict what is going on. Don’t worry, just be aware that it’s only the console messages that are slow, your event system is still working correctly.

Caching the ‘transform’ and ‘gameObject’ properties

The transform and gameObject properties of MonoBehaviour are often used to check property values against other values.

There are a few reasons to avoid using transform to move objects, but a position-check is a perfectly valid example. There is, however, a small problem with the above code: The transform property internally does a GetComponent() call. This means, that every frame a method call is needed to find the reference to the Transform component of our GameObject.

This code illustrates what is actually going on under the hood of Unity. At this point it is not necessary to fully understand how these internal calls work, just keep in mind that every method call and dot-operation costs performance and therefore we want to avoid them as much as possible.

The solution: Cache your variables and even Unity properties!

Instead of finding a reference to our Transform component in every frame, we do it only once and store it in a variable. You could call this variable myTransform or something, but I prefer to call it the same as the Unity transform property. This way, I don’t have to change any of my working code, when I want to optimize things at the end.

Pay attention to the new keyword, which we use to tell the compiler that we intend to override the inherited member transform from MonoBehaviour. This step is not entirely necessary, but sometimes Unity will throw a warning and remind you that there already exists a variable called transform.

Caching references in variables is a common way to optimize performance.

What we did with the transform property is just one example of caching a reference for later use. We do the same thing whenever we access another script or component, but in case of the built-in Unity properties, I think it is worth mentioning that we can override those with more performant ones.

Note, that this kind of optimization is only effective and noticeable when resources are limited or you are dealing with many script objects. Caching Unity properties for only your player will not speed up your game visibly!

String “auto-completion”, Tags and Hash IDs

Unity Tags, Layers and Animator components are great tools to use, but they have one drawback: It is necessary to pass strings into certain MonoBehaviour methods to make them work.

Consider this short example:

There are several situations in which you can’t get around using strings as parameters for certain Unity methods. Other times it might be the most convenient and practical solution.

At this point it would be too much to talk about all the implications of using strings and how or why to avoid them. Instead, I’d like to show you a remedy for one of the many downsides of using strings in functions.

Strings as method parameters are difficult to deal with because of possible spelling-errors or tedious renaming of multiple string-instances.

The most common examples of string usage in methods are:

  • Output messages for console logging, warning messages and exceptions.
  • Accessing Animator layers and parameters
  • Identifying objects by Tag
  • Calling a method by name when using Invoke() or a Coroutine

A good solution for working with anything Animator related is to hash strings to integers and feed the Animator with ID’s instead of layer and parameter names. Int variables are much better for performance than strings. They also have the benefit of being visible in IntelliSense.

Create this script and attach it to a GameObject in the scene (Awake must be called for the StringToHash() method to create our ID’s):

I prefer to declare my hash variables as static, because then I can access them without finding a reference to them from other scripts. (A drawback is, that Unity’s debug inspector does not show static fields, so you have to set breakpoints or print to the console, if you want to debug your strings and hashes.)

If you’d like to use auto-completion on string parameters to easily remember them and prevent spelling-errors, try this:

Note, that a class which only stores variables doesn’t need to be attached to a GameObject. You can also declare multiple classes within one file.

"Auto-completion" for string values through static class.
“Auto-completion” for string values through static class.

 

Recap: Use hash ID’s for Animator layers and parameters. Store strings that will not change in a static class.

MonoDevelop Basics

In this article, you will build a C# script from scratch and learn the most important tools in MonoDevelop.

Code completion

Also referred to as autocomplete or IntelliSense, code completion describes the greatest tool every created for programmers. By its name you alreasy know what it does, but we’ll go over the details soon.

First, open a Unity project and create a new C# script called Player. Next, open it in MonoDevelop by double clicking it and delete everything inside it. Now, let’s start from scratch:

This is all you need to define a class in C#. But before you start typing, follow these guidelines:

MonoDevelop code-completion.
MonoDevelop code-completion.

Type the first two letters of the word public and hit Enter to auto-complete it. From now on, there will be almost nothing that you have to type out in its full length. If auto-completion doesn’t pop up you can force it via a keyboard shortcut; in my case: CTRL + Space.

If you’re having trouble, check your preferences:

MonoDevelop code completion preferences.
MonoDevelop code completion preferences.

 

Continue to define your class by typing the letter and hitting Enter to autocomplete it to class. Names like Player are not (yet) in your auto complete list, so you’ll have to spell it out. But once you’re done with your class definition, you will also have access to Player in your code completion window.

In fact, auto completion is a list of all keywords that are currently available to you. This includes keywords from the C# language itself, such as public or class, as well as classes or variables, which you defined.

Next, we want our script to derive from the MonoBehaviour class, because this is what we need to make our script work as a component on a GameObject in Unity. If you try to type out the keyword, there won’t be any auto complete suggestions at the moment. This is, because MonoDevelop doesn’t know about Unity’s MonoBehaviour at the moment. Let’s tell it:

Remember to only type the first few letters and then autocomplete with Enter.

UnityEngine is a collection of classes. MonoBehaviour is one of the classes that live within the UnityEngine namespace. Now, we can use auto completion to inherit from MonoBehaviour and give our class access to all the Unity goodies.

Now we have a functioning class. Save your file and check for errors in Unity, by attaching your script to a GameObject in the scene and hitting Play. Open the console window to see, if any errors appear in the log.

Continue with the following example:

For testing purposes, we will define another class within the same C# script. In fact, this is not a unusual thing to do, just be aware of the fact, that only the first class in a file can be a MonoBehaviour. Following MonoBehaviours will just not work correctly, although no error is shown in Unity.

Construct a new instance of the Test class in the Start() method and store a reference to it in a variable called test of the Type Test.

If this does not yet make sense, don’t worry, just copy the code and follow along to learn more about auto completion.

Code completion showing class members.
Code completion showing class members.

 

Now that we a class instance called test, we can use the dot-operator to access members (public variables) of that class.

Use auto completion to find your variables.

A short rundown of icons used in MonoDevelop’s auto completion:

  • M : method (function)
  • P : property
  • F : field (member variable)
  • C : class

(There are a few more icons, but I’ll save them for later.)

Here is our complete script with a print statement to see if it works correctly:

Checking variable values via the print statement is rather tedious and not very elegant. Click here to learn how to make private variable visible in the inspector.

Renaming variables and classes

If you ever want to rename a variable, be sure to use MonoDevelop’s renaming tool: Select your variable (highlight it or just place your cursor within it) and hit CMD/CTRL + R or right click Refactor Rename. This process is called refactoring because we don’t just want to rename a single word, but instead rename all instances of our variable.

Refactoring a class works the same way, but be aware that a class that derives from MonoBehaviour must have the same name as the file that is attached to a GameObject in the scene.

Shortcuts

Line endings

Accessing variables and communicating between scripts

One of the most common tasks in Unity is to access variables on another script or component.

Remember that a component in Unity is nothing more than a piece of code put into a class with a nice name such as Transform or BoxCollider.

Here’s an overview of different ways to read information and how to communicate between different scripts:

  1. Private variables and scope
  2. Public variables and accessors
  3. GetComponent()
  4. Static variables
  5. Messaging

Private variables and scope

At the most basic level we access information by reading private variables within a single class.

Private variables are also called member variables and are only accessible from within the class they are declared in. Their scope is limited to the containing code block, which, among others, can be a class, function or if-statement. Whenever a variable is declared in between curly braces you can only see and read from it within the same code block or nested blocks.

See code example abovehealth can be read from within the Start() method, because it was declared within the Player class which is a parent element to the Start() method. Generally, you can only read variables, which are declared at the same or a higher level than that of which your call or assignment originates, but not the other way around.

Think of a variable declaration as a “parent” and calls to that variable as “children”. The children must be contained within the parent code block.

Here is an example of a variable that is inaccessible due to scope:

The variable count is declared within a for-loop which is a code block and only exists in between the following curly braces. The print-call happens outside of that code block, it is at a higher level and therefore can’t access the variable.

A variable must be declared before it is used. When declaring  a variable on the class level, the line number on which the declaration happens is irrelevant to the compiler.

Here is an example for a variable declaration which is limited to the scope of the Start() method:

Important: A variable that is declared on a lower level than the class level (meaning: within a method), is always private and can not have any other access operator applied. Therefore, you do not need and can’t use the private keyword.

Tip: Keep in mind, that on the class level, the private accessor is implicit in C#. You may omit the keyword and the variable will still be private by default. However, many consider it best practice to always declare accessors explicitly.

Recap:

Private variables have a scope in which they are accessible; they are members of a class or other code block.

Public variables and accessors

Variables, methods and even classes are declared with a certain protection level, which limits the element’s scope in a specific way. The most common way to define scope is by the use of the private or public accessor.

Declaring a variable or method as public makes it accessible from other scripts. There is, however, a strict rule to follow when attempting to read variables from another class:

Scripts can communicate with each other via public variables if one class has a reference to the other class instance.

Here is a script example of our Player class:

Note that both the class and the variable health have the public accessor applied, which makes them visible to other scripts.

On line 5 you find a variable of the type Player. This will be used to store a reference to the Player class instance. On line 9 this variable is assigned the current player script, which lies on the same GameObject. (See the next section for more information; just know that GetComponent() returns an instance of the class we’re trying to find.)

Reminder: A class is only a template that tells the computer how to build an object. The object is created by constructing an instance from the class. (Unity does this for us automatically when we attach a MonoBehaviour script to a GameObject and press Play.) A reference tells the program where to find a specific object instance in memory.

When our Player variable holds the correct instance/object (meaning that it is not null), we can access all public variables within it by using the dot-notation:

The same works for functions:

Check out MonoDevelop Basics if you need to catch up on how to use auto-completion and other tools for convenient programming.

Remember, to access a class, method or variable from another script, they need to be declared as public. Next, the calling script needs a reference to the other class instance. Finally, you can access a member or method via dot-notation.

GetComponent()

GetComponent() is a Unity method from the MonoBehaviour class that is used to access data on other components. To fully understand how this method works, you have to wrap your head around a few different concepts.

Let’s attach our player script to the Main Camera GameObject in the Unity hierarchy and tell it to find the Camera component:

First, you declare a variable of type Camera to hold a reference to the Camera Component which you are going to find on the same GameObject. Next, you call GetComponent() in it’s generic version on the type Camera, which will return the first object of type Camera that is found.

Above is the “standard” version of GetComponent(), which might be easier to understand, because it is slightly more explicit. The method searches for a class that is called Camera by string and then passes the class as the type of Camera so that we can store it in our variable.

The as operator can be used to convert classes (they must be a reference type, so that they are able to return null!). In this case we want to convert whatever object we find that matches our search string, to a Camera object. If this works, because our camera is indeed a camera object, we basically just pass the reference.

If for whatever reason, our camera would not be of type Camera the method would return null, instead of throwing an error, which is convenient in this case, because now we can search for objects that only might exist.

Because variables which have the value null can cause Null-Reference-Exceptions, it is very common to perform a null-check before accessing such variables.

If you were to access our mainCamera variable without any null-check, Unity might throw an exception, if the variable doesn’t hold a Camera object.

Because searching by string is a relatively costly operation for computers, the generic version GetComponent<type>() is preferable. Nevertheless, GetComponent() is still a costly operation itself, so even in it’s generic version, it should be called as rarely as possible. Use it for caching variables once in Start() or Awake()!

Here’s a more complete example:

Note, that both the Player script and the Camera component are on the same GameObject in this case. (Just for testing purposes, this is not a practical example!)

In Awake() we find a reference to the camera. In Update() we adjust the camera’s field of view, but only if the reference exists.

How does GetComponent() know where to search for objects?

Until now, GetComponent() returned a component on the same GameObject, but you might be guessing that we will use it to find scripts on other GameObjects, too, so how does this work?

Consider this script for an enemy object:

In this example, we want to access multiple components on a different GameObject. Before anything can work, we will need to find a reference to the other GameObject. Once we have found an object, we can perform a GetComponent() search on it, by using the dot-notation. There are multiple ways to find references in Unity C#:

1. Assigning a reference through a public variable in the editor

When you declare a public variable in the Enemy script on the enemy GameObject, Unity will automatically create a field in the inspector, which you can use to assign a reference by visually dragging an object onto the field or selecting one from the dot-picker to the right of the field.

Unassigned reference for a public variable in the inspector
Unassigned reference for a public variable.

 

public-variable-reference_filled
Public variable with assigned reference.

Assigning references through public inspector fields is very easy to understand, but it also requires a null-check, because it is quite possible to forget to populate the inspector field. During development there are also a few situations, which might break such a manually established connection, especially when working with Prefabs in Unity. Still, it’s a very design-friendly solution to quickly hook up things.

Best usage: Use public inspector fields, when you want to give a designer the control over which reference is assigned. For example a Camera-Follow script that takes a public variable Target and follows any object that is assigned through the inspector.

Public inspector variable with unassigned Transform.
Public inspector variable with unassigned Transform.

Note, that inspector fields show us which type a variable/field expects. When you drag a GameObject onto a field that says “None (Transform)” the editor will automatically assign the Transform component of the object.

2. GameObject.Find()

This Unity method returns the first active GameObject that matches a given string parameter. The search is performed on the entire scene.

Recommendation: Be cautious when using this method, because it is slow! If you must use it, then only call it once in Awake() or Start().

Active GameObject in inspector.
Active GameObject in inspector.

Be aware of the fact, that GameObject.Find() only returns active objects. Also, if you rename your objects during development, you will have to adjust your scripts as well, which might become tedious, since Game Designers like to rename things to make them look pretty in the hierarchy…

3. GameObject.FindWithTag()

A better alternative is to search for objects by Unity Tag. First, assign a tag to your GameObject via the Inspector:

Inspector Tag on GameObject
Inspector Tag on GameObject.
Add Tag to GameObject in Inspector
Add Tag to GameObject in Inspector.

Add Tag… will take you straight to Unity’s Tags and Layers editor, which you can also find at Edit > Project Settings > Tags and Layers. Here you can create a custom tag, which will then appear next to the default one’s in the Tag list. Once our player is tagged with the Player tag, we can easily find a reference by using GameObject.FindWithTag():

GameObject.FindWithTag() is not the fastest solution, but a practical one.

You can use this method for individual objects like a player or a game manager. You should only call it once and cache the result in a variable. Performing the search on a hundred objects tagged Enemy might be slow, so reconsider your options when dealing with many entities.

Would you like to use auto-completion for your tags? Here’s another trick when working with strings as parameters: Strings, Tags and Layers

4. Transform.GetChild()

If your GameObjects have a fixed relationship in the hierarchy, you can find them by index with Transform.GetChild().

Note, that the Unity hierarchy is built with Transforms. So when traversing the hierarchy to find another object, you are going to use the Transform class.

Hierarchy Transforms
Hierarchy Transforms

As you can tell from the inspector, all elements in the hierarchy include a Transform component, which can be accessed by an index starting at zero. When trying to find the first child object in a parent-child relationship, we search for index 0.

Now that you have found a reference to a GameObject and stored it in a local variable, you can access it via the dot-notation and use GetComponent() to pick a specific component.

So let’s put it all together:

Here’s another trick, how you can visually check if a private variable has been populated or not.

Recap:

  1. Declare variables for components you wish to store in your class (line 5 – 6).
  2. Find a reference to the GameObject on which those components live (line 10). You also declare playerGO locally because you won’t be needing it any longer, once the variables for playerScript and playerTransform are assigned.
  3. Don’t forget a null-check to prevent errors!
  4. Assign the final variables by using GetComponent().

It is true, that there’s a plethora of ways to find references and store them. Remember, it is ok to just go ahead with the first solution, that comes to mind and then improve it later!

Generally, try to get to your data in as few steps as possible. For example, if you’re looking for the weapon’s Transform, consider traversing the hierarchy from the player to the child objects, instead of looking for a GameObject first and then doing a GetComponent() to find the Transform. Save on method calls and dot-notation operations!

Addendum:  We’ve learned that GetComponent() performs a search for a component type/class on a GameObject by using the dot-notation.

By now, you should know exactly what’s going on when you see the above example. We’re looking for the playerPosition by performing a GetComponent() on our player reference and then going one level deeper into the Transform position.

If you’re on top of things, you might wonder:  “Why use GetComponent() in this case, when there clearly is an easier way…”

True, you might as well do this:

Let’s clear things up: transform is a Unity property that does a GetComponent() call with <Transform>. Read more here.

We start to get a grip of the idea, that GetComponent() is always called on some kind of object via the dot-notation, but why are we allowed to do this:

GetComponent() always needs to know on which object to perform a search and here it seems as if this information was missing. However, the above line 9 is basically a shorthand for:

MonoBehaviour offers us another built-in property called gameObject, which will return the GameObject to which our script is attached. Therefore, gameObject and transform are also calls to the GetComponent() function. Read this if you’re interested in knowing why you shouldn’t use those properties in your Update() loop.

Static variables

Now comes a part, in which the humble beginner might think: “well this is the easiest method of accessing variables across scripts, why not use this one first place?” To which I will reply: “static variables are great, but there’s much to learn before one can safely use them!”

A static variable lives on a level with the class template, not with the individual instances of a class. It is a single entity which is shared by all class instances.

We’ve learned, that Unity creates instances of our classes when we attach them to GameObjects and start the game. So if we create multiple enemies, all of which have an Enemy script attached, which stores health, each enemy has their own instance of the health variable. Try it out!

  1. Create a GameObject called Enemy.
  2. Attach the Enemy script to it.
  3. Duplicate the enemy a few times.
  4. Assign each enemy a different health through the public field in the inspector.
  5. Press play and watch the console output different health values for each enemy.

Nothing new here, so let’s add in a static variable:

When you look at the inspector, you will find that Unity doesn’t allow us to set static variables through the editor. (It would be rather confusing, if it were possible, anyway…)

Instead, we increment the count variable whenever an enemy script is started by Unity. Since every enemy is created only once per session, our static count will tell us how many enemies we’ve created.

In short: We’ve created multiple instances of the Enemy class by duplicating the GameObjects in the Editor. Every instance has their own set of private and public variables, but all of them share a single static variable called count.

To avoid confusion: the static keyword is not an accessor, it is meant to create a single variable that lives among your class object.

Let’s make it even clearer and create a new testing script on our Main Camera:

Active camera with Test script.
Active camera with Test script.

Then deactivate our enemies in the inspector. Turning off GameObjects in Unity sets them inactive. On a component level this is called enabled or disabled.

Enemies inactive in hierarchy.
Enemies inactive in hierarchy.

Press play, watch the console and start to activate one enemy after the other by clicking the checkboxes for each GameObject. You will see how the count variable is incremented with every new enemy that comes alive.

The count variable increments.
The count variable increments.

Now, while the Unity player is running, select your enemies and delete them from the hierarchy. The count variable will still be printed to the console, because it still exists, although all of the enemy class instances were deleted.  If you’re window doesn’t show the print output in four compact statements, hit Collapse at the top row of the console tab.

Further reading on counting enemies: If you actually want to use the count variable for something, you probably want it to tell us the amount of enemies that are currently alive. A typical way of doing this:

The OnEnable() and OnDisable() methods are built-in MonoBehaviours just like Start(). They get called whenever the script is turned on or off. This is true, when enabling the script itself, as well as when deactivating the GameObject on which the script resides.

Messaging

I’ve included messaging in this article, because it’s one of the main ways to communicate elegantly between script and you should consider using it in your own projects as soon as you’ve mastered the previous sections.

Because sending messages in Unity is worth it’s own topic, please continue reading here.