Encapsulation
What you need to know
Introduction
Encapsulation is a key principle of object-oriented programming. If you have ever wondered why some fields are initialized as private, public, or have the word Serialized Field listed before the field type? Unfortunately, most Unity tutorials for beginners do not mention why this is done or the importance of it. This article will try to correct that.
About
- Subjects: C# and Unity
- Objective: To cover the principle of encapsulation and its importance to game development.
- Development Time: 5 min
Getting Started
Fields
Fields are the variables that are initialized in a C# class before the constructor or at the top of the class. These are used to store data that is used throughout the class or data that may need to be accessed by other classes. This is in contrast to variables that are used only inside a single method, these should be stored in local variables set inside the method.
public class Health
{
private float health;
public float healthMax;
Public Health(float health)
{
this.health = health
this.healthMax = health
}
}
Public fields are most commonly seen in Unity tutorials. That is because it makes them easy to access outside of the script and they appear inside the Unity editor where they can be modified and assigned values. While this is great for testing and building quick prototypes, it can become dangerous and confusing as your project progresses and you add complexity, you forget the specifics of how you implemented the class.
Private fields solve some of our problems by protecting the data from being accessed outside the class. You may be thinking “But, how do we get to the data or modify it?” and the answer to that is methods. By using methods to access our data we can solve our second issue with public fields, forgetting how it was implemented. With methods we are able to perform checks and place limitations on how the data is retrieved or modified. There are two types of methods we use to access our data.
Getters
Getters are used to retrieve data from fields. Most of these could be simply stated as
public int GetHealth()
{
return health;
}
They can also serve another purpose of helping us avoid code duplication and reducing the fields in our class. If for instance if we have a Health class we can just create one field called healthMax with the type float and we can have methods for GetHitPoints() and GetHealthPrecentage() without having to store a variable for each and without have to duplicate code for calculating percentage everywhere we need it.
public float GetHealthPercent()
{
return health / healthMax;
}
Setters
Setters are used to modify or data. Again, these can be as simple as
public void SetHealth(float newHealth)
{
Health = newHealth;
}
Setters can also allow us to do checks on the data being passed in. For instance, if you want to heal the player you could create the method setHealth(float amount).
public void setHealth(int healAmount)
{
if(healAmount < 0)
{
Debug.Log("Heal Amount is below zero");
}
else if(health + healAmount <= healthMax)
{
health += healAmount;
}
else
{
health = healthMax;
}
}
This method takes in the heal amount and checks to make sure it is not outside the bounds you specify, in this case above -1 and below 101.
Great now all your fields are now private, and you have the getters and setters you need. But, you may have noticed a problem. We cannot access this data in the Unity editor. Sticking with the same health system, we cannot assign our initial health value. This is where SerializedField comes to the rescue.
SerializeField
For our purposes, SerializeField tells the editor that this field is private and needs to be shown in the editor.
[SerializeField]
private float health;
[SerializeField]
private float healthMax;
Now our fields are protected from inappropriate access and from our future selves and others that will need to use our scripts.
There are a few more nuances to SerializeField that the documentation covers. The important thing to know is what can and cannot be serialized.
The serialization system can do the following:
– CAN serialize public non-static fields (of serializable types)
– CAN serialize nonpublic non-static fields marked with the SerializedField attribute.
– CANNOT serialize static fields.
– CANNOT serialize properties.
Serializable types
Unity can serialize fields of the following types:
– All classes inheriting from UnityEngine.Object, for example GameObject, Component, MonoBehaviour, Texture2D, AnimationClip.
– All basic data types, such as int, string, float, bool.
– Some built-in types, such as Vector2, Vector3, Vector4, Quaternion, Matrix4x4, Color, Rect, LayerMask.
– Arrays of a serializable type
– Lists of a serializable type
– Enums
– Structs
Wrap-up
Encapsulation helps us protect our data while future proofing our scripts. It allows others to use our classes without knowing how things are implemented. Privatizing our fields keeps them safe from inappropriate access. Getters allow access to our data and can reduce the need for additional fields. Setters provide safety checks and limitations on how our data is set. Finally, SerializeField provides the convenience of modifying/assigning data in the Unity editor while still keeping our data safe.
And now you are ready to start encapsulating the code in your own games created in Unity. Thank you for stopping by. Stick around and check out more of our tutorials or posts like our piece on How to Build a Calculator in Unity. Also, leave a comment telling us what you liked or did not like about the tutorial. Was it easy to follow along? What do you want to learn next? As always, check out some of our published apps below.
Instead of Setters & Getters we can also use Properties. Isn’t it???