User Interaction States
How to effectively manage user interaction in a simple, modularized fashion.
As humans, we like to implement solutions which are familiar to us. We get caught up doing things the way we know how to do them, rather than the “best” way to do them. It’s easy to get caught up in thinking like this and as a result we end up using outdated technologies and implement features in ways that our modern contemporaries don’t understand, or are simply less effective or efficient. My purpose with this and future papers will be to expose readers to a broad spectrum of solutions that will hopefully help them in their own coding. Today I’ll be covering User Interaction States, a great way to modularize and simplify the handling of user input into your application.
User Interaction, or player input, can range in complexity from very simple inputs handling such as seen in FlappyBirds, or as complex as something like Call of Duty. Aside from the very simplest of systems, it is extremely important to have a system setup which can help manage user input so that it doesn’t become a mess of if/and statements with dozens of potential states to check for. So let’s jump right in.
Once Upon A Time...
It was another lazy Sunday afternoon, perfect for a little bit of Netflix and… code. Today I was struggling with my user interaction system which had started out pretty straight forward and simple, and yet had spiraled out of control pretty quickly. What had once looked like this:
As the number of states and possible inputs had increased, the complexity of my once simple user input method had spiraled out of control. And more problematically, I wasn’t quite sure how to go about solving the problem. It was only going to get worse.
I kicked back and threw my legs up on the desk, linking my hands behind my head. I wonder if Frankie, my super smart, genius talking dog, had ever dealt with this issue before. “Hey Frankie, have you…”
“Implemented User Interaction States? Of course I have. What do I look like to you?”
Smart dog. Knew what I was going to ask before I even asked it. Maybe it had some sort of… mind reading powers. Another question for another day. As I picked myself up off the floor (where I had fallen from the shock of being interrupted) I queried, “So I need a way to separate user interaction in a set of meaningful but separate states to limit the player to a more specific set of inputs at any given time, while also allowing easier debugging. Are you saying that this… User Interaction Manager you mention would solve the issue?”
“Yep, you have to setup a user interaction class which can be loaded into a user interaction manager. The user interaction class will handle all the input relevant for a particular state, and anytime the state changes you will load a new user interaction class into the manager. That way all of your input management for a particular state is in one place, and you can more easily manage the transitions between them.”
Well, I’ll be damned. That sounds pretty… good. It also sounds pretty easy. Every time a new UserInteractionState is loaded, the UserInteractionManager tears down any existing UserInteractionState and then setups the new one. The UserInteractionManager will also need a Destroy method so that it can call a final TearDown on any existing UserInteractionStates when it is destroyed.
Now that we’ve gone over the theory, it is useful to step through a practical implementation. First let’s setup the interfaces involved. Let’s start with the IUserInteractionManager.
First up is the IUserInteractionManager.
And a basic implementation of a basic manager.
Next up is the interface for the IUserInteractionState
It is important that the user interaction state has Setup and TearDown methods so that it can instantiate any code necessary to run that particular state, but that may not be relevant to other states, and then get rid of it when the state is disposed of. It also needs an Update method so it can run the frame by frame code responsible for checking and reacting to the player input. Now let’s try a basic implementation.
In this implementation, we check for input which is used to control the player. During the setup method we subscribe to the game menu’s button, and during the teardown we unsubscribe. If the Game menu button is clicked on, we call on the UserInteractionManager to load a new state, and specify which state that is.
Ways To Extend This Concept
You might find that a lot of UserInteractionState’s rely on similar input checks. For example, multiple states might allow the user to control the players movement. One way to handle this is make these methods extension methods.
Now you can just call this method from inside the user interaction states Update() method instead of defining one individually inside that state.
Ever since I started using User Interaction States to organize my input code, life has been sweet and easy. But just because everything is moving smooth doesn’t mean my learning had really sunk in – so a few weeks later Frankie asked me to summarize what I had learned.
- That by segregating my code into separate class implementations of a standard interface, I could keep my input code from having to handle multiple states at once.
- Having teardown and setup states means that I can activate code or listen for events (such as button presses) only when they are relevant; thus preventing strange behavior when the player manages to interact in ways we don’t expect them to as developers.
As with anything in coding, there is often no best solution. It is important to keep a large variety of coding tools in our toolbox so that we can pick the right one for the problem at hand. User Interaction States turned out to be perfect for King Randall’s Party. Perhaps they will be the right solution for your project?
Share this Post