0
\$\begingroup\$

Both my Player class and Enemy class should have an enum called State. (The values inside of that enum would be different in each class.) I'd like to have the Player class and Enemy class inherit from an abstract base class that would require those two classes to have that enum. Is this possible?

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

No, this is not possible.

If your two enums define different sets of values, then they must be two different types, and C# does not have a concept of inheritance for enums, so they can't descend from a common parent type that could be described in the abstract class.

The closest you can do is something like...

public abstract class StatefulBehaviour : MonoBehaviour {

    // Hold a backing integer as a go-between for all different state types.
    private int _state;

    // Caller tells you what type of state they're expecting - convert to that.
    public T GetState<T>() where T: struct, System.IConvertible {
        System.Object state = _state; // Boxing! Ewwwwww....
        return (T)state;
    }

    // Caller gives you a state of a particular type - convert it to lingua franca.
    public void SetState<T>(T state) where T:struct, System.IConvertible {
        _state = System.Convert.ToInt32(state);
    }
}

Then your player could look something like this:

public class PlayerMovement : StatefulBehaviour {

    public enum PlayerState : int {
        Idle,
        Walking,
        Running,
        Climbing,
        Jumping,
        Falling,
        Dead
    }

    public void Jump() {
        SetState(PlayerState.Jumping);
    }

    public bool IsDead {
        get {
            return GetState<PlayerState>() == PlayerState.Dead;
        }
    }

    // Etc.
}

This means it's on you to police that you're using the right state type consistently for each object - since unrelated states from different objects might map to the same integer. (You could add some debugging support here - in development builds, have StatefulBehaviour cache the last type it was set with, and complain if someone tries to set or get a state of a different type)


Myself, I'd be tempted instead to take a composition over inheritance approach if you want shared state management logic between multiple different component types. That way you don't have a bottleneck where every bit of logic with states needs to inherit from a single base class.

  • Introduce a State component type.

  • Anything that needs states can [RequireComponent(typeof(State))] to ensure it has a state component attached.

  • The State component references a (shared) collection of states - possibly using a type object pattern so you can define your states in data rather than enum code files

  • The State component holds a current value, maintaining the invariant that it's always a member of the referenced collection.

  • You can add a State component to any object via the Inspector, and configure which collection of state values it should draw from. (This makes it easy to, say, re-use a common set of states between all switch & trigger objects, even if they have different activation logic)

Or you could go even further, where each of your individual states is its own object, with references to the states it can transition to. Then you have a state machine graph not unlike the one used by Unity's Mechanim animation controllers. Now the idea of a "collection" of states is implicit in the connectivity of the graph, and the only difference between a PlayerState and an EnemyState is that they're not reachable from one another.

\$\endgroup\$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .