This article originally appeared in Game Developer Magazine, May 2005.

"Button Disambiguation: How to make your game feel more responsive and intuitive by measuring and intelligently resolving ambiguous player control"

Introduction

Download the sample application:
PushingButtons.zip
158K

Have you ever been playing a game, and you pressed a button to make your character do something, and the character either did something else, or simply did nothing at all?

More to the point, if you are responsible for the design or implementation of the player control in a game, have you ever had someone come to you and tell you "it's broken", or worse: "it doesn't feel right" - yet when you try it yourself, it seems fine to you. Is it in their imagination?

A core aspect of programming a game is converting the player's input from the gamepad buttons into the character's actions. On the face of it this appears a simple problem: you just map buttons to events. However due to the non-precise way that different players press buttons and perceive events, problems of ambiguity arise which lead to frustration and a feeling of unresponsiveness. The player thinks he has hit the correct button at the correct time, but, as he's not a robot, the intent of his input is ambiguous and cannot be resolved satisfactorily with a simple mapping.

This article discusses the physical and perceptual reasons for this ambiguity, discusses how different people produce different input, describes methods for analyzing what is actually occurring, and presents a strategy for resolving input ambiguity that allows your game to feel responsive and intuitive.

A fairly standard button layout
Figure 1 - The layout of the Xbox controller. This square arrangement of buttons is the most common layout on current consoles.
 

On a typical gamepad such as the standard pads used with the Sony Playstation and the Microsoft Xbox, there are four buttons that are all operated by the player's right thumb. In this article I'm going to concentrate mainly on the use of these four buttons.

One of these buttons is the "primary" button, which is used to trigger the primary action in the game. In platform games such as Mario, this is "Jump". This button is "X" on Sony Dualshock, where it is the bottom button of the group of four. The primary button is A on Xbox, in a similar configuration to the Sony Dualshock.

For the purposes of the article I'm going to be referring to the buttons as laid out on the X-Box. Mostly because I can refer to each button by a letter (A,B,X or Y) and the diamond shaped layout is the most common. (see Figure 1)

Mapping player input to game events

The mapping of player input to events can be done in a number of ways, but basically it boils down to a set of rules. Each game event (such as jumping) must satisfy a number of conditions before it can be triggered. This can be expressed in pseudocode as:

If (conditions met) then (trigger event)

I'm going to use two examples here, both based on a simple "Mario" style platform game.

Example #1: Jumping

Let's say our primary button (A) is the jump button. The rule could be:

If Button A pressed then JUMP

But you don't want to jump while you are in the air, so a more reasonable rule would be:

If Button A pressed and ON GROUND then JUMP

Example #2 - Super Jump and Ground Pound

This actually two moves performed with the same buttons. In our game pressing the right shoulder button (R1) causes the character to crouch. Pressing A while crouched will cause the character to do a super high jump.

If you press R1 while in the air, the character will do a "ground pound" where they rapidly slam down into the ground. Both these moves are similar to moves in Super Mario 64.

This can be expressed as three rules:

If button R1 pressed and ON GROUND then CROUCH
If button R1 pressed and IN AIR then GROUND POUND
If button A pressed and CROUCHED then SUPER JUMP

This seems nice and straightforward. However there are numerous problems with this simple implementation. As we will see later, getting player control to work is inevitably a fiddly and complex task. In order to provide a feeling of simple intuitive control to the player you will actually have to write some rather convoluted ad hoc code.

Detecting and Recording player input

The simplest way of handling input from a joystick is to query its current state. i.e. "is button X pressed right now".

This works fine for things such as acceleration and braking, which are continuous events. But for one-time events, such as jumping and shooting, you actually want to detect when the player initially presses the button. You need to respond when a button goes from "released" to "pressed" - i.e., when the button is "triggered".

In addition, you often want to know how long a button has been pressed, and sometimes how long since a "trigger" event has occurred. You might also want to be able to flag the "trigger" event as having been handled, so it does not get continually re-used.

So, for the purposes of this article, I'm going to assume a fairly simple implementation of a joypad button interface that provides the information listed above. This is also what I've implemented in the sample code.

Thumb positioning - Precise Thumb vs. Sloppy Thumb

