Правильное название
Название — один из важных моментов в разработке. Шутки в сторону. Лучшее имя для перечисления должно отражать, из чего оно состоит. Хорошие имена короткие и говорят сами за себя: WindowName, EntityType и т. д. Это так просто. Нет причин добавлять «s» или «enum» или называть его ListOfEntitiesType. Краткость — душа остроумия. И не забудьте использовать пространство имен, чтобы ваши перечисления были аккуратно разделены ими.

Какими могут быть значения членов перечисления?
По умолчанию это int, и я рекомендую придерживаться его. Но иногда требуется сделать что-то другое, и для значения членов перечисления вы можете использовать любой целочисленный числовой тип, который вам нравится: байты, целые, длинные и даже короткие.

Правильная индексация
Многие разработчики используют недопустимые индексы по умолчанию. Например -1 или int.MinValue, или -99999. Эти вещи раздражают. Давайте посмотрим на пример: представьте, что у вас есть перечисление DamageType и класс 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; }
    …..
}

Если вы создадите этот класс с пустым конструктором, вы получите следующие значения по умолчанию: Type — DamageType.Range, а Amount — 0. Что нелогично, поскольку по умолчанию для DamageType будет None. Если ваша цель не другая.

Полезные фрагменты
Как перебрать все элементы перечисления? Легкий:

var allElementsOfEnum = Enum.GetValues(typeof(MyEnum));

С этого момента мы можем легко получить случайные элементы перечисления. Или создайте по одной сущности каждого типа.

И это немного сложно, но в то же время интересно. Представьте, что вы работаете над реальным симулятором животных. У вас есть еж, который живет на земле и едва умеет плавать, у вас есть окунь, который живет в воде и едва может жить на поверхности:

public enum AnimalHabitat { 
    None = 0, 
    Ground = 1, 
    Water = 2, 
}

…и тут приходит геймдизайнер и просит добавить черепаху, которая живет и на земле, и под водой. Мы могли бы добавить в перечисление Amphibian еще один элемент, равный 3. И тогда нам нужно будет проверить среду обитания животных следующим образом:

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 
}

И затем каждый раз, когда мы будем добавлять пересекающееся поведение, нам нужно будет снова модифицировать наш код. И проблема в том, что это мешает принципу SOLID. Если быть точным, кнопка S означает, что должна быть только одна причина для изменения класса. И я не вижу смысла менять здесь поведение наземной или водной среды обитания. Нам просто нужно проверить, есть ли у Амфибии свойства поведения на земле или в воде.
Итак, давайте попробуем другой способ!

[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 
}

И тогда вам нужно будет вспомнить немного магии. Магия побитовых операций.

var habitat = AnimalHabitat.Amphibian; 
if (habitat & AnimalHabitat.Ground == AnimalHabitat.Ground) 
{ 
    //do the ground stuff 
} 
... 
if (habitat & AnimalHabitat.Water == AnimalHabitat.Water) 
{ 
    //do the water stuff 
}

Имейте в виду, что в этой ситуации у вас может быть 8 флагов (включая ноль, который будет означать «Нет», поскольку мы заключили сделку ранее). И это даст вам 256 комбинаций.

Заключение
Как мы видим, Enums может быть мощной структурой данных, которая может помочь построить логику игры, над которой вы работаете. И правильное использование перечислений не только принесет пользу в процессе разработки, но и поможет поддерживать игру в будущем.