Lesson 48 - Understanding Enums

Tutorial Series: Introduction to Unity with C# Series

Previous Article  |  Next Article


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.

Related Articles in this Tutorial:

Lesson 1 - Who This Course is For

Lesson 2 - What to Expect from this Course

Lesson 3 - Installation and Getting Started

Lesson 4 - Starting the First Project

Lesson 5 - Prototype Workflow

Lesson 6 - Basic Code Review

Lesson 7 - Game Loop Primer

Lesson 8 - Prototyping Continued

Lesson 9 - C# Fundamentals and Hello World

Lesson 10 - Variables and Operations

Lesson 11 - Variables and Operations Continued

Lesson 12 - Floats, Bools and Casting

Lesson 13 - If Statement Conditionals

Lesson 14 - If Statements Continued

Lesson 15 - Complex Evaluations and States

Lesson 16 - Code Syntax vs. Style

Lesson 17 - Variable Scope

Lesson 18 - Object-Oriented Programming Intro

Lesson 19 - OOP, Access Modifiers, Instantiation

Lesson 20 - Object Containment and Method Returns

Lesson 21 - "Has-A" Object Containment

Lesson 22 - "Is-A" Inheritance Containment

Lesson 23 - Static Fields and Methods

Lesson 24 - Method Inputs and Returns

Lesson 25 - Reference vs. Value Types

Lesson 26 - Introduction to Polymorphism

Lesson 27 - Navigating the Unity API

Lesson 28 - Applying What You've Learned and Refactoring

Lesson 29 - Constructors, Local Variables in the Update Method

Lesson 30 - Collecting Collectibles, Items and Powerups

Lesson 31 - Spawning and Managing Prefab Powerups

Lesson 32 - Implementing Powerup State Logic

Lesson 33 - Displaying Text, OnGUI, Method Overloading

Lesson 34 - Referencing Instantiated GameObjects, Parenting

Lesson 35 - Understanding the Lerp Method

Lesson 36 - Creating Pseudo Animations in Code

Lesson 37 - Understanding Generic Classes and Methods

Lesson 38 - Animations Using SpriteSheets and Animator

Lesson 39 - Working with Arrays and Loops

Lesson 40 - Debugging Unity Projects with Visual Studio

Lesson 41 - Camera Movement and LateUpdate

Lesson 42 - Playing Audio Clips

Lesson 43 - Routing Audio, Mixers and Effects

Lesson 44 - Adding Scoring Mechanics and Enhancements

Lesson 45 - Scene Loading and Game Over Manager

Lesson 46 - Understanding Properties

Lesson 47 - Controller Mapping and Input Manager

Lesson 48 - Understanding Enums

Lesson 49 - Dealing with Null References

Lesson 50 - Handling Variable Framerates with time.DeltaTime

Lesson 51 - Preparing the Project for Final Build

Lesson 52 - Final Build and Project Settings

Lesson 53 - Introduction to the Unity Physics Engine

Lesson 54 - Understanding FixedUpdate vs. Update

Lesson 55 - Movement Using Physics

Lesson 56 - Attack Script and Collision Events with OnCollisionEnter2D

Lesson 57 - Projectiles and Stomping Attack

Lesson 58 - Parallax Background and Scrolling Camera

Lesson 59 - Infinitely Tiling Background Sprites

Lesson 60 - OOP Enemy Classes

Lesson 61 - OOP Enemy Classes Continued

Lesson 62 - Trigger Colliders and Causing Damage

Lesson 63 - Multi-Dimensional Arrays and Procedural Platforms

Lesson 64 - Finishing Touches

Lesson 65 - Series Wrap


Please login or register to add a comment