Alright, so our controller mapping is pretty much done for now, but there's one more thing I wanted to cover and that is the C# concept of Enums. Now we haven't seen many Enums in use throughout the Unity API, and we probably won't be using them that much for the remainder of this course, but Enums are pretty simple to understand, it's a foundational concept of C#, so we might as well get familiar with this concept. Now, there's a particular place that we've seen Enums in our code, and kind of ignored it up to this point, and that is with the Input class methods.
The GetKey() method, for example, has two overloads. For example, if we look at the overloads here, one is for KeyCode, the other one is for a string. What's a KeyCode? We hover over and it says an Enum. Alright, so when we right click this and go to definition, here's an Enum. It's rather large because this handles pretty much any type of typical button input for a keyboard. As you may notice here, an Enum is sort of like a very narrowly-defined type, sort of like a really, really simple class that's comprised of just a sequence of named constants that are separated by commas. What's the use of Enums? Why not just use strings for names, right? Well, Enums are preferable to strings in that they can't be mistyped as strings can.
We just pretty much dealt with that with the InputManager where we had to remember the name of our axis, and not only do we have to remember it, strings can fail silently. They don't give you an error if you type in the wrong string, not always, unless it's coded that way. If you don't have an explicit error for key inputs, for example, then you have to basically guess at whether or not you're using the right name. It could be ambiguously labeled, you could guess the string value of an obvious key, for example, P or Q. You just image they'd be P or Q. What about the Enter key? Is it "Enter" or is it "Return" in quotes, for example. I don't know, and that's why Enums come to the rescue here. Why leave it up to a guessing game, why not just used its named constant, instead, which you can easily look up with IntelliSense? Using IntelliSense as our guide, we just type in KeyCode, and then if we suspect it's Enter, I'm going to hit E. There is no Enter. Hitting R for Return, there it is. Return key.
It's just that much easier using named constants to constrain the list of possibilities for the end user, for the consumer of the code. You may have noticed that there's these integer values beside each KeyCode in the definition. You could reference the numerical value instead of the actual named constant, and this sometimes has its advantages. Under normal conditions, you're going to want to use the named constant. In the definition, if you don't explicitly assign the numerical value, it assumes a numerical value based on the item's order in the Enum, starting from 0. Just to demonstrate now how all this works with Enums, let's just fire up a test script and create our own Enum. Here in the Scripts, Tests. Call this "Enums," and go to our main scene on the Test GameObject, attach that.
We'll say public enum, we'll say PlayerStates, and this enum will be comprised as follows: Idle, Walking, Running, Attacking, Defending, Jumping, and Falling. These are all common states in a typical game, especially a platformer, right? Now here, we can give this class an enum by referencing it like this. We'll create a field to hold those PlayerStates. We'll say Playerstate, because it can only hold one state at a time, which we'll talk about more in a second. And just to flush this out more, I'll say int MoveSpeed. This is not an example we're actually going to use in this project, I'm just showing you how this all works, by way of analogy. In Start() we can say MoveSpeed = 0. And, well, we'll start off our starting state, we'll say, is Idle. We access the named constant by going through the enum and then there's our list of possible named constants, and we'll say Idle.
Then in Update() you can imagine a state-keeping scenario using enums, such as this, if (Playerstate == PlayerStates.Running) we'll say MoveSpeed = 2., Else if (Playerstate == PlayerStates.Walking) MoveSpeed = 1. Else, MoveSpeed = 0. For consistency's sake, I want to rename these. Say PlayerState with a capital S, and let's just rename them all. Alright, and, of course you can, as I said earlier, you can instead of using the named constant, you can just use the numerical values. This would be indexed at 0, see if you hover over it it'll tell you it's numerical value. if (PlayerState == 0) that would refer to Idle as well as a possible enum state. What I wanted you to notice was how you can use Enums for state-holding, in much the same way that we've been using bools for much simpler state-holding. Things that you're either in a true or false state. You can use an Enum, somewhere in the code where you can determine whether or not the state is Walking, Running, Attacking, and so on.
And the rest of your code can sort of look at that as a summary of what state you're in, and not worry about the underlying code that determines that state. With that, you can then determine some other behaviors. Again, it's sort of like the bool that we used for IsPowered, except that it's a lot simpler, the bool is. Whereas a bool can only hold one of two possible states, on or off, an enum can hold any number of possible states that are predefined in the Enum itself. The analogy I always think of is: a bool is like a light switch or a light bulb, it can be either on or off, right? One of two possible states. Whereas an enum is more like one of those multi-speed blenders, where you can be in any state or multiple states, but as soon as you switch to one of those states, it switches off whatever previous state it held. Only one button can be pressed down at a time, and the other buttons pop right back up. One goes to on, the others go to off.
That's kind of how enums work, and wherever you have a state-holding mechanic in your game that resembles that, an enum would be a good choice. Enums are great when you need named constants to prevent mistyped information, as well as holding state, similar to bools, and they're really simple to create and use. Really, there's no reason not to use them whenever these scenarios pop up. Alright, in our project we could have used an enum at some point. A good example probably would have been a custom Input class that sort of acts as an interface between the Unity InputManager and the rest of your code. You could accept the user input, and then convert it to an enum state of sorts, that then the rest of your code references in order to determine its behavior. But our game is pretty simple, and I don't really want to clutter it up and make it any more difficult than it needs to, but at the same time I wanted you to be aware of enums and that the option is available to you. Alright, so that's all I wanted to say about enums. I'll see you in the next lesson.
Lesson 48 - Understanding Enums