How to get a variable from another script in Unity

How to get a variable from another script in Unity (the right way)

In Unity by John French20 Comments

Getting a variable from another script in Unity can be pretty straightforward.

In fact, even if you’re only just getting started with the basics of Unity, chances are you’ve already created a public reference between a script variable and another object, by dragging and dropping it in the Inspector.

You might have already accessed components on a game object from code, or created connections between objects through an interaction between them, such as when two objects collide.

But what if you want to create a connection between different scripts or components, on different objects, that don’t otherwise interact?

How can you keep track of game-wide, global variables, like a score or the player’s health?

And what’s the best way to do that, without making a mess of your project?

In this article you’ll learn the basic methods for accessing a variable on another script. along with some best practice tips to help you keep your project clean and easy to manage.

What you’ll find on this page:

How to access a variable from another script in Unity

To access a variable from another script you’ll first need to get a reference to whatever type of object, class or component you’re trying to access.

For example, suppose I’m writing a player health script for the 2D Knight character below, and I’d like to play a sound effect whenever the player gets hurt.

I have an audio source on the character and a Player Hurt function in the script that I can use to trigger the sound, so how do I connect the two?

Example Unity Scene

In this example, I want to get a reference to an audio source component on my Knight character.

Before I can trigger the audio source component to play from the script, first, I need to get a reference to it.

In my player health script, I’ve created a public audio source reference variable.

Like this:

public class PlayerHealth : MonoBehaviour 
{ 
    public AudioSource playerAudioSource; 
}

Next, I need to connect that reference to the audio source component on the character, so that the script knows which audio source I’m referring to.

There are several ways I can do this but let’s start with the simplest method.

How to manually access a variable using the Inspector

In this example I’ve added an audio source component to the player object and have created a public audio source reference variable in my player health script.

I’ve made the audio source variable public, which means so that it’s visible in the Inspector and available to other scripts.

Public vs Private variables in Unity

If the public and private Access Modifiers are new to you then, put simply, public variables can be accessed by other scripts and are visible in the Inspector while private variables are not accessible by other scripts and won’t show up in the Inspector.

The access modifier is added before the data type and, if neither is used, the variable will be private by default…

Here’s what it looks like in code:

public float publicFloat;
private string privateFloat; 
int privateInteger;

You may have already used both public and private variables in tutorials and other examples and, generally, it’s the simplest way to show a variable in the Inspector or allow another script to access it.

However… there’s a little more to it than that.

It is possible to show a private variable in the Inspector, using Serialize Field,

Like this:

// This will show in the inspector

[SerializeField]
private float playerHealth;

It’s also possible to make a variable available to other scripts without also showing it in the Inspector.

Like this:

// This will not show in the inspector

[HideInInspector] 
public float playerHealth;

Generally speaking, it’s good practice to only make a variable public if other scripts need to access it and, if they don’t, to keep it private.

If, however, other scripts do not need to access it, but you do need to see it in the inspector then you can use Serialize Field instead.

This keeps the variable private but makes it visible in the Inspector.

However… for the sake of keeping examples simple, in many tutorials and examples, you will often see a variable marked as public for the purpose of editing it in the Inspector.

In my example, I’ve used a public variable because I will want to be able to access it from another script and so that I can set the variable in the Inspector, which is exactly what I’m going to do next.

Set the variable in the Inspector

Both the script and the audio source are attached to the same game object, which in this case is the player, and connecting the two is as easy as dragging the audio source component to the player audio source field on the script component.

Like this:

Set a reference in Unity in the Inspector

Click and drag the component to the empty field to create the reference.

I could also use the circle select tool, which will list all of the game objects in the Scene with components that match the reference type, in this case, any game objects with audio sources attached.

Like this: 

Circle Select Unity Inspector

Using circle select lists all of the objects in the Scene with components that match the reference type.

Now that I have a cached reference to the audio source component I can access its all of its public properties and methods.

Like this:

public class PlayerHealth : MonoBehaviour
{
    public AudioSource playerAudioSource;

    void PlayerHurt()
    {
        // Deal damage!
        playerAudioSource.Play();
    }
}

I can use the same method to access script instances as well.

Just like when creating an audio source reference variable, a script reference variable works in the same way.

Instead of “AudioSource”, however, simply type the name of the class as the variable’s type.

For example, I could create a reference to an instance of the “PlayerHealth” script I just wrote.

Like this:

public PlayerHealth playerHealth;

