How to use Get and Set (without crashing Unity)

In Scripting Basics by John FrenchPublished 4 Comments

When you first start learning how to use Unity, you’ll probably make the variables in your scripts either public or private, depending on whether or not you want other scripts to be able to access them.

Which is fine.

However, as the relationships between your scripts become more and more complex, you might find that you want more control over how the values in your game are read, which scripts can change them and what happens when they do.

For example, you might want other scripts to be able to read a variable, but not set it.

Or you might want to modify an incoming value before it’s updated, such as by clamping it within a set range.

You could even check if a new value is different from the current variable, and raise an event for other scripts to respond to when it’s actually changed.

In Unity, it’s possible to control what happens when a variable is accessed by turning it into a Property, which separates a variable’s Get and Set functions, allowing you to write your own, custom, access code.

So how do properties in Unity work? And when should you be using them?

How to use properties in Unity 

In simple terms, a property is made up of two variables:

  • A public variable, for other scripts and classes to access
  • And a private backing field, which is the real value that only the property’s class can change

The public variable will normally have the same name as the private one, except that it’ll be capitalised.

Like this:

private float health;
public float Health;

Right now, however, there’s no connection between the two variables, meaning that accessing the public Health value won’t change the real float that’s behind it.

To do that, you’ll need to use the Get and Set accessors.

How Get and Set work in Unity

Get and Set are accessor functions that can be used to change what happens when you read or write to a variable.

Normally, when you Get a variable, you’re reading the value of it, and when you Set a variable, you’re changing it to a new Value that you’ve passed in.

The get and set accessors give you custom control over this process meaning that, instead of changing the public variable, you can use them to change the private one instead, creating a Property.

Like this:

private float health;
public float Health
{
    get { return health; }
    set { health = value; }
}

The get accessor must return a value, in this case whatever the backing field is set to, while the set accessor uses the value keyword to set the backing field to whatever value has been passed to it.

But why bother with any of this?

After all, as it is now, the property is simply setting and reading the private backing field in the same way that any normal variable would, just with extra steps.

So what’s the point of using Get and Set?

When would you use a property in Unity?

The purpose of using get and set is to give you more control when variables are accessed and what happens when they actually are.

For example, you might want to limit a health value to a specific range.

Like this:

float health = 100;
public float Health
{
    get { return health; }
    set
    {
        health = Mathf.Clamp(value, 0, 100);
    }
}

And while you could do this elsewhere in your script, or in other scripts when the value is set, doing it where the value is actually modified makes the most sense and will be easier to find if you ever want to change how it works.

Executing code when a value is changed allows you to also check if certain conditions have been met.

For example, when modifying a health value, you might want to check to see if it’s dropped below zero, and then run additional code if it has.

Like this:

bool alive = true;

float health = 100;
public float Health
{
    get { return health; }
    set
    {
        health = value;
        if (health < 0 && alive)
        {
            alive = false;
            Debug.Log("Player has died!");
        }
        health = Mathf.Clamp(health, 0, 100);
    }
}

Lastly, it’s possible to use get and set to make a variable that can be read but not written.

This works by making the set accessor private, meaning that while other classes can read the value using the publicly available get accessor, they can’t change it.

Like this:

float health = 100;
public float Health
{
    get { return health; }
    private set { health = value; }
}

This essentially makes the variable read only to other classes, which can be useful when you have a publicly available reference that you don’t want other scripts to be able to change, such as when using a Singleton, for example.

How to make a variable read-only in Unity 

A private set accessor can be used to prevent a variable, that’s otherwise publicly accessible, from being changed by other classes.

This is different to the read only keyword which is an accessibility modifier, like public or private, and that prevents a variable from being set after it’s first initialised.

Protecting a variable from being changed is a common use for properties, as it allows you to still access the value externally, but without accidentally changing it.

However, if this is all you need from a property, creating two variables for each value you want to create can clutter up your project.

Instead, it’s possible to create a basic property without declaring a second variable by using an auto-implemented property instead.

Auto-implemented properties

An Auto-Implemented Property is a simpler version of a regular property that can be used when you don’t need to introduce any additional logic.

Normally, when creating a property, you’d need to manually create a backing field, which is the private variable that the public property reads from.

However, if all you want to do is limit the accessibility of the property, such as to remove the set accessor, or make it private, for example, it’s possible to do that using just one variable all on one line.

This works by adding get and set accessors to a variable, but without declaring their bodies.

Like this:

public float Health { get; private set; }

However, while this can be very convenient, it’s important to only use auto-implemented properties for changing a variable’s accessibility, not for running additional logic, otherwise you’re likely to crash Unity when you try to use it.

Why Unity crashes when using an auto-implemented property

Auto-implemented properties still use a backing field, just like manually created ones do.

However, the difference is that, unlike when making a property yourself, auto-implemented backing fields are created anonymously, by the compiler, meaning that you won’t be able to access it.

This is a problem, because it means that, if you try to add any kind of logic to the get or set accessors, the only value that you’re going to be able to use is the publicly available variable.

Like this:

// IMPORTANT
// Don't do this, it will crash Unity!!

public float Health
{
    get { return Health; }
    set { Health = value; }
}

This isn’t how properties work.

The point of a property is that it provides access to a different value, the backing field, not itself.

Meaning that if you try to use any kind of logic with an auto-implemented property, you’re likely to create an infinite loop, which will crash Unity.

How to show an auto-implemented property in the Inspector

Another drawback with auto-implemented properties is that they’re not, typically, visible in the Inspector.

Variables with get and set accessors aren’t normally serialisable meaning that, even if they’re public, they won’t show up.

When creating a property manually, you can get around this by serialising the backing field instead.

Like this:

[SerializeField] float health;
public float Health { get; private set; }

But, when using an auto-implemented property, the backing field is anonymous, so how can you serialise it?

Luckily, it’s possible to use the Serialize Field attribute, but target the backing field of an auto-implemented property instead of the publicly available variable, causing it to show in the Inspector.

Like this:

[field: SerializeField] public float Health { get; private set; }

Now it’s your turn

Now I want to hear from you.

How are you using properties in your game?

Are you using them to keep variables private?

Or are you processing other logic when values are read or written?

And what have you learned about using get and set in Unity that you know someone else would find useful?

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

John French profile picture

by John French

Game audio professional and a keen amateur developer.

Get Game Development Tips, Straight to Your inbox

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

How to CODE in Unity. Available to Pre Order Now. Game Dev Beginner.

Comments

  1. Thanks buddy for this nice, simple and well explained tutorial. This is helpful!

  2. Whoa, it’s eye opening article. I need to rethink my choices 😀
    Thanks John!

Leave a Comment