Abstraction is one of the most important things to master in programming. In this article, we will explain what it is and how we can improve our code in Unity using abstraction.
Abstraction improves code because it hides how things work from other code. As a result, the code becomes easier to understand and more uniform.

In This Article

What Is Abstraction?
The best way to describe abstraction is to explain it with a real world analogy. Right now, you are looking at this page on a browser. Intuitively, you understand how the browser connects to the internet and displays pages. However, you are not fully aware of how it works in detail. You are not concerned with what protocols are used or what javascript code is running in the background. All you care about is getting to the page and reading it.
In simple words, abstraction leaves us in the dark about how things really work. It basically acts as a simplification. While this might make you feel stupid it should actually be seen as a good thing. Imagine if you need to know how your entire phone works to just send.a text message. That would be crazy! As you may have noticed, technology is essentially a huge hierarchy of abstractions on top of each other.
What is Abstraction in Programming
When we talk about abstraction in programming, we simply mean that we hide information for parts of code that don’t need to know. This way, we cut up the code into little chunks that each have their own responsibility. While abstraction dumbs down the code, it also simplifies it and makes it easier to understand.
Why Use Abstraction in Programming
As mentioned before, we use abstraction in programming to simplify the code. Using abstraction, we make it more intuitive for programmers to understand what the code is doing, without going into too much detail. However, it’s not just purely about simplification. Abstraction in programming also deals with unification, meaning that we try to interact with sections of code in the same way. So, what does this all mean? Let’s start by examining some examples of how we can improve our code in Unity using abstraction.
How To Use Abstraction In Unity
Of course, there are a number of ways how we can use abstraction in Unity. To make it more clear, we have listed several ways how you can start implementing abstraction into your code right now.
Below we will discuss how to use abstraction in Unity through:

Abstraction Through Functions In Unity
The easiest way to use abstraction in Unity is through functions. Let’s say we want to determine the distance between a player and an enemy. Todo this, we could use the code listed below. However, do you notice that it requires understanding of the pythagorean distance formula?
Player.cs
public class Player : MonoBehaviour { private void Update() { Vector3 axis = enemy.transform.position - transform.position; float d = Mathf.Sqrt((axis.x * axis.x) + (axis.y * axis.y) + (axis.z * axis.z)); Debug.Log("The distance to the player is " + d); } }
Clearly, we can simplify the code using the Vector3.Distance() method. After all, Unity has provided this function for it, so why not use it? By using the Vector3.Distance() method, we have created an abstraction of the original code. We no longer have to understand how the method works, as long as we are able to use it correctly.
Player.cs
public class Player : MonoBehaviour { private void Update() { float d = Vector3.Distance(enemy.transform.position, transform.position); Debug.Log("The distance to the player is " + d); } }
As we can see, the snippet above is much easier to read. Next to that, by using Vector3.Distance() method, we have unified the code some more. This means that every time we calculate the distance in our code, we can use the Vector3.Distance() method.
Abstraction Through Classes In Unity
Another way how we can improve our code in Unity is by using abstraction in classes. We can use classes in a similar way to how we used a function to hide details about the code. Imagine a scenario where we damage the player whenever a bullet collides with it. In the snippet below, we have implemented this exact scenario in a very naive way:
Bullet.cs
public class Bullet : MonoBehaviour { [SerializeField] private float m_Damage = 2.0f; private void OnCollisionEnter(Collision collision) { Player player = collision.gameObject.GetComponent<Player>(); player.Heatlh -= m_Damage; } }
Problems of Classes Without Abstraction
Notice how the Bullet class is fully aware of how it damages the player. All the details on how to do this are written down. First, it retrieves the Player component, then it accesses its Health property and lastly it subtracts the applied damage.
Also, think about what happens if we decide to add another type of weapon that shoots projectiles at the player. This Projectile class too needs to subtract health from the player whenever they collide. Yet, it would be messy to have a Bullet and a Project class have similar code. So what can we do?