On the vast majority of games, the player rarely moves his thumb from the vicinity of these four buttons, so even when not pressing a button, they will rest their thumb over the buttons, ready to press them as needed.

There are two basic ways in which a person can hold their thumb over the buttons. I call these Precise Thumb and Sloppy Thumb. As we shall see, it is important to consider both types of thumb positioning when designing and implementing your control scheme.

Precise thumb
Figure 2a – The "precise" player rest the tip of their thumb over the primary button.
 

Precise Thumb is where the player uses the tip of his thumb to press each of the four buttons. When moving from one button to another, the precise thumb player will lift his thumb off the button, and press it down on another button. (Figure 2a)

Sloppy thumb
Figure 2b – the "sloppy" player rests his thumb over all the buttons - allowing a button press by just tilting the thumb..
 

Sloppy Thumb is where the player uses the whole thumb to operate the four buttons. There are many variants, but basically the sloppy player uses the thumb tip only to operate the uppermost button. The buttons to the sides are operated by the sides of the thumb, and the lower button is operated by either the middle of the thumb pad, or the bone at the first joint in the thumb. (Figure 2b)

In order to press a different button, the sloppy player will usually just tilt his thumb.

The Nintendo Gamecube controller is built around the expectation that the player will use some kind of "sloppy thumb" technique. There is a large central primary button, and with the three other buttons surrounding it, encouraging you to keep your thumb squarely over the primary button, and hit the other buttons with the edges and the tip of your thumb.

This radical difference in thumb position (and button layout) can lead to perceived control problems that only arise on one platform and with just one tester. But remember one tester out of your pool of testers could equate to many thousands of player having the same problem if you are making a reasonably popular game. If you have very few testers, then if someone comes to you and says "it feels wrong when I do this", then pay close attention, because they represent a goodly chunk of your potential audience.

The Causes of Ambiguity

Ambiguity cause #1 - Imperceptible State Changes.

The player runs his character towards the chasm. When he gets to the edge, he presses the jump button. The character does not jump, and instead plunges to his doom.

Why did the character not jump? Because in the internal model of reality that the game stores, the character had already run off the edge of the cliff when they pressed the jump button. However, to the player it looked like he was right at the edge and a jump looked perfectly possible. There was a discrepancy between the perceptions of the time at which the player left the ground.

On one frame (on the ground) pressing button A will make the character jump. On the next frame (in the air) pressing A will have no effect. To the player these two frames of the game (just 0.016 seconds apart) appear identical.

This problem also occurs when jumping just before landing, or just before hitting a wall (for a wall jump)

Ambiguity Cause #2 – Change in button function based on state.

In Nintendo's Super Mario 64 DS, when playing as Mario, pressing A to jump then R1 (R1 = Right shoulder button, use the Z button on the Nintendo 64 version), will trigger a ground pound. Pressing R1 then A will trigger a backflip. Pressing them both at the same time will cause one of: a ground pound, a backflip, or a normal jump, seemingly at random. This is bad because the user has no control; they are doing the same thing over and over, yet getting different results.

This problem also shows up in Mario when you try to do a long jump, which is done by running, then jumping by pressing A+R1. Sometimes while attempting this you will do a Ground Pound by accident. This is not the fault of the player. To the player it appeared they did everything right, but the results were not what they expected.

Now at this point you might think "hey, I'm pretty good at Mario, I don't notice those problems, I can long jump no problem". Sure, but to get good at it you had to train yourself to work around these control issues. You had to learn that to do a consistent long jump you had to tap R1 and between 0.05 and 0.18 seconds later tap A. This you learn by failing repeatedly when you first play the game until you get it right.

To the beginning player this is not fun. Controls that do not do what you want are frustrating. Just as bad are inconsistent controls, where sometimes the character does one thing, and sometime another, without any logic perceptible to the player. They might not be able to voice it exactly, but the game "just feels wrong". Ignore this at your peril.

Ambiguity Cause #3 – Accidental button presses with Sloppy Thumb

A fairly standard button layout
A fairly standard button layout
Figure 3 – The "precise" player moves his thumb from A to Y by lifting his thumb off A and putting it on Y. This is a nice clean motion, and it’s easy to assume your player will do this.
 