Just like with the audio source component, I can set this variable in the Inspector to reference any instance of any player health script in the Scene, and use that connection to access its public variables and methods.

Like this: 

public class SomeOtherScript : MonoBehaviour
{
    public PlayerHealth playerHealth;

    void Start()
    {
        playerHealth.playerAudioSource.Play();
    }
}

This method of creating and assigning references manually is easy and straightforward.

And, chances are, if you’ve done anything at all in Unity, you’ve already created references like this before.

But what if you can’t drag and drop the object in the Inspector?

This might be because the component is created at runtime, or simply doesn’t exist yet.

Or it may be that the field is private and isn’t visible in the Inspector.

And while it is possible to serialise private fields, it may be that you have no need to change the variable from the Inspector and want to keep it hidden for the sake of keeping the script simple and easy to manage.

Whatever the reason, how can you get a reference to something, without assigning it manually?

One option is to use Get Component…

How to use Get Component in Unity

Get Component is a method for finding a specific type of component.

It allows you to search for a specified type of component on one or a number of game objects and get a reference to it.

This is especially useful for getting references to components that are on the same object as the calling script, but it can also be used to search for components on other game objects as well.

So how does it work?

Get Component takes a generic type which, if you look at the code below, is entered in place of the T in angled brackets.

GetComponent<T>();

If the angled brackets “<T>” are new to you, don’t worry.

In this case, they simply mean that Get Component can search for any type of component and that you’ll need to specify the type in the angled brackets when using it.

Simply replace “T” with whatever component type (or class name) you’re trying to find.

Like this, to find an Audio Source component:

GetComponent<AudioSource>();

In my previous example, I created a public reference to the player’s audio source manually, by setting it in the Inspector.

Using Get Component, I can set the reference I need in Start without exposing it as a public variable.

Like this:

public class PlayerHealth : MonoBehaviour
{
    AudioSource playerAudioSource;

    void Start()
    {
        playerAudioSource = GetComponent<AudioSource>();
    }
}

You might have noticed that I didn’t specify what game object the component is attached to, I just typed “GetComponent…”.

This works because the component I want is on the same game object as the script.

But what if it’s not?

What if it’s on a child object, or a parent object, or somewhere else entirely?

Get Component from a different object

To get a component from a different game object, you will first need a reference to that game object (more on how to do that later).

GameObject otherGameObject;

Once you have it, Get Component can be called using the game object’s reference and the dot operator.

Like this:

public class PlayerHealth : MonoBehaviour
{
    public AudioSource playerAudioSource;
    public GameObject otherGameObject;

    void Start()
    {
        playerAudioSource = otherGameObject.GetComponent<AudioSource>();
    }
}

For this to work, you will usually need to have a reference to the object that the component is attached to, except if the component is on a child object or the object’s parent.

In which case, it’s possible to use Get Component in Children or Get Component in Parent to get the component without having a reference to its object first.

Here’s how you do it.

How to use Get Component in Children

Get Component in Children works in the same way as Get Component except, instead of only checking the specified game object, it checks any child objects as well.

Like this:

public class PlayerHealth : MonoBehaviour
{
    AudioSource playerAudioSource;

    void Start()
    {
        playerAudioSource = GetComponentInChildren<AudioSource>();
    }
}

Note that Get Component in Children checks its own game object and all its children.

This means that if there’s already a matching component on the game object that calls it, this will be returned and not the component on the child object.

How to use Get Component in Parent

Just like Get Component in Children, you can also get components from parent objects too!

Like this:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerHealth : MonoBehaviour
{
    public AudioSource playerAudioSource;

    void Start()
    {
        playerAudioSource = GetComponentInParent<AudioSource>();
    }
}

Just like Get Component in Children, Get Component in Parent checks both the game object it’s called on and the object’s parent.

So if there’s already a matching component on the game object, it will be returned just as if you were using the standard Get Component method.

This can be an issue when you are using multiple components of the same type and you want to be able to distinguish between them.

Luckily there’s a solution for that too…

How to get the second component on a game object (managing multiple components)

Get Component, Get Component in Children and Get Component in Parent are great for retrieving a single component from another game object.

However…

If you’re using multiple components of the same type on an object, it can be tricky to know which component is actually going to be retrieved.

By default, when using any of the Get Component methods, Unity will return the first component of that type, from the top down, starting with the game object it’s called on.

That means that if there are two components of the same type, the first one will be returned.

But what if you want to access the second component?

