To jump on the seasonal bandwagon, I am thankful for an awesome team that can work together to accomplish amazing things. Over the course of the past few months we have gone from a fun conceptual prototype into a nearly feature-complete alpha, and I've retained (most of) my sanity in the process!
Now, down to business. Last time I talked about how UI conventions can be used to your benefit. This time I would like to discuss how NOT to build an editor. These are the hard-learned lessons I have picked up in my brief experience. I would love to hear from any readers (anybody out there?) with other suggestions, since there's an increasing likelihood that tools and infrastructure will end up being my focus.
Games, and editors in particular, require tender loving care. When you set out to write your first few lines of code you will be tempted to just throw things together quickly - after all, Agile is supposed to be all about diving straight into the code, right? WRONG! Agile is about quickly adding on features, iterating on a design, and integrating feedback as quickly as possible. If you screw up the overall structure of your editor in the first sprint it will become increasingly difficult to accomplish what you need to.
For example, take a relatively simple user story: A user selects an object and edits the properties of any attached components. Reading this you decide that in the MouseClick event of your form you will set a SelectedItem property somewhere and update the UI. Fantastic! You now have a functional editor!
You start working on the next item: A user updates an object's position by dragging it. Hmm - okay, so we need to keep track of where the user first clicked, then in the MouseMove event we check for a drag and handle that. Still not too bad, and we're still in Sprint 1!
Work progresses like this for a few weeks - new functionality usually requires a few extra variables and some extra logic. Eventually you end up with the MouseDown, MouseUp, MouseClick and MouseMove events being full of duplicated logic that seems to require an increasing amount of maintenance. Where did we go wrong? Well - to answer that let's look at how we COULD have handled these requirements.
What if we thought of our user interactions as a finite state machine (FSM)? Under this model, we just have to define the state changes. Well-written user stories often lend themselves well to a state machine. Given the above two, for instance, we can say that the default state is IDLE. If the user clicks on an object we know that they want to select it. We also know that, after dragging, an object should be selected. Putting these two together we can say that when the mouse button is pressed and the cursor is over an object, we select that object and change the state to DRAGGING.
One of the big advantages I have found in thinking of a UI as a FSM is that it gives you an automatic framework to consider what states there are, under what conditions one state can change to another, and it basically forces you to explicitly name the states. You also get access to all of the tools built around designing state machines - diagrams, simplification and a common language to speak with any engineers you might work with.
This is by no means a new concept - I'm sure this has been discovered and rediscovered time and again by upstart designers much like myself. Then again, if you come from an object-oriented background or you've never worked directly with state machines it probably wouldn't be your first inclination. Maybe you prefer to have a series of loosely coupled classes using databinding and viewmodels to represent granular data of what is happening in your UI. Even then, I feel it is helpful sometimes to take a step back and realize that what you're really doing is building the same state machine, just at a different level of granularity and abstraction.