When moving his thumb from one button to another when using the Sloppy Thumb technique, it's quite likely that you may hit some other button by mistake. Particularly when going between opposite buttons

For example, when going from A to Y the "precise thumb" player will lift their thumb off A and then press Y (Figure 3) in a nice clean motion. The sloppy player will tilt their thumb forward, rocking it from A to Y and quite possibly momentarily pressing X or B. (Figure 4)

A fairly standard button layout
A fairly standard button layout
A fairly standard button layout
Figure 4 – The "sloppy" player moving from A to Y. The player is simply tilting his thumb forward, and in the second image accidentally presses X with the side of his thumb. At that point all three buttons are depressed. Your game will feel better if you can handle this case.
 

Ambiguity Cause #4 – Release and Press vs. Press and Release

It's common in games for an action to involve releasing one button, and then pressing another in rapid succession.

This can happen in two ways. Say when moving from A to X. The precise thumb player Releases X, then Presses A (figure 5) whereas the sloppy player will Press A, then release X, so for a brief period of time, A and X are both pressed.(figure 6)

A fairly standard button layout
A fairly standard button layout
A fairly standard button layout
Figure 5 – Precise movement from A to X.

 
A fairly standard button layout
A fairly standard button layout
A fairly standard button layout
Figure 6 – Sloppy movement from A to X. Note how at one point both A and X are pressed together.
 

This can lead to problems if you have an event triggered by A+X being held. Or if your event tied to X relies on no other buttons being pressed.

Measuring Ambiguity

In dealing with all these problems, the most important tool is one that gives you the ability to see exactly what is happening, and more importantly "what just happened". People are going to show you control problems, and you are going to have to figure out the precise sequence of events that caused that problem to occur.

The first thing to implement is a simple log file. Every time an event of interest occurs, you just print out that event, along with the time and any other useful information. Then when the control problem crops up, you just look at the log file and see what caused the problem.

In the example game I'm using the "OutputDebugString" Win32 function, since there are numerous programs designed to capture and filter these debug strings. I use a free one called "DebugView" by Sysinternals (www.sysinternals.com)

Example: consider the situation in Figure 4, the corresponding output log looks like this:

14.218: + Pressed A
14.218: Event Jump
14.418: + Pressed X
14.418: + Pressed Y
14.484: – Released X
14.484: – Released A

The number on the left is the time in seconds. The player presses A (fig 4a) to jump (which happens in the same frame). Then the player rolls his thumb forward (figure 4b) pressing Y and X simultaneously. As the thumb rolls forward fully onto Y, they release X and A simultaneously.

Now consider the case for one the ambiguity problems we listed above, the "Super Jump" vs. "Ground Pound". Remember the problem was that pressing A and R1 at the same time resulted in inconsistent results. Sometimes a Super Jump, and Sometimes a Ground pound.

Here's the output for a ground pound:

21.199: + Pressed A
21.199: Event Jump
21.215: + Pressed R1
21.215: Event Gnd_Pnd
21.232: Event Land
21.249: Event Crouch
21.432: – Released R1
21.432: Event UnCrouch
21.465: – Released A

Here's the output for a super jump

33.778: + Pressed R1
33.778: Event Crouch
33.794: + Pressed A
33.794: Event SuperJump
33.961: – Released A
33.977: – Released R1

Note that in the first listing A is pressed before R1 (by 0.016 seconds), so the game triggers a jump first, and then a ground pound.

In the second listing R1 is pressed 0.016 seconds before A is pressed, meaning the game triggers the crouch, then as we are crouched, it triggers a Super Jump when A is pressed.

To the player, it looks and feels like they attempted to do the same thing both times. They simply pressed A and R1 simultaneously. There is no way whatsoever that they can distinguish between the two events described above. The response of the game is inconsistent and ambiguous. There is no clear link formed in the player's mind between action and response. They get annoyed. Your job is to stop this happening.

Log files are useful but can be rather dense, and difficult to pore over. The lines all look alike, and the problem can be hidden in a dense flurry of events. The next step is to present this information in a graphical format.

Our Test App
Figure 7 – The test application; a simple platform game with the input debug graph shown on the top.