One method is to simply reorder the components so that the one that you want is first.

And if that works for you, then do that.

However…

If other objects are accessing the component in the same way, reordering them could cause issues for other scripts that may rely on a certain object order.

Alternatively, you can use Get Components to retrieve all of the components of a given type from the game object and then choose from those.

Here’s how it works…

First, create an array of the type of component you’re trying to retrieve:

Like this:

public AudioSource[] audioSources;

Note the square brackets after the variable type, which mark it as an Array.

If you’re not familiar with Arrays, they simply allow you to store multiple variables of the same type in a single array variable, kind of like a list (but not to be confused with actual Lists in Unity, which are similar to arrays, but can be reordered).

Next, populate the array using GetComponents, GetComponentsInChildren or GetComponentsInParent.

Like this:

audioSources = GetComponents<AudioSource>();

This will add a reference to the array for every matching component that’s found.

Once you’ve filled the array, each element has its own index, starting from 0:

Unity Array of audio sources

Each Array element has an index, starting from zero which is the first.

To access a particular element of the array, simply type the name of the array variable, followed by the index of the element you want to access in square brackets.

Like this:

public class PlayerHealth : MonoBehaviour
{
    public AudioSource[] audioSources;
    public AudioSource playerAudioSource;

    void Start()
    {
        audioSources = GetComponents<AudioSource>();
        playerAudioSource = audioSources[1];
    }
}

In this example, I’ve set the playerAudioSource variable to the second entry in the audio source array.

You’ll notice that I’ve entered number 1 to get the second entry, not 2. This is because the array index starts counting at 0, not 1.

While this method will help to distinguish between multiple components of the same type, it can also be vulnerable to errors, as it will still be possible to change what is returned by simply reordering or removing one of the components.

For this reason, it’s sometimes better to set the reference manually (if that’s an option) or to split components across multiple game objects (if doing so prevents any confusion between them).

And, while it may seem counter-intuitive to create multiple objects to each hold single components, if it helps to avoid errors and makes your project more manageable, then the tiny performance difference is likely to be worth it.

Is Get Component Slow?

Using Get Component can be a helpful way of caching references.

However…

Because Unity is essentially searching through an object’s components every time you use it, it is slower than using an existing, cached reference.

That’s why it’s a good idea to use Get Component as infrequently as possible.

Such as once, in Start, to cache a reference to a component, or occasionally in the game when setting up new objects.

However, so long as you’re not calling Get Component in Update, or calling it from a large number of objects all at once, you’re unlikely to run into performance issues when using it.

Get Component vs setting a public variable in the Inspector (which to use)

So… which is the better option for getting a reference to component or script?

Is it Get Component, or should you manually set a public variable in the Inspector?

Generally speaking, once you have a reference to a script or a component, both methods perform the same and one isn’t necessarily any better than the other (as long as you’re not calling Get Component frequently, e.g. in Update).

So, when deciding which method to use, it’s better to consider which will be easier for you to manage.

For example… if you’re creating a game object Prefab, and are using several different parts, each with their own scripts that refer to other parts and Components of the object as a whole, there’s no real sense in using Get Component to connect everything together. It’s more convenient, and probably more manageable, to set up the connections yourself, saving them in the finished Prefab.

Alternatively, however, if you’ve created a reusable script component that is designed to perform a single task when it’s dropped onto a game object, Get Component can be a useful way of automatically setting it up.

Say, for example, I wanted to create a script that randomises an audio source’s settings in Start. Using Get Component to set up the audio source automatically would remove an unnecessary step.

I could then simply add it to any object with an audio source on it and let the script set itself up.

Handy, right?

There’s just one problem.

If I forget to add an audio source to the object when adding my script, it’s going to try to get something that simply isn’t there, causing an error.

So if I want to use Get Component to automate the set up of a script, how can I make sure it has everything it needs?

That’s where Require Component comes in.

How to use Require Component

Require Component is a class attribute that simply forces Unity to check for a certain type of component when adding the script to an object.

It also prevents you from removing a required component from an object if another script requires it to be there.

For example, I can specify that my Randomise Audio script needs an audio source to work.

Like this:

[RequireComponent(typeof(AudioSource))]

This also works with other types of component and, of course, other script classes:

[RequireComponent(typeof(PlayerHealth))]

Require Component is a class attribute, so it’s added ahead of the class declaration in square brackets.

Like this:

using UnityEngine;

