How To Improve Code in Unity by Using Enums

Are you using a lot of value types like integers, and booleans in your code to keep track of things? For example, do you use an integer that holds the value of the currently held weapon? Perhaps you determine whether the player is alive or dead through a boolean variable. In this article, we will show you how you can improve code in Unity by using Enums.

Learn how to improve your code in unity by using enums

What is an Enum in C#

Many programming languages offer Enumerations as a language feature and C# is no different. While the syntax to define Enumerations is different across languages, they all help developers in the same way. Most importantly, Enumerations offer developers a way to create a list of constants that can be managed more easily than regular constants. You can also view Enumerations as giving a developer a list of choices rather than a list of constants. Looking at the snippet, you can see an example of a PlayerSkills Enum in C#.

PlayerSkills.cs
  1. public enum PlayerSkills
  2. {
  3. Melee,
  4. Magic,
  5. Sneaking,
  6. Crafting
  7. }

Enum inside Unity Inspector
Enum directly appears in the Unity Inspector

How to Use Enums in Unity

In order to start using Enums in Unity, you don’t need to do anything. This is because Enums are a standard language feature of C# and Unity understands how to work with them. After declaring and using an Enum in your code, they instantly appear inside the Unity inspector. In the code below, we are using the PlayerSkills Enum that we previously declared inside a Player class using the SerializeField Attribute.

Player.cs
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4.  
  5. public class Player : MonoBehaviour
  6. {
  7. [SerializeField]
  8. private PlayerSkills m_CurrentSkill;
  9. }

The Advantages of Using Enums in Unity

Now that we know how to use Enums inside of Unity, you might also wonder why we should bother. After all, whether your code works or not is the most important thing, right? Actually, good code is not just measured by whether it works or not. To be clear, good code is also measured by how maintainable it is, meaning how easy it is to change code in the future. We can improve the maintainability of our code in Unity using Enums.

The advantages of using enums in Unity

How Enums Improve the Readability of Code

One way to ensure the maintainability of your code is to make it more Human Readable. The more Human Readable your code is, the easier it is to understand for yourself and other developers. When it comes to enums, they make the code more intuitive and easier to read.

In the code below, the Enum version of the LoadSaveGame method is much easier to read through compared to the boolean version. Instead of returning false, you will see that the method is returning an error named SaveGameNotFound.. Rather than asking yourself what true or false means for this method, the code documents itself.

ErrorCode.cs
  1. public enum ErrorCode
  2. {
  3. None = 0,
  4. SaveGameNotFound
  5. }
  6.  
GameManager.cs
  1. using System.IO;
  2. using UnityEngine;
  3.  
  4. public class GameManager : MonoBehaviour
  5. {
  6. // Load a SaveGame using a method that returns an Enum
  7. public ErrorCode LoadSaveGameUsingEnum(string filename)
  8. {
  9. if(!File.Exists(filename))
  10. {
  11. return ErrorCode.SaveGameNotFound;
  12. }
  13.  
  14. return ErrorCode.None;
  15. }
  16.  
  17. // Load a SaveGame using a method that returns a boolean
  18. public bool LoadSaveGame(string filename)
  19. {
  20. if(!File.Exists(filename))
  21. {
  22. return false;
  23. }
  24.  
  25. return true;
  26. }
  27. }

How Enums Make Code More Flexible

Next, compared to other constants, Enums can be expanded and given default values. Another neat feature is that the values of an Enum increment automatically in the order that you define them. This means that when you expand an enum, newly added values will automatically be greater than the values before it.

Continuing the earlier example, we now add new functionality that checks if the save game that we are loading is still compatible with the game. To start, we add a new SaveGameNotCompatible value to our Enum and return it in the LoadSaveGame method whenever the save game is not compatible. As you can see, this would have been more tedious using the method that simply returned a boolean.

ErrorCode.cs
  1. public enum ErrorCode
  2. {
  3. None = 0, // Has Value of 0
  4. SaveGameNotFound, // Has Value of 1
  5. SaveGameNotCompatible, // Has Value of 2
  6. }
GameManager.cs
  1. using System.IO;
  2. using UnityEngine;
  3.  
  4. public class GameManager : MonoBehaviour
  5. {
  6. // Load a SaveGame using a method that returns an Enum
  7. public ErrorCode LoadSaveGameUsingEnum(string filename)
  8. {
  9. if(!File.Exists(filename))
  10. {
  11. return ErrorCode.SaveGameNotFound;
  12. }
  13.  
  14. if(!SaveGameNotCompatible(filename))
  15. {
  16. return ErrorCode.SaveGameNotCompatible;
  17. }
  18.  
  19. return ErrorCode.None;
  20. }
  21. }

Of course, loading a save game is not the only problem that can occur in your game., For example, you might run into problems while storing the settings as well. Luckily, it is really easy to expand the error codes that we are supporting by extending the Enum: We can even reserve some space for future save game error codes.

ErrorCode.cs
  1. public enum ErrorCode
  2. {
  3. None = 0, // Has Value of 0
  4.  
  5. SaveGameNotFound, // Has Value of 1
  6. SaveGameNotCompatible, // Has Value of 2
  7.  
  8. // (3-9 Reserved for future SaveGame Error Codes)
  9.  
  10. SettingsFileNotFound = 10, // Has Value of 10
  11. SettingsFileNotCompatible // Has Value of 11
  12. }

How Enums Make Code Easier to Debug

Another advantage of using Enums is that they make it easier to debug code. Not only because they improve the readability of the code, but also because Enumerations make debugging more intuitive. Instead of dealing with constant values, you will be reading code that is more akin to human language.

