I am running into a design issue when it comes to deciding which type to use when wanting to represent something.
Lets take Inputs as an example.
You make a Input manager that lets you type in a name for your input and what button that name corresponds to.
You are now able to select which key you want to check is being pressed by doing a InputDown(“String Name”) check.
I really dont like using strings as a means to choosing something. Strings can be very flexible, but easy to misuse (typos and what not). So then we get into maybe having a InputName class with static input names representing the input names we typed in the Input Manager. Now we dont have to worry about typos as long as we always use those static fields, but what if we want to change the name of the input? Now we need to remember to go in and change those static fields.
If we go with enums, then we get the neat things that come with enums such as help from intellisense. The bad thing is that the user would need to edit the enum file directly, unless if maybe we get into auto generating code?
More examples
Lets take another example, an Audio Manager. We need to be able to define different audio channels so we can handle their volumes separately. We pretty much have the same issue as our inputs, except there is a higher change that I will not need to reference it in code that much, but more so in the editor on the components via a dropdown or what ever.
Another example, a State Machine data passer thing. This might be poor design, but I have a component that I can call GetState(); It will return to me a State object that has information about what ever state assigned there that was of type T. So the internal dictionary is a Dictionary<Type, State>. The Type doesnt need to have anything to do with the actual state, its just what the state decided to use to define itself in the dictionary so that other objects can select it and get its data (The data of that state is stored in a plain object variable, so to get the actual data there would be a cast done). The reason for not using a enum with all the states is because the state can come from anywhere. For example, my Grounded state might come from my custom Rigidbody component, while my Walking state comes from something completely different, like a totally different asset that might have its own enums representing its states. However, what about strings? Would that have been a better choice?
Heres the code to give a better idea
Click for code
public class StateWatcher : MonoBehaviour
{
Dictionary<Type, State> states = new Dictionary<Type, State>();
public State GetState<T>()
{
if(states.ContainsKey(typeof(T))) return states[typeof(T)];
Debug.LogWarning("StateWatcher couldnt find state of type " + typeof(T).ToString() + ". Returning Null");
return null;
}
public bool AddState<T>(string stateName, object stateObject)
{
if(states.ContainsKey(typeof(T))) return false;
State state = new State(stateName, stateObject);
states.Add(typeof(T), state);
return true;
}
[Serializable]
public class State
{
public string name;
public delegate void StateEvent();
public event StateEvent OnStartState;
public event StateEvent OnEndState;
object stateObject;
public State(string stateName, object stateObject)
{
name = stateName;
this.stateObject = stateObject;
}
public void StateStarted()
{
OnStartState();
}
public void StateEnded()
{
OnEndState();
}
public void Subscribe(StateEvent onStart, StateEvent onEnd)
{
OnStartState += onStart;
OnEndState += onEnd;
}
public void Unsubscribe(StateEvent onStart, StateEvent onEnd)
{
OnStartState -= onStart;
OnEndState -= onEnd;
}
public void SetStateObject<T>(T stateObject)
{
this.stateObject = stateObject;
}
public T GetStateObject<T>()
{
if(stateObject != null)
{
if(stateObject.GetType() != typeof(T))
{
Debug.LogWarning("StateWatcher State GetStateObject type does not match. Actual state type is " + stateObject.GetType() + " where the GetStateObject type was " + typeof(T));
}
return (T)stateObject;
}
return default(T);
}
}
}
In terms of managing these things, how do you do it? If I have a public enum so that I can select it in the editor, what happens if I decide I want to remove an enum value? I had enum AudioLayer {Main = 0, PlayerSfx = 1, EnemySfx = 2} and now I decided I didnt want a PlayerSfx and MonsterSfx, but instead wanted to combine them into just Sfx. How do I change all my editor properties? All my code will throw compile errors when I remove the enums, so I can change them fine there, but my editor stuff will be hidden away until its found in runtime or something. This goes for strings too. If I have a custom editor to be able to have get all the AudioLayer Strings as a Dropdown, how do you change them all?
I would like to know how others handle this =).