[RequireComponent(typeof(AudioSource))]
public class RandomiseAudioSource : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        AudioSource source = GetComponent<AudioSource>();
        source.volume = Random.Range(0.5f, .75f);
    }
}

Now when adding this Script to an object, if an audio source doesn’t exist, one will be added for me.

And, if I try to remove that audio source while it’s still needed, Unity will stop me.

Unity Require Component Warning

Require Component helps you to avoid sabotaging your own project.

This also works at runtime, except that instead of seeing a warning like in the image above, if you try to destroy a component that’s required by a script, it will be disabled, instead of removed.

Remember, however, that Require Component only works when adding or removing the script.

So, for example, if you add a script to a game object and then, later, give it a Require Component attribute, Unity will not check for that component, which could then cause an error.

Using Require Component with Get Component is a great way of automating the set up of script components, while still making sure that they have everything they need.

And this can make setting up references on closely linked objects much easier and much more straightforward.

But…

How can you get a reference to a completely different object?

Like the player, or an enemy, or any number of entirely separate game components.

Without making a mess of your project.

Finding different objects in the Scene

As you start to build the different parts of your game you will, no doubt, need each part to connect and communicate with each other.

And while the easiest way to do this is to set it up manually in the Inspector, that’s not always possible.

For example, you might instantiate an enemy that needs to find the player.

Or you might need different game systems to be able to set themselves up at the start of a level.

Luckily though, there are plenty of options available for finding objects in the Scene.

Let’s start with some basic options.

Find GameObject by Name

One simple method of getting a reference to an object is with its name.

Like this:

public class FindObject : MonoBehaviour
{
    public GameObject player;

    void Start()
    {
        player = GameObject.Find("Player");
    }
}

This will return a game object that matches an exact string.

In this case, “Player”.

It’s case sensitive, so you’ll have to type the name of the object exactly.

It can also be slow…

Similar to Get Component, this method searches game objects in the Scene and, as such, it’s not the most efficient option.

So, while it’s ok to use Find sparingly, it’s a bad idea to use it frequently, for example inside of your update loop.

And while it is easy, and can be very convenient, finding an object by its name has a few drawbacks.

For example, if the name of the object changes at any time, the script will no longer be able to find it.

And, if you have multiple objects of the same name in the Scene, there’s no guarantee which object will be returned.

This is unlike other searches, such as Get Component, which is more predictable (searching top down).

To differentiate between objects of the same name, you can use a forward slash to identify a parent and child object, kind of like you would in a file directory.

Like this:

player = GameObject.Find("PlayerObject/Player");

However, this approach is also vulnerable to name changes as well as object hierarchy changes, both of which will cause this method to stop working.

So… what other options are there for finding a game object elsewhere in the Scene?

How to find an object by its tag in Unity

Tags in Unity can be helpful for telling particular objects apart.

Such as in a collision, where you might want to check if an object collided with the player or if the player collided with an enemy by checking its tag.

Like this:

private void OnTriggerEnter(Collider other)
    {
       if (other.tag == "Player")
        {
            // Do Something
        }
    }

That’s not all though,

Tags can also be used to find and store game object references by using Find With Tag.

First assign a tag to the game object you want to find.

For example, the Player Tag:

Set a Tag in Unity

Set an Object’s Tag in the Inspector, or create a new one with Add Tag…

You can also create new tags using the Add Tag… option.

Next find the object using Find With Tag.

Like this:

player = GameObject.FindWithTag("Player");

Find with tag will return the first object that is found in the Scene with a matching tag.

However…

Just like when searching by name, if your Scene contains multiple objects with the same tag, there’s no guarantee that you’ll get the one you want.

That’s why it’s often helpful to use Find with Tag to search for an object when you know it’s the only one with that tag, such as the player for example.

But what if you want to get a reference to all of the objects in a Scene with a common tag?

An enemy tag for example…

How to get multiple objects with tags

Just like Find with Tag, Find Objects with Tag finds objects in the Scene with a certain tag attached, adding them all to an array.

Like this:

public class FindObject : MonoBehaviour
{
    public GameObject[] enemies;

    void Start()
    {
        enemies = GameObject.FindGameObjectsWithTag("Enemy");
    }
}

This is helpful for finding a number of objects of a certain type at once.

However…

Just like Find with Tag, Find Objects With Tag can also be slow, so it’s usually best to avoid using it frequently, such as in an Update loop.

Find Objects of Type

Find Objects of Type can be useful for finding game objects that share the same script or component.

