Search Unity

Reasons to manually assign values to enums

Discussion in 'Scripting' started by ArachnidAnimal, Nov 10, 2017.

  1. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,835
    In Unity when your script defines an enum and an enum needs to be serialized, it based on the underlying value of the enum. This can pose problems if someone then needs to re-order items in the enum or add/remove items. I ran into this issue.

    Code (csharp):
    1.  
    2. public enum WeaponTypes
    3. {
    4.   HANDS,
    5.   PISTOL,
    6.   LAUNCHER
    7. }
    8. public WeaponTypes weaponType; //Serialized in inspector
    9.  
    So in the inspector, the weaponType was serialized to be "WeaponTypes.LAUNCHER". So the underlying value is "2".
    Then I go into the code and add an element in-between PISTOL and LAUNCHER.
    Now the enum is:
    Code (csharp):
    1.  
    2. public enum WeaponTypes
    3. {
    4.   HANDS,
    5.   PISTOL,
    6.   RIFLE,
    7.   LAUNCHER
    8. }
    9.  
    Then unbeknownst to me at the time, all existing items using this serialization then became "WeaponsTypes.RIFLE". This is because now RIFLE has the underlying value of 2. I had to go and change all the items in the resources folder that had serialized values of this enum.

    So I think this could be a good case of manually assigning enum values from the git-go, to allow for items to be added and moved in enum:
    Code (csharp):
    1.  
    2. public enum WeaponTypes
    3. {
    4.   HANDS = 100,
    5.   PISTOL = 200,
    6.   RIFLE = 250,
    7.   LAUNCHER = 300
    8. }
    9.  
    Had I done this, there would have been no problem because the values are persistent.
    I always read about how assigning the values is usually avoided. So is this a case where manually assigning values to enums is a preferred method?
    Does anyone else do this so to avoid issues like this in Unity?
     
  2. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    We actually have a clause in our coding guidelines that says: enumerations which are serialized must assign values explicitly.
     
    KelsoMRK likes this.
  3. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    You can also set enums to powers of two and use a bit mask to combine different constants. For example:
    Code (csharp):
    1.  
    2.         enum StatusEffect { Poisoned = 1, Frozen = 2, OnFire = 4};
    3.         int havingABadDay = (int)StatusEffect.Poisoned | (int)StatusEffect.OnFire; // bitwise "or"
    4.         if ( (havingABadDay & (int)StatusEffect.OnFire) != 0) Debug.Log("You're on fire");
    5.  
    It's a pretty good way to squeeze a bunch of boolean flags into one int, if you need to save memory.
    (There's probably a cleaner way to write the above example)
     
    ArachnidAnimal likes this.
  4. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    In this case, you probably want to decorate the enum with the System.FlagsAttribute too.
     
    ArachnidAnimal likes this.
  5. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,835
    Yeah, I've used this once before. I like to use the logical shift operator, so I don't have to waste brain energy remembering what 2 ^ 13 power is. :)
    Code (csharp):
    1.  
    2.    enum StatusEffect { Poisoned = 1 << 0, Frozen = 1 << 1, OnFire = 1 << 2};
    3.  
     
    StarManta likes this.
  6. triangle4studios

    triangle4studios

    Joined:
    Jun 28, 2020
    Posts:
    33
    Until today, I did not know that you could assign a value to an enum. And I have been using them for 3 years. I started opting to use strings instead as I needed reliability. Today, while self educating on bitwise operators, I learned about this epic upgrade to my knowledge accidentally!

    I think it is import to clarify that the implicit assignment of an integer value is by design and not the fault of Unity. It has its benefits (providing automatic order) and combined with the ability to provide an explicit value to all or any of the values there are limitless possibilities with them!

    I admit it has driven me nuts, so much so that I never use enums. But all that is about to change!
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Enums, even manually-assigned values, are still not super useful in Unity vis-a-vis serialization, which still emits them as inscrutable numbers in your YAML scene / prefab files.

    https://forum.unity.com/threads/bes...if-not-do-something-else.972093/#post-6323361

    https://forum.unity.com/threads/unity-card-game-structure.1006826/#post-6529526

    It is much better to use ScriptableObjects for many enumerative uses. You can even define additional associated data with each one of them, and drag them into other parts of your game (scenes, prefabs, other ScriptableObjects) however you like. References remain rock solid even if you rename them, reorder them, reorganize them, etc. They are always connected via the meta file GUID.

    Collections / groups of ScriptableObjects can also be loaded en-masse with calls such as
    Resources.LoadAll<T>().
     
    Nad_B likes this.