It’s hard to find a developer who has never heard about enum. But do you use it correctly? Let’s find out.
The naming is one of the important things in development. Jokes aside. The best name for enum should reflect what it consists of. The good names are short and self-explanatory:
WindowName
, EntityType
, etc. It’s that simple. There is no reason to add ‘s’, or ‘enum’ or call it ListOfEntitiesType. Brevity is the soul of wit. And don’t forget to use a namespace, so your enum will be separated by them.By default, it's int, and I recommend sticking with it. But sometimes, there is a requirement to do something different, and for the value of enum members, you can use any integral numeric type you like: bytes, int’s, long’s, and even shorts.
Many developers use invalid indexes as default. For example,
-1
or int.MinValue
, or -99999
. These things are annoying. Let’s look at the example: you have an enum DamageType
and class Damage
, which you send somewhere to draw some damage.enum DamageType
{
None = -1,
Range = 0,
Magic = 1,
Close = 2,
}
class Damage
{
public DamageType Type { get; private set; }
public int Amount { get; private set; }
…..
}
If you create this class with an empty constructor, you will get these default values: Type is
DamageType.Range
, and Amount is 0
. This is not logical since the default of DamageType
will be None unless your goal is different. How to iterate through all elements of enum? Easy:
var allElementsOfEnum = Enum.GetValues(typeof(MyEnum));
From that point, we can easily get random elements of enum. Or create one entity of each type.
And this one is a bit complicated but interesting at the same time. Imagine that you are working over a real-world animal simulator. You have an urchin that lives on ground and can barely swim; you have a bass-fish that lives in water and barely can live on the surface:
public enum AnimalHabitat
{
None = 0,
Ground = 1,
Water = 2,
}
Then comes a game designer, and he asks you to add a turtle that lives both on the ground and underwater. We could add another element to the enum Amphibian that equals
3
. And then, we will need to check animal habitat like this:if (animal.habitat == AnimalHabitat.Ground || animal.habitat == AnimalHabitat.Amphibian)
{
//do the ground stuff
}
...
if (animal.habitat == AnimalHabitat.Water || animal.habitat == AnimalHabitat.Amphibian)
{
//do the water stuff
}
And then, each time we will add intercrossing behaviors, we will need to modify our code again. And the problem is that it interferes with the SOLID principle. With the S point to be exact, that says that there should be only one reason to change the class. And I don’t see any reason to change the behavior of the ground or water habitat here. We need to check if Amphibian has properties of ground behavior or water behavior.
So let’s try another way!
[Flags]
public enum AnimalHabitat
{
None = 0b_0000_0000,
Ground = 0b_0000_0001,
Water = 0b_0000_0010,
Amphibian = Ground | Water, //that will be 0b_0000_0011
}
And then you will need to recall some magic - the magic of bitwise operations.
var habitat = AnimalHabitat.Amphibian;
If (habitat & AnimalHabitat.Ground == AnimalHabitat.Ground)
{
//do the ground stuff
}
...
If (habitat & AnimalHabitat.Water == AnimalHabitat.Water)
{
//do the water stuff
}
Keep in mind that in this situation, you can have 8 flags (including zero, which will stand for None as we made a deal previously). And it will give you 256 combinations.
As we can see, the enum can be a powerful data structure that can help build up the logic of a game you are working on. And proper usage of enum benefits the process of development and will help support games in the future.
Also published on: https://gamasutra.com/blogs/TymurKoshel/20210618/383786/Enums_in_C_and_how_to_cook_them.php.