For example you could use it to find all of the audio sources in a Scene .

Like this:

public class FindObject : MonoBehaviour
{
    public AudioSource[] audioSourcesInScene;

    void Start()
    {
        audioSourcesInScene = FindObjectsOfType<AudioSource>();

        foreach(AudioSource audioSource in audioSourcesInScene)
        {
            audioSource.mute = true;
        }
    }
}

This script will find every audio source in the Scene and mute each one.

Or you could find every object with a health script on it…

Like this:

public class FindObject : MonoBehaviour
{
    public PlayerHealth[] objectsWithHealth;

    void Start()
    {
        objectsWithHealth = FindObjectsOfType<PlayerHealth>();
    }
}

Whatever you need it for, Find Objects of Type can be a quick and easy way to manage a group of objects that all share the same functionality.

But… just as with any function that involves searching the Scene, this method can be slow.

And while it may not cause you any real problems when your project is small, as your game grows bigger, using this method to find and manage collections of objects can be slow and difficult to manage.

Using the previous example, instead of finding every Enemy, or every object with Health, it can be easier to, instead, have objects add themselves to a List that other objects and scripts can then check.

And that’s not all. You will likely find that, as you build your project, more and more scripts need to share the same pieces of information.

Information such as the score, the player’s position, health or the number of enemies in a Scene.

To have each script connected to every other script it needs to use could become difficult to manage very, very quickly.

So what’s the best way to manage all of those variables in a game, and make them available to other scripts too?

Without breaking everything.

Global variables in Unity

What are global variables in Unity?

Global variables in Unity generally refer to a variable that has a single value, a single point of reference and that is accessible from any script.

Compared to variable instances on regular scripts, which may have many different instances each with different values on multiple game objects, a global variable’s purpose is to keep track of a single variable’s value for other scripts to reference.

You might use this for the player’s health, the score, time remaining or other game-critical values.

How do you make a global variable in Unity?

There are several methods for creating global variables in Unity.

The simplest method for creating a global variable is to use a static variable.

Static variables in Unity

A static variable in Unity is a variable that is shared by all instances of a class.

To mark a variable as static in Unity, simply add the static keyword when declaring it.

Like this:

public class PlayerHealth : MonoBehaviour
{
    public static float health=100;
}

Then, to access the variable, instead of referring to an instance of the class, you can access it via the class itself.

Like this:

Float hp = PlayerHealth.health;

This works because the variable is public and static, so even if there are many instances of this script, they will all share the same value.

It’s also possible to mark an entire classes as static,

Like this:

public static class PlayerHealth 
{
    public static float health;
    public static float armour;
}

Note, however, that as static classes can’t derive from MonoBehaviour, so you’ll need to remove the normal “: MonoBehaviour” inheritance from the end of the class declaration.

You’d also be forgiven for thinking that this automatically makes every variable inside the class static. It doesn’t.

Instead, marking a class as static simply means that it cannot be instantiated in the Scene.

You’ll still need to mark individual variables and methods inside the class as static for them to work as you expect.

Using statics to create a Singleton game manager

One method of using static variables to manage global references and values is to create a Singleton game manager.

A Singleton uses a single, static, point of entry via a static instance reference.

That way other scripts can access the Singleton, and its variables, without getting a reference to it first.

For example, you could create a script called Game Manager that holds variables such as the score, game time and other important values, and add it to an object in the Scene.

The Game Manager script then keeps a static reference to itself, which is accessible to other scripts.

Like this:

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    public float playerHealth=100;
    public float gameTime = 90;

    private void Awake()
    {
        Instance = this;
    }
}

Notice the Get; Private Set, lines after the variable declaration? Get and Set functions turn a variable into a Property which, simply put, adds a layer of control over how a variable is accessed by other scripts. They can be used to run additional code when setting or getting a variable or, in this case, to prevent the other scripts from setting the instance.

This script needs to be added to an object in the Scene in order to work, so the class itself isn’t static, just its instance reference.

Once it is, however, other scripts can access the manager’s public variables by referencing the Game Manager class and its Instance.

Like this: 

void Start()
    {
        Debug.Log(GameManager.Instance.playerHealth);
        Debug.Log(GameManager.Instance.gameTime);
    }

This is a very basic example of the Singleton design pattern. In practice, when using Singletons, some extra care should be taken to manage the accessibility of variables and to avoid creating duplicate game manager instances in the Scene. See the links section at the end of this article for some more advanced information about using Singletons.