In the example below, we added some extra debug logging that will print the result of the LoadSaveGame method. In this case, we are attempting to load the most recent save game and log the results to the Unity Console if it fails. However, rather than printing out the value of the constant (either 1 or 2), it will actually print out SaveGameNotFound or SaveGameNotCompatible.

GameManager.cs
  1. using UnityEngine;
  2.  
  3. public class GameManager : MonoBehaviour
  4. {
  5. public void LoadRecentSaveGame()
  6. {
  7. ErrorCode result = LoadSaveGameUsingEnum("recent.save");
  8. if(result != ErrorCode.None)
  9. {
  10. Debug.LogError("Could not load save game: " + result);
  11. }
  12. }
  13. }

Where to Use Enums in Unity

Now that we know how to use Enums in Unity and what some of the advantages are, you be wondering where to actually use them. After all, if we want to improve our code In Unity using enums, we have to know where to use them. Generally, we use an enumeration in Unity when dealing with constants or storing state.

Where to use Enums in Unity

Using Enums to Create a Constant

To start, the obvious usage of Enums is to use them to create some sort of a constant. Imagine the scenario where you are prototyping a racing game where, due to various reasons, the player might not finish. As the game is still in a very early stage of production, it is not exactly known yet what can cause the player not to cross the line. In this scenario, it makes sense to implement the different reasons for finish as an Enumeration. The reasons why the race ended is flexible and can be used throughout the game as constants.

RaceEndReason.cs
  1. public enum RaceEndReason
  2. {
  3. Finished,
  4. RanOutOfFuel,
  5. Crashed,
  6. DidNotFloat,
  7. CarGotTeleportedToAnotherDimension,
  8. Expired
  9. }

Using Enums to Create a State

Another useful reason to use enums is to create and store a state. A simple example is a state that a developer can use to check whether the player is alive. Initially, it might make sense to implement this as a boolean. Yet, as the the game progresses, more complex player logic might be needed. For example, enemies can only attack when the player is alive. Yet, they should not immediately attack the player while (re)spawning. Simply put, the state of the player is no longer binary (either true or false). In this case, it also makes sense to implement the player state as a Enum.

PlayerState.cs
  1. public enum PlayerState
  2. {
  3. Alive,
  4. Dead,
  5. Spawning,
  6. VictoryDance // Dance when level is complete.
  7. }

Using Enums to Create an Indexer

Next, we can utilize Enums to create an indexer. For example, imagine you are developing a prototype where a player has to actively manage their inventory. Despite the fact that the designers assure you there won’t be more than 3 different inventory slots, you decide to implement the slots using an Enumeration. In the code below, you can see how an Enumeration is used to change an item in a list.

SlotType.cs
  1. public enum SlotType
  2. {
  3. Primary,
  4. Secondary,
  5. Utility
  6. }
Player.cs
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4.  
  5. public class Player : MonoBehaviour
  6. {
  7. [SerializeField]
  8. private List<GameObject> m_Weapons;
  9.  
  10. public void ChangeWeaponForSlot(GameObject weapon, SlotType slot)
  11. {
  12. m_Weapons[(int)slot] = weapon;
  13. }
  14. }

Advanced Enum Features

Next to using enums to improve your unity code, they come with a few other cool tricks that we want to mention. Firstly, they allow you to a create default values which van be referenced throughout the project. Secondly, similarly to defining a default value, you can create a size value. This value represents the total number of values in your enum. You can see how both these advanced features work in the snippets below:

ClassType.cs
  1. public enum ClassType
  2. {
  3. Warrior,
  4. Paladin,
  5. Bard,
  6.  
  7. Size, // The number of useful values in this enum
  8. Default = Warrior // A value that can be used as default.
  9. }
Player.cs
  1. using UnityEngine;
  2.  
  3. public class Player : MonoBehaviour
  4. {
  5. [SerializeField]
  6. private ClassType m_ClassType = ClassType.Default; // A warrior by default
  7.  
  8. private void Awake()
  9. {
  10. // Print out all available class types..
  11.  
  12. for(int i = 0; i < (int)ClassType.Size; i ++)
  13. {
  14. Debug.Log((ClassType)i); // Cast integer to class type.
  15. }
  16. }
  17. }

Best Practices for Using Enums in Unity

Below you can find some best practices for using Enums in Unity. Using these practices, it should be easy to improve your unity code using enums in a variety of ways.

  • Create a unique .cs file for your Enum or place all Enums into a Constants.cs file.
  • Generally, it is a bad idea to define a Enum inside a class when that Enum will be used by other classes. To prevent abuse, consider making the Enum private.
  • When defining Enums, make sure that the naming is consistent everywhere. This again improves the readability of your code.
  • Try to avoid using Enums as a way to identify types (e.g. SmallEnemy, BigEnemy or FinalBoss). There are better ways to handle this than through Enums.
Best practices

Summary

What you learned in this article:

  • Enums offer developers a way to create a list of constants that can be managed more easily than regular constants.
  • Enums are a standard language feature of C# and Unity understands how to work with them.
  • Enums make code more intuitive and easier to read.
  • Enums can be expanded and given default values.
  • Values of an Enum increment automatically in the order that you define them.
  • Enumerations make debugging more intuitive.
  • Generally, we use an enumeration in Unity when dealing with constants or storing state
  • Try to avoid using Enums as a way to identify types.
Summary of how to enhance your code

Conclusion

To conclude, we have learned what enums are and what advantages they have over regular constants. Not only do enums offer more flexibility, but they also improve the readability of our code. Next, we now also know how to improve code in Unity by using enums. During this article we have examined cases where Enums should be used and what their advantages are. Finally, we shortly discussed some best practices when it comes to using Enumerations with Unity.