• No results found

Figure 5.4 Microsoft's Force Editor, built into the DirectX SDK.

From the application's point of view, differences start at the device enumeration phase. We need to query for force feedback compatible devices only, as follows:

HRESULT hr = g_pDI->EnumDevices( 0, EnumFFDevicesCallback, 0, DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK );

No changes to the EnumDevicesCallback function are required. A force feedback joystick is, as far as devices go, just a plain joystick that can be read as usual. The next relevant step is reading the effects from a .ffe file. One such file can contain several effects, so we will use an Enum call with a Callback function to retrieve those effects. Here is the Enum call:

HRESULT hr = g_pFFDevice->EnumEffectsInFile( strFileName, EnumAndCreateEffectsCallback,

NULL, DIFEF_MODIFYIFNEEDED );

Let's now examine the code for the callback. For simplicity, I will assume the .ffe file only contains one effect; so after retrieving it, no further calls will be pursued. Here is a suggested implementation of the routine, which stores the effect in persistent structure for later access. As usual, error checking is deleted for clarity:

LPDIRECTINPUTEFFECT pDIEffect;

BOOL CALLBACK EnumAndCreateEffectsCallback( LPCDIFILEEFFECT pDIFileEffect, VOID* pvRef ) {

HRESULT hr = g_pFFDevice->CreateEffect( pDIFileEffect->GuidEffect, pDIFileEffect->lpDiEffect,

&pDIEffect, NULL ); return DIENUM_STOP; }

Then, all we have to do is trigger the effect as needed. This is a two-step process. First, we need to stop any previous forces, so both effects do not conflict. Second, we trigger the new effect. Here is a simple example—first, the stop for any other effects:

HRESULT hr = g_pFFDevice->SendForceFeedbackCommand( DISFFC_STOPALL );

second, the execution of the effect: HRESULT hr = pDIEffect->Start(1, 0);

The first parameter is the number of repetitions we want for the effect, and the second parameter is a flags parameter. Passing INFINITE as the first parameter causes the effect to loop forever, such as the engine vibration for a helicopter. These kinds of effects must be manually stopped with a call to:

pDIEffect->Stop();

The force feedback API from DirectInput is very comprehensive. But we have only scratched the surface. For example, we can mix effects dynamically or even create them procedurally without using the Force Editor. With time and lots of experimentation, many interesting uses can be devised.

[ Team LiB ]

In Closing

Input is a vast subject, requiring many techniques. But unfortunately, no broad standards are available. Although we have focused on specific techniques for the PC, most ideas are valid for other platforms as well. Ideas like device abstraction, mouselooks, or response curves are universal and are also used on other platforms.

[ Team LiB ]

Chapter 6. Fundamental AI Technologies

"I not only use all the brains that I have, but all that I can borrow."

—Woodrow Wilson KEY TOPICS Context Structure of an AI System Specific Technologies In Closing

An interesting artificial intelligence is a major component of any successful game. AI makes games challenging and addictive, and thus generates a large portion of the gameplay value. AI is a deeply evolved science with more than 50 years of history. This means very well-known methods exist to cover a broad range of scenarios and goals, whether it's commanding an army in Age of Empires or piloting a tie fighter in a Star Wars game.

In this chapter, we will study how game AI is just a specific application of general concepts from classic AI. This means most traditional AI techniques will be perfectly valid for in-game use. On the other hand, our craft will require some specific tricks and twists, such as added attention to performance and a focus on aesthetically pleasing results. In the next two chapters, we will survey game AI techniques in some detail. We will use this first chapter as an introduction to general-purpose AI techniques, so we can devote the next two chapters to action and strategic game AI, respectively. In Chapter 9, "Scripting," we will do a survey of techniques for one of the most powerful paradigms for coding any AI system. These four chapters, taken as a whole, should provide a clear and thorough understanding of the state of the industry.

[ Team LiB ]

Context

So, what is AI anyway? What are the goals and conditions that differentiate a good AI system from a bad one? Essentially, bad AI design often starts by setting the wrong goals.

One definition of AI might be something like "AI is the computer simulation of intelligent behavior." This would be valid except for the fact that we really don't know for sure what intelligence is. Does "intelligence" mean "behavior that exhibits great ability to adapt and solve complex problems," or is it "behavior that is close to that of humans"? History shows us again and again that humans are not always brilliant, yet there is a quality to their behavior that makes them intelligent. As you will learn in this chapter, some games make the mistake of trying to follow the first definition, and by doing so, produce results that are completely unrealistic. Take, for example, one of the classic AI problems—finding a route from point A to point B that avoids obstacles.

Many algorithms exist to solve this problem with varying degrees of success. They analyze the map and trace a path connecting the two endpoints and avoid any obstacles in-between. Some of them, however, go too far, ensuring that the path between A and B is

optimal—that is, the shortest possible path. This is the case in the popular A* algorithm, which we will cover in Chapter 8, "Tactical AI." According to the first definition, A* is clearly a very intelligent algorithm. In fact, it is so intelligent that it can algorithmically build optimal paths between two endpoints, even if we have to cross many miles and obstacles in the process. But it's completely unrealistic when compared to the behavior of a human being. Humans do not trace optimal paths, and they often make mistakes traversing very complex labyrinths (see Figure 6.1).

Figure 6.1. Comparison between A

*

and a human path finder. Left: initial problem. Middle:

human. Notice how we try to approach the target, and if there's no path available, often bail out.

Right: A

*

knows the solution beforehand so it traces a highly unrealistic but correct path