When is it ok to use static variables in Unity?

When used in moderation, and for their intended purposes, static classes, references and variables can be extremely helpful.

However…

While they can be very convenient, relying on them too often, or in the wrong way, can cause problems.

Why?

Well, it depends on how you’re using them.

You may have heard that it’s generally bad practice to use statics (and Singletons for that matter).

But what’s the deal?

Why can’t you use static variables?

When is it ok to use them?

What will actually go wrong if you do?

One of the main reasons for avoiding statics is to prevent encapsulation and dependency issues, given that, unlike class instances, statics are not specific to any one object or scene but are, instead, accessible to the entire project.

This is, of course, exactly why using a static variable can be very convenient, you can access it from anywhere.

But, the same thing that makes a static easy to use, can also cause problems as your project grows.

For example, carelessly connecting multiple scripts together via static references, simply because it’s an easy way to do it, could cause unwanted dependencies between those scripts.

Removing one could break another, or could simply become difficult to manage.

And, while there are legitimate reasons for using statics, as a project gets larger, using them carelessly in this way can cause problems that are difficult to find, test or fix.

Should you never use static variables?

In reality, using static variables sparingly isn’t necessarily a problem, particularly if your project is small, and so long as you understand the right way to use them.

So what is the right way to use them?

Generally, it’s ok to use a static variable for something if there will never be more than one of it.

And I really do mean never…

For example, it might make sense to store the player’s health in a static variable, right?

Like this:

public static class PlayerHealth
{
    public static float hp=100;
}

It’s then easily accessible by player scripts, enemy scripts and the UI.

However…

If you later decide that you’re going to add co-op multiplayer support to your game, and you’ve hard coded the static variable path “PlayerHealth.hp” into every single script that needs to access it, it might be difficult for you to then find and change every reference to that variable to get it to work for a second player.

Also, a health script as a reusable component would ideally be used for players and enemies alike.

Directly referencing a static health variable makes it impossible to reuse the script for anything else.

So how can you leverage the benefit of globally accessible variables, while keeping it modular?

That’s where Scriptable Objects come in…

Scriptable Object variables in Unity

Scriptable Objects in Unity are data containers that allow you to store information independently from script instances in the Scene.

They work differently from regular classes and static classes but are incredibly useful for building a project that is easy to manage.

They are amazingly useful.

No… really!

So how do they work?

When you create a regular class, the class sits in the Project and instances of that class are created in the Scene when they’re added to game objects as components.

Each object’s class instance in the Scene holds its own variable values (member variables) and different objects each have unique data. Such as the health of an enemy, for example.

This is great for creating data that is specific to objects in a Scene.

However…

When you create a Scriptable Object class, the class acts as a template and individual instances are created inside the Project, in the Assets Folder.

Not in the Scene.

Scriptable Objects are, essentially, assets that sit in your project folder but that can be directly referenced from script instances in the Scene.

Now…

If I’ve lost you, don’t worry, because you’ve probably already used assets in this way before.

For example, audio clips function in a similar way to Scriptable Objects.

Audio clips are assets in the Project while audio sources are components that sit on game objects in the Scene.

Audio source components reference audio clips to play them, and changing the audio clip is as easy as dragging a new clip to the audio source’s clip field.

Set Audio Clip in Unity

Scriptable Objects work in a similar way to other Assets, such as Audio Clips.

It’s also possible for two different audio sources to reference the same audio clip without needing a reference to each other.

Neither audio source needs to know that the other exists, yet they can both use the same audio clip.

And removing one, makes no difference to the other.

It’s entirely modular.

Which is the power of Scriptable Objects… modularity.

So how can you leverage the power of Scriptable Objects to manage object references and global variables?

Here’s how to do it…

How to create a global variable using Scriptable Objects in Unity

In the following example, I’m going to create a player health value again, except this time using a Scriptable Object:

Full disclosure, and credit where it’s due, I first discovered this method of using Scriptable Objects as variables from a Unite talk by Ryan Hipple. Whereas I’m using Scriptable Objects to create basic global variables, Ryan’s talk highlights, in depth, how you can leverage Scriptable Objects to structure your game in a very modular way. I strongly recommend watching it in full and I’ll leave a link to the video at the end of this article.

Here’s how it works…

First I need to create a template script that the Scriptable Object assets will derive from.

1. Create a new C# script in the Project Folder:

Create a New Script in Unity