The Difference Between Have to And How to
Important to understand is that the Bullet and Projectile classes only need to know that they have to damage the player. Yet, both the Bullet and Projectile classes don’t need to know how they damage the player. This is a very important distinction to make when it comes to applying abstraction in programming.
Using Abstraction with Classes in Unity
Preferably, we would like to hide details as much as possible while also trying to unify them. Clearly, both Bullet and Projectile classes are trying to do the same thing. So unifying the code should be pretty easy.
To improve the code using abstraction, let’s add a new method to the Player class. We will call this method ChangeHealth and it will change the health of the player accordingly. Next, we will create a new class called PlayerHealthModifier that will act as a go-between for the Player and Bullet classes.
Player.csPlayerHealthModifier.cs
public class Player : MonoBehaviour { [SerializeField] private float m_Health = 10.0f; public void ChangeHealth(float change) { m_Health += change; } }
public class PlayerHealthModifier { public void ChangeHealth(float change) { Player player = FindObjectOfType<Player>(); player.ChangeHealth(change); } }
Next, we also have to change how the Bullet class applies its damage to the player. In the snippet below, you can see what this looks like.
Bullet.cs
public class Bullet : MonoBehaviour { [SerializeField] private float m_Damage = 2.0f; private void OnCollisionEnter(Collision collision) { PlayerHealthModifier healthModifier = new PlayerHealthModifier(); healthModifier.ChangeHealth(-m_Damage); } }
Using Abstraction in Unity using Mediators
As you can see, any type of Bullet class is now able to change the health of the player in a uniform way. They can do this through the PlayerHealthModifier class that acts as a go-between. This class automatically finds the instance of a Player and changes its health accordingly.
Creating such a go-between is called a Mediator or a Proxy. As a result, the Bullet class no longer has a dependency on the Player class. From now on, a bullet can simply create a new instance of the PlayerHealthModifier and change the player health however it sees fit.
Finally, notice that the Bullet class understands that it has to change the health, yet doesn’t necessarily know how to change the health. The details are now hidden within the Player class through the PlayerHealthModifier mediator.
Using Unification to Improve Abstraction in Unity
Now that we have a class that handles health changes for the player, we can utilize the same code for other functionality. Instead of subtracting health from the player, we can also use the PlayerHealthModifier to increase the health of the player. In the code below, you can see how we have created a HealthPickup class. This pickup increases the player health whenever it colliders with the player.
HealthPickup.cs
public class HealthPickup : MonoBehaviour { [SerializeField] private float m_Repair = 5.0f; private void OnCollisionEnter(Collision collision) { PlayerHealthModifier healthModifier = new PlayerHealthModifier(); healthModifier.ChangeHealth(m_Repair); } }
As can be seen above, we have simplified the code by creating a new class that has the sole responsibility to change the player health. Next to that, the code is more uniform as multiple classes can reuse the PlayerHealthModifier class.
Abstraction Through Delegates in Unity
Another way to implement abstraction is through delegates. Similar to an earlier example, we can use delegates to handle health changes for the player. Instead of using a method we will create a new delegate. This delegate can be invoked by both the Bullet and Projectile classes. Using a delegate, we can improve code in Unity using abstraction in a similar way as functions do.
Player.csBullet.cs
public class Player : MonoBehaviour { [SerializeField] private float m_Health = 10.0f; public delegate void ChangeHealthEvent(float change); public ChangeHealthEvent ChangeHealth; private void Awake() { ChangeHealth += UpdateHealth; // Or use a lambda ChangeHealth += (change) => m_Health += change; } private void UpdateHealth(float change) { m_Health += change; } }
public class Bullet : MonoBehaviour { [SerializeField] private float m_Damage = 2.0f; private void OnCollisionEnter(Collision collision) { Player player = collision.gameObject.GetComponent<Player>(); player.ChangeHealth.Invoke(-m_Damage); } }
Abstraction Through Polymorphism In Unity
The most complex form of abstraction is through polymorphism. We will discuss this form of abstraction in an upcoming article as a follow up. Please, keep an eye out for that!
Best Practices for Abstraction
In order to make the most of abstraction in your code, we recommend you to follow these guidelines:
- Try to always consider if your code Has to do it or How it has to do it
- Try to look for areas of the code that can be unified.
- Try to keep your classes under 500 lines of code. If it’s longer you should consider using abstraction.
- Try to keep your functions under 100 lines of code. If it’s longer you should consider using abstraction.

Summary
What you learned in this article:
- Abstraction leaves us in the dark about how things really work
- With abstraction in programming, we simply mean that we hide information for parts of code that don’t need to know
- Using abstraction, we make it more intuitive for programmers to understand what the code is doing,
- Abstraction in programming also deals with unification, meaning that we try to interact with sections of code in the same way.
- Using abstraction, we no longer have to understand how a method or class works as long as we are able to use it correctly
- When using abstraction in programming, we are more concerned with Having to do Something rather than How to do Something.
- Try to keep your classes under 500 lines of code
- Try to keep your functions under 100 lines of code

Conclusion
To conclude, we now know what abstraction is and how using it helps improve our code in Unity. Whenever trying to use abstraction, always make sure that your ask yourself whether code Has to do something or whether it should know How to do something. Finally, we have also shared some best practices on how to use abstraction in your code.
Further Reading
Other articles you may find interesting:
