Is there a nice way to make a type that associates things with enum values?

I commonly want to associated something with each value of an enum. Consider, for example, setting the player’s speed based on their stance.

I could do this:

float standSpeed;
float crouchSpeed;
float crawlSpeed;

I do not enjoy this:

  • I have several fields that are clearly related, but the inspector just shows a sequence of floats. I’d like them to be grouped.
  • If I add a new enum value, I have to add a whole new field
  • Getting the relevant value is a bit annoying. The best I can do is this:
public float Speed
{
get => stance switch {
  Stance.Stand => standSpeed,
  Stance.Crouch => crouchSpeed,
  Stance.Crawl => crawlSpeed
};
}

What I’d love to be able to do is this:

Record<Stance, float> playerSpeed;

[...]

float mySpeed = playerSpeed[stance];

So, basically, a dictionary that’s guaranteed to have all of the values of an enum as keys, that shows up in the inspector.

A dictionary isn’t really optimal here. Unity won’t let me inspect it, and it’s not guaranteed to have every enum value as keys.

I could make a struct for this specific purpose, but now I’m doing things manually again! (maybe this is a place for codegen, or something?)

I guess I could cobble something together myself – but has anyone done this before or used a third-party asset to do it?

Sounds perfect for a ScriptableObject, which can actually function as a de-facto enum as well.

Let’s say you have three stances: crawl, crouch and stand and you want to encode a speed for each.

using UnityEngine;

[CreateAssetMenu]
public class Stance : ScriptableObject
{
    public float Speed = 1.0f;
}

Now make three of them (right-click-create) and fill in the values!

8728803--1180962--Screen Shot 2023-01-13 at 11.26.55 AM.png

I lazily left the script in there, you’d probably put it somewhere else.

Then in your MonoBehaviour you’d have a list of available stances:

public Stance[] AvailableStances;  /// drag them in here!

Here’s the general blurb:

Enums enums are bad in Unity3D if you intend them to be serialized:

https://discussions.unity.com/t/809088/4

https://discussions.unity.com/t/817068/2

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>().

1 Like

Ah, that’s a decent idea, especially if I wind up stapling more data onto stances later (like the collider parameters).

I hadn’t considered the agony I’d experience if I reordered the enums (or done anything else to mess with their values). I usually don’t serialize them…but this sounds like a scenario where I’d be doing exactly that :stuck_out_tongue:

Thanks!

1 Like

You’re welcome. ScriptableObjects are an amazing way to encode complex semantically meaningful typesafe information into your game. It can eliminate all manner of silly code changes to add “one more stance,” for instance.

In my games I use them EVERYWHERE. I can’t live without them.

For instance, here’s a random collection of snaps from various game configuration things for Jetpack Kurt and Pilot Kurt:

8728821--1180965--Screen Shot 2023-01-13 at 11.37.34 AM.png 8728821--1180968--Screen Shot 2023-01-13 at 11.37.06 AM.png 8728821--1180971--Screen Shot 2023-01-13 at 11.36.58 AM.png 8728821--1180974--Screen Shot 2023-01-13 at 11.36.25 AM.png

Frequently I will put static factory methods to load and / or manage collections of these things, putting those managers right into the ScriptableObject class itself.

1 Like