Up until now, you may have only been adding new scripts as components. To create a new script asset in the Project without adding it to an object, right click in the Project View and select New C# Script.

          • Call it FloatVariable, this Scriptable Object template will form the template for any Float Variable Scriptable Objects you make.

Scriptable Object Template class

          • Open it up and replace MonoBehaviour with ScriptableObject so that it inherits from the Scriptable Object class.
public class FloatVariable : ScriptableObject
          • Next, declare a public float variable called value.
public float value;
          • Lastly, before the class declaration, add a line that reads:
[CreateAssetMenu(menuName = "Float Variable")]

This allows assets of this Scriptable Object to be created from the Project view’s Right Click Menu. This is important as, without this, you won’t easily be able to create Scriptable Objects from this template.

Your script should now look something like this:

using UnityEngine;

[CreateAssetMenu(menuName = "Float Variable")]
public class FloatVariable : ScriptableObject
{
    public float value;
}

That’s all that’s needed to create the Template, now to create Script Instances that can hold unique data.

2. Next, create a Float variable asset from the Scriptable Object template

          • In the Project View right click and select Create > Float Variable

Create a Scriptable Object in Unity

          • Name the newly created Scriptable Object something sensible, like PlayerHP

Player Health Scriptable Object

          • Select the newly created Scriptable Object, and set a starting value in the Inspector, e.g 100.
Set Global Variable in Inspector

Set the starting value in the Inspector, I’ve used 95 here but 100 would make more sense, don’t you think?

Scriptable Object values, unlike member variables, do not reset when the Scene changes or even when you exit Play Mode. This means you’ll need to manually change the value when you want to reset it.

In this example, to reset the player’s health, you could create a second Float Variable, called DefaultHealth, that stores the starting health of the player, and then simply set the player’s health at the start of the Scene using that value as a reference.

So now you’ve created a variable template and a variable instance, how can other scripts use that value?

3. Reference the Scriptable Object from scripts in the Scene

Finally, to reference the global player health value from any script:

          • Create a public FloatVariable variable on any other script. Call it playerHealth, just as an example (the name does not need to match the Scriptable Object)
public FloatVariable playerHealth;
          • In the Inspector, set the FloatVariable to reference the PlayerHP Scriptable Object (click and drag it, or use circle select).
Select a Scriptable Object Variable in the Inspector

Selecting the Scriptable Object works just like selecting any other asset.

You can then use the variable like any other float, making sure to remember to use the Dot Operator to access its actual value.

Like this:

using UnityEngine;

public class PlayerHealth : MonoBehaviour
{
    public FloatVariable playerHealth;

    void Start()
    {
        Debug.Log("The player's health is: " + playerHealth.value);
    }

    void TakeDamage(float damageTaken)
    {
        playerHealth.value -= damageTaken;
    }
}

Tip: Remember to type playerHealth.value when accessing the variable, not just playerHealth, which won’t work.

Now, any script can access the same variable directly, without needing a reference to any other object.

So what’s so great about this?

And how is it any better than a static variable?

I’ll explain…

Scriptable Object global variables vs static variables

Using Scriptable Objects for global variables can be much, much more flexible than using static variables.

This is because, while a static reference is written directly into the script, a Scriptable Object based variable only needs a reference to a variable of that type.

How is that better?

In the example above, I used a Scriptable Object variable to keep track of the player’s health, in this case using an instance of my Float Variable template.

So, any time I want to access the player’s health (from any Script in the project) I simply make a reference to a Float Variable Scriptable Object and then drop in the PlayerHP instance.

Like this:

public FloatVariable playerHealth;

What’s great about this is that, just like swapping out audio clips, I can use any Float Variable Scriptable Object in its place.

For example for a second player.

All  I’d have to do is create another Scriptable Object Float Variable called Player2HP and use that instead.

All without ever editing the script.

It’s this flexibility and modularity, that makes Scriptable Object variables so incredibly useful.

Now it’s your turn

Now I want to hear from you.

How will you use these tips in your project?

What’s worked well for you in the past?

What hasn’t? And what did you wish you knew when you first got started in Unity.

Whatever it is, let me know by leaving a comment below.

From the experts:

Ryan Hipple explains how to avoid Singletons and use Scriptable Objects as variables:

Jason Weimann describes the different types of Singleton Patterns he uses and some common pitfalls to avoid:

by John Leonard French

Game audio professional and a keen amateur developer.

Get Helpful Game Development Tips, Straight to Your inbox

