informa
Features

Programming Responsiveness

If you can't control your actions in a game, might the game be to blame? In a technical article, Neversoft co-founder Mick West examines the problem of - and solutions for - response lag in game code.

[If you can't control your actions in a game, might the game be to blame? In a technical article, Neversoft co-founder Mick West examines the problem of response lag in games, along with a number of possible solutions.]

Responsiveness is something that can make or break a game at first impression. This is especially true in reviews where a game with poor responsiveness will be described as "sluggish," "unresponsive," "floaty," or "sloppy." A better game might be called "tight" or "responsive."

Several factors contribute to perceived responsiveness, and this article looks at some of them from a programmer's perspective, offering a few routes to making your game more responsive.

Response Lag

Response lag is the delay between the player triggering an event and the player receiving feedback (usually visual) that the event has occurred. If the delay is too long, the game feels unresponsive. Several factors contribute to the length of this response lag.

If your game is unresponsive, it may well be the cumulative effects of four or five different factors. Adjusting one factor alone may not make a perceptible difference, but addressing all the factors can lead to a noticeable improvement.

Players, and sometime even designers, cannot always put into words what they feel is wrong with a particular game's controls. Often they will try to do something that requires some synchronization, but will fail, and they won't be able to tell you "the event happened 0.10 seconds after my input," but will instead say the game felt "slow" or "not tight" or "difficult."

Or they might not be able to tell you anything concrete, and simply say the game sucks, without really understanding why it sucks.

Designers and programmers need to be aware of response lag and the negative effect it has on a game, even if test players do not directly report it as a factor.

Why Lag Happens

To understand why lag occurs, you need to understand the sequence of events that occur from the time the user presses a button, to the time the results appear on screen. To understand this, we need to look at the main loop structure of the game. The main loop performs two basic tasks: logic and rendering.

The logic portion of a main loop updates the game state (the internal representation of the game objects and environment), while the rendering portion creates a frame that's displayed on the television.

At some point in the main loop, usually at the start, we also get input from the user, which is sometimes considered a third task in the main loop, but is also commonly a part of the logic task. I've kept it separate here because it's important to see in what order things happen.

There are several ways a main loop can be structured. The simplest is shown in Listing 1, where we simply alternate between calling the logic and the rendering code. We assume that some frame synchronization occurs in the call to Rendering() and that we're running at a fixed frame rate, usually 60fps or 30fps for an NTSC console game.

Listing 1: The Simplest Main Loop

while (1) {
Input();
Logic();
Rendering();
}

The main loop here also only shows half the story. The call to Rendering() is doing the CPU side of the rendering task, which is iterating over the environment and the object, culling, animating, sorting, setting up transforms, and building a display list for the GPU to execute.

The actual GPU rendering is performed after the CPU rendering and usually is asynchronous, so while the main loop is processing the next frame, the GPU is still rendering the previous one.

So when does the lag come in? To understand the factors that contribute to lag, you need to understand the sequence of events that occurs from the user pressing a button to the feedback for pressing that button.

At the highest level, the user presses a button; the game logic reads that button press and updates the game state; the CPU render function sets up a frame with this new game state, then the GPU renders it; and finally this new frame is displayed on the screen.


Figure 1: When a player presses a button, the game can take up to three frames (in the best case) to create visual feedback and programming problems can introduce additional frames of lag. The actual lag time is multiplied by the length of a single game frame.

Figure 1 shows this sequence graphically. Sometime in Frame 1, the player presses a button to fire a gun. Since the input processing has already been done for that frame, this input is read in Frame 2. Frame 2 updates the logic state based on this button press (a shot is fired).

Also in Frame 2, the CPU side of rendering is performed with this new logic state. Then in Frame 3, the GPU performs the actual rendering of this new logic state. Finally at the start of Frame 4, the newly rendered frame is presented to the user by flipping the frame buffers.


So how long is the lag? It depends on how long a frame is (where a "frame" here is a complete iteration of the main loop). It takes up to three frames for the user's input to be translated into visual feedback.

So if we are running at 30fps, then the lag is 3/30th or one-tenth of a second. If we are running at 60fps, then the lag will be 3/60th or 1/20th of a second.

This calculation illustrates a common misconception about the difference between 60fps and 30fps games. Since the difference between these two frame rates is just 1/60th of a second, people assume that the difference in responsiveness will also be 1/60th.

But in fact, going from 60 to 30 does not just add a vsync to your lag, it acts as a multiplier, doubling the length of the process pipeline that's responsible for lag. In our ideal example in Figure 1, it adds 3/60ths of a second, not 1/60th. If the event pipeline is longer, which it quite possibly can be, it can add even more.

Figure 1 actually illustrates the best possible sequence of events. The button press event is translated into visual feedback via the shortest path possible, which we can clearly see in the sequence of events.

As a programmer, being familiar with the order in which things happen is a vital part of understanding why things act the way they do in the game. It's quite easy to introduce additional frames of lag (meaning an extra 1/60th or 1/30th of a second delay), by not paying careful attention to the order in which events occur.

As a simple example, consider what would happen if we switched the order of the Logic() and Rendering() calls in our main loop. Look at Frame 2 of Figure 1: here the GPU logic (rendering) happens after CPU logic, so input at the start of Frame 2 will affect the CPU logic and hence the GPU logic in the same frame.

However if GPU logic is performed first, then the input will not have an effect on GPU logic until the next frame, hence introducing an extra frame of lag. While this is a novice mistake, programmers need to make absolutely sure it's not happening.

Extra frames of lag can be introduced in a subtler manner as a result of the order of operations within the game logic. In our example, we are firing a gun.

Now perhaps our engine is set up to increment the position of the objects in the world using a physics engine, and handle events that are raised due to this update (such as collision events). In this situation, the sequence of input or logic looks like Listing 2.

Listing 2: Physics Update Is Followed By Event Handling

void Logic() {
HandleInput();
UpdatePhysics();
HandleEvents();
}

Event handling via messages is a very nice way of decoupling systems and a programmer might decide to use it for the player control events. To fire a gun, the HandleInput() function will fire an event telling the gun to fire.

The HandleEvents() function will take this event and cause the gun to actually fire. But because the physics update has already happened for this frame, the effect on the world state will not be incorporated until the next frame, hence introducing an extra frame of lag.

More Lag Causes

Lower level action ordering can draw out the lag even more. Consider a jump, for example. The feedback is the character actually moving. To make something move in a game, you can either set the velocity directly or apply a force to it, such as acceleration or, more likely, a momentary impulse.

There's a problem in this scenario if your physics engine updates positions before the velocity change is applied, a common condition in many introductory game programming tutorials.

Although the velocity of the jumping object is updated in the same frame as the one where the input event is handled, the object will not actually begin to move until the next time around the loop-on the next game frame-and so it introduces an additional frame of lag.

Remember, these are cumulative problems that can be difficult to discern in isolation, but the combined effect can make your game controls turn to mush.

Suppose you had made all three mistakes listed above: you do rendering before logic, you handle logic events after advancing the physics state, and you update position before velocity. That's three additional full iteration of the main loop, in addition to the three you already have built in-six frames of lag between the player pressing a button and seeing the result on screen.

At 60 frames per second that's 1/10th of a second, which is bad enough, but if the game is running at 30fps, the lag is doubled to an unbearable 1/5th of a second, or 200 milliseconds.


Other factors can contribute to lag, further compounding the consequences. Movement can be driven by animations, with velocity changes built into specific time points in an animation. For example, if the animator places the jump velocity impulse a fraction of a second into the animation to better match the visuals, it might look better, but it feels bad.

The animator can correct it by making sure the velocity impulse is on the first frame of animation when the player needs that immediate feedback. But then the question is how does triggering an animation translate into actual movement?

It's quite likely that animation updating is handled by the Render() function. Any events triggered by the animation will not be handled until the time around the loop, which adds another frame.

In addition, triggering an animation might not make it advance a frame until the next frame, delaying the event firing for a frame. Our lag could potentially be increased from six to eight frames, which would be quite unplayable, even at 60 frames per second.

That's not the end of it either. There are many other ways in which extra frames of lag sneak their way into a game. You might be pipelining your physics on a separate thread (or a physics processing unit).

What if you're using triple buffering to smooth your frame rate? You could be using abstract events that take a couple of passes through the system to resolve into real events. You might use a scripting language that adds an additional frame in the way it waits for an event.

It's quite possible to make your game logic incredibly flexible by abstracting various concepts of time and events, and yet while doing this, programmers can lose sight of exactly what's going on under the hood, making it far easier for additional frames of delay to creep in.

Responsiveness, Not Reaction Time

One of the great misconceptions regarding responsiveness is that it's somehow connected to human reaction time. Humans cannot physically react to a visual stimulus and then move their fingers in less than one-tenth of a second.

Game players' peak reaction times vary from 0.15 seconds to 0.30 seconds, depending on how "twitchy" they are. Quantifiables such as these are often brought up when discussing game responsiveness, but the connection is specious.

It's not how fast a player reacts to the game; it's how fast the game reacts to the player. The issue is not one of reaction times, but of synchronization.

Take Guitar Hero, for example, a game in which symbols come at you, the player, and you have to hit the correct button at a very precise point in time (when the target object is within a particular region). You are anticipating the future event, and there is no reacting involved at all.

The problems of lack of responsiveness occur when the game does not react fast enough to the player and the target object has moved beyond the target region by the time the event occurs.

If you press the button at the correct time, you do not expect the object to move even a few more pixels before it explodes. But since objects generally move at least a few pixels per frame, having a few frames of lag can permit the object to drift past its target.

Many action games are based around anticipation and button pressing. In a skateboarding game, you want to jump just before you hit the end of a rail. In a first-person shooter, you fire the instant someone moves in front of your gun.

Again, this is not reaction time. You usually have seen the target at least half a second before you shoot it, probably more, and will be either moving the gun, or waiting for the target to move in front of the gun.

Because of the somewhat unintuitive nature of these problems with responsiveness, it is important for programmers to fully understand the issues. The most important thing is to be able to clearly describe the frame-by-frame path through logic and rendering that a button-triggered action takes before it creates visual feedback. Once you have this, you can optimize it as close to the optimal pathway as possible.

[EDITOR'S NOTE: This article, originally published in Game Developer magazine, was independently selected by Gamasutra's editors, since it was deemed of value to the community. Its republishing has been made possible by Intel, as a platform and vendor-agnostic part of Intel's Visual Computing microsite.]

Latest Jobs

Sucker Punch Productions

Bellevue, Washington
08.27.21
Combat Designer

Xbox Graphics

Redmond, Washington
08.27.21
Senior Software Engineer: GPU Compilers

Insomniac Games

Burbank, California
08.27.21
Systems Designer

Deep Silver Volition

Champaign, Illinois
08.27.21
Senior Environment Artist
More Jobs   

CONNECT WITH US

Register for a
Subscribe to
Follow us

Game Developer Account

Game Developer Newsletter

@gamedevdotcom

Register for a

Game Developer Account

Gain full access to resources (events, white paper, webinars, reports, etc)
Single sign-on to all Informa products

Register
Subscribe to

Game Developer Newsletter

Get daily Game Developer top stories every morning straight into your inbox

Subscribe
Follow us

@gamedevdotcom

Follow us @gamedevdotcom to stay up-to-date with the latest news & insider information about events & more