Get access to exclusive tips & tricks and master game development basics the easy way, with deep-dive tutorials and guides.

Popular Posts

Image credits

Comments

  1. I don’t know if it’s a good idea to show scriptable objects before explaining the importance of private variables for instances and getters/setters.

    It’s like showing the window before explaining there’s a door and a key to open and close access as you need (rather than jumping through the window everytime just because it doesn’t need a key)

    Other than that, amazing explanation

    1. Author

      Thanks for the feedback, the focus of this article is making a connection to another script/variable, which I found to be a nightmare as a beginner, but I accept that properties and particularly public/private are related to this so I may expand the article a bit to include those. Thanks again.

  2. Good article for beginners. I think the way that Ryan Hipple uses scriptable objects is really interesting.

    I tried doing things like this but I like to have really generic Actors who have the ability to hit any other Actor with health in a scene so I use the traditional GetComponent().DoDamage(damage) approach.

    I think the SO’s are a really good idea for things like a tower defense or whatever where if an enemy gets to the end, they can call playerLives.ReduceLives() since there’s only one player.

    Going slightly more advanced where you’re talking about what you want to happen when the player is acted upon or does some sort of action: I think you could write something about how important events (delegates) are for creating untangled code.

    Ex. Player class has an OnPlayerDamaged event that gets fired upon taking damage, any class listening for the event (like the PlayerAudio or AudioManager) would then play a damage sound when that event gets invoked.

    1. Author

      Thanks! It’s definitely a separate article but yes, events are super important, especially to avoid polling. I also really like the Scriptable Object even approach (as seen in Ryan’s talk) I found it easier to get started with.

  3. Wow! This is a really good tutorial/explanation. It’s a pretty fundamental topic, but I haven’t yet happened upon a thorough explanation about it such as this. You’re presenting and comparing all options, asking and answering obvious questions, explaining (dis-)advantages…

    This is how you teach, folks!

  4. After reading 3 articles I subscribed. Very useful tutorials, just some slight changes and it will fit in perfectly to my game. Thank you very much! The explanations are very detailed, better than Unity Manual itself lol. I hope you can make a tutorial about data saving pls I saw people using PlayerPrefs and people saying NOT to use PlayerPrefs 🙁

    1. Author

      Thanks! I hadn’t realised that some people didn’t like them, I’ll add it to my TO DO list. Thanks for the tip.

  5. Hi John – I thought this was a really fantastic introduction. Thanks for taking the time to write this. Cheers – Dave

  6. I also suggest researching in the way of IoC. IoC Containers could provide great linking variables from script to script using Injections, but without a lot of dependencies. The best one for Unity is Zenject. But anyway you will use some of the approaches that you described above.

    Good luck!

  7. You are a lifesaver man and your blog is offering the best tips on useful stuff in Unity.
    Thank you, keep up the awesome job!

  8. Hi John,

    I stumbled across your stuff while tinkering with my own game effort…

    I’ve immediately subscribed, and bought one of your assets on the Unity Asset store too (the Ultimate Game Music Collection). Probably not the last.

    Thanks for such clear and methodical explanations and resources… and as for your music… Nordic Landscape – wow.

    Well it’s fantastic to be reminded of why we play games and pursue Art in the first place.

    Thanks for what you’re doing. You deserve every success.

  9. I came in for a quick and dirty fix; searching for how to GetComponent when it is associated with a different GameObject.
    Your explanation is extremely exhaustive. Daunting at times, but invaluable for people with minimal background. So hell yes, thank you!
    And keep it up. Exactly as you do – exhaustive and thorough!

  10. I use the approach of Scriptable Objects all the time because I like the idea of having my data separate from logic and allowing things to listen for when the data changes (instead of having objects linked directly to each other). I also like the flexibility it gives the design team.

    However, I can’t see using Ryan Hipple’s approach exactly as presented. I’ve never seen anyone explain how having SOs just for variables doesn’t have a negative impact on performance. A simple game with 1 player character and 10 enemies could have a 100 variables that need to be tracked just for those objects (let alone everything else).

    No negative reflection on you though. You did a great job explaining the options just think people need to know there is an overhead cost to creating SOs that regular variables don’t have.

    1. Author

      Thanks for your feedback! I hadn’t considered that there could be a performance impact to using scriptable objects but I’ll try and run a test to see what I can find out about it for the article. In reality, there’s probably a middle ground that’s efficient and convenient. Thanks again.

Leave a Comment