Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

3D Game Programming All In One (2004)

.pdf
Скачиваний:
139
Добавлен:
17.08.2013
Размер:
17.91 Mб
Скачать

628Chapter 22 The Game Server

After putting that code in, copy C:\3DGPAi1\RESOURCES\CH22\ITEM.CS over to C:\koob\control\server\misc. You will find the datablocks for the coins (where the coin values are assigned) in there.

Note that when we added the coins in the preceding code, the static parameter was set to 0. This means that the game will not create a new coin at the place where the coin was picked up, if it is picked up. The weapons of the ammo do this, but we don't want our coins to do it. It's a game play design decision.

In addition to the datablocks for the coins in item.cs, you will also find this code:

if (%user.client)

{

messageClient(%user.client, 'MsgItemPickup', '\c0You picked up %1', %this.pickup-

Name);

%user.client.money += %this.value; %user.client.DoScore();

}

The last two statements in there allow the player to accumulate the money values, and then the server notifies the client of the new score. Note that it is similar in that small way to the checkpoint scoring.

Again, until the client code is in place, you can insert echo statements there to verify that things are working properly.

Deaths

We want to track the number of times we die to further satisfy requirements, so open C:\koob\control\server\server.cs, locate the method GameConnection::onDeath, and add these lines at the end:

%this.deaths++;

%this.DoScore();

By now these lines should be familiar. We can expand the player death by adding some sound effects and animation. Add the following to the end of C:\koob\control\server\ players\player.cs:

function Player::playDeathAnimation(%this,%deathIdx)

{

%this.setActionThread("Die1");

}

datablock AudioProfile(DeathCrySound)

{

fileName = "~/data/sound/orc_death.wav"; description = AudioClose3d;

Team LRN

Triggering Events

629

preload = true;

};

function Player::playDeathCry( %this )

{

%client = %this.client; serverPlay3D(DeathCrySound,%this.getTransform());

}

The first function, playDeathAnimation, will play the animation sequence we named Die1 in our model. After that is another audio profile, pretty straightforward, followed by the function playDeathCry, which will play that profile's sound effect. These are invoked by two lines that you should place in the OnDisabled function farther back up in the player.cs file. Add these two lines to OnDisabled just before the call to SetImageTrigger:

%obj.playDeathCry();

%obj.playDeathAnimation(-1);

One more thing—copy the audio wave file C:\3DGPAi1\RESOURCES\CH22\ORC_ DEATH.WAV to C:\koob\control\data\sound in order to make the sound work.

Kills

The victim, who notifies the shooter's client when he dies, actually does the kill tracking. So we go back to GameConnection::onDeath and add this:

%sourceClient = %sourceObject ? %sourceObject.client : 0; if (%obj.getState() $= "Dead")

{

if (isObject(%sourceClient))

{

%sourceClient.incScore(1); if (isObject(%client))

%client.onDeath(%sourceObject, %sourceClient, %damageType, %location);

}

}

This bit of code figures out who shot the player and notifies the shooter's client object of this fact.

Now it is important to remember that all this takes place on the server, and when we refer to the client in this context, we are actually talking about the client's connection object and not about the remote client itself.

Okay, so now let's move on to the client side and finish filling the requirements!

Team LRN

630 Chapter 22 The Game Server

Moving Right Along

So, now we have our player's model ready to appear in the game as our avatar, we've got wheels for him to get around in, and a way to figure out where he's been.

We've also put some things in the game world for the player to pursue to accumulate points, and a way to discourage other players from accumulating too many points for themselves (by killing them).

All of these features are created on the server. In the next chapter, we will add the features that will be handled by the game client.

Team LRN

chapter 23

The Game Client

By now we've met most of our requirements, at least to the point of implementation. Testing them for correct operation and completeness I will leave as an exercise for you, Gentle Reader, because you may (and probably will) want to modify

and enhance the requirements anyway.

According to my list, the requirements that remain outstanding are the following:

2.Internet multiplayer game play.

3.Global in-game chat.

11.All other players are enemies.

12.All point values configurable from a setup file.

14.3 points per vehicle destroyed.

15.Ability to race around the track and score 5 points for each lap you lead. (partial)

16.Laps can only be scored in the car.

17.A 10-lap race with no time limit.

18.A 10-point bonus for winning the race.

29. When one map is finished, cycle to the next in the list.

Of this list, I will leave numbers 14, 16, 17, and 18 and the remaining portion of number 15 (scoring 5 points) to you to complete as exercises. They are variations of the coin scoring and the lap and checkpoint tracking we covered in Chapter 22. The functioning code is available in the Koob installation kit on the CD, if you need help.

Most of the remaining work requires additional client code to support the server addi-

 

tions we made in the last chapter—we'll add some multiplayer support, a little bit more

 

client support, and user interfaces to access those capabilities.

631

Team LRN

632 Chapter 23 The Game Client

Client Interfaces

We are going to add code to allow users to run a server and to allow players to connect to a server. In order to make that connection, we will want to provide the user with an interface he can use to find servers, decide which one offers an interesting game, and then connect to the server.

Another thing we need to do is make sure that when the user quits a server, he returns to his selection interface rather than simply exiting as Koob does now.

Additionally, we need to add a capability to the playing interface to provide a chat window with a text entry where players can type in messages to send to other players. Maybe they'll want to exchange recipes or something. Yeah, that's it—recipes! It's not like they're going to taunt anyone anyway, is it?

In Chapter 6 you saw the MasterScreen interface module that combined these interfaces. In this chapter we'll look at the same issue but in a slightly different way, in order to show how easy it is to make different—yet equally valid—design decisions.

Also, we'll need to modify a few of the files, like the MainScreen interface, to more closely conform to our needs.

In a later section we'll add the code required to make these interfaces functional.

MenuScreen Interface

We will make some changes to our main menu screen so that it provides the user with the additional choices to

view information about the games and credits

play in single-player mode (as it already has)

host a game

connect to another server

Open your MenuScreen.gui file and locate the following line:

command = "LaunchGame();";

This line is a property statement in a GuiButtonCtrl. Delete the entire control, from where it says

new GuiButtonCtrl() {

down to the closing brace ("}").

In the place of the deleted control, insert the following:

Team LRN

Client Interfaces

633

new GuiButtonCtrl() {

profile = "GuiButtonProfile"; horizSizing = "right"; vertSizing = "top";

position = "30 138"; extent = "120 20"; minExtent = "8 8"; visible = "1";

command = "Canvas.setContent(SoloScreen);"; text = "Play Solo";

groupNum = "-1"; buttonType = "PushButton";

helpTag = "0";

};

new GuiButtonCtrl() {

profile = "GuiButtonProfile"; horizSizing = "right"; vertSizing = "top";

position = "30 166"; extent = "120 20"; minExtent = "8 8"; visible = "1";

command = "Canvas.setContent(ServerScreen);"; text = "Find a Server";

groupNum = "-1"; buttonType = "PushButton";

helpTag = "0";

};

new GuiButtonCtrl() {

profile = "GuiButtonProfile"; horizSizing = "right"; vertSizing = "top";

position = "30 192"; extent = "120 20"; minExtent = "8 8"; visible = "1";

command = "Canvas.setContent(HostScreen);"; text = "Host Game";

groupNum = "-1"; buttonType = "PushButton";

helpTag = "0";

};

Team LRN

634 Chapter 23 The Game Client

new GuiButtonCtrl() {

profile = "GuiButtonProfile"; horizSizing = "right"; vertSizing = "top";

position = "30 237"; extent = "120 20"; minExtent = "8 8"; visible = "1";

command = "getHelp();"; helpTag = "0";

text = "Info"; groupNum = "-1";

buttonType = "PushButton";

};

You may, if you wish, use the built-in GUI Editor (press F10) to do this. Make sure that you set all of the properties to match those just listed.

The significant thing to note about these controls is the command property. Each one replaces a displayed MenuScreen interface with a new interface, according to its function, with the exception of the Info button.

The Info button uses the getHelp feature of the common code base. It searches all of the directories nested under the root main directory looking for files with the extension .hfl, and then it lists them in alphanumeric order. If you preface the file name with a number, such as 1., 2., and so on, it will sort them numerically.

This should give you a main menu that looks like Figure 23.1.

SoloPlay Interface

The SoloPlay interface, as shown in Figure 23.2, prepares a list of mission files that it finds in the maps subdirectory in the control\data directory tree. From this list, you can select the map or mission you want to play. Its code and definition can be found in the SoloScreen modules.

It's worth remembering that even when you play in solo mode, under-

neath the hood, the Torque Engine is

Figure 23.1 MenuScreen interface.

Team LRN

Client Interfaces

635

still running in two parts: a client and a server. They are just closely coupled with no cross-network calls being made.

Host Interface

The Host interface is somewhat similar, as you can see in Figure 23.3, but offers more options: the ability to set a time limit and a score limit, plus map selection modes. Its code and definition can be found in the HostScreen modules.

If both time and score limits are set, the first one reached ends the game. A setting of 0 makes that limit infinite. The sequence mode causes the server to step through the maps in order as shown in the listing, as each game finishes and the new one loads. The random mode causes the server to randomly select a map for each game. The time limit is saved by the control in the variable $Game::Duration, and the score limit is saved as $Game::MaxPoints.

FindServer Interface

Figure 23.2 SoloPlay interface.

Figure 23.3 Host interface.

The FindServer interface, shown in Figure 23.4, lets you browse for servers. Its code and definition can be found in the ServerScreen modules. It will find servers that are running on the local LAN you are connected to (if you are connected to one, of course), and it will attempt to reach out via the Internet to contact the master servers at GarageGames and find games for you to connect to. You are not required to use the GarageGames master servers, but then you will have to write your own master server software to connect to. This can be done using Torque Script but is beyond the scope of this book. There are master server resources available from the GarageGames user community.

Team LRN

636 Chapter 23 The Game Client

n o t e

The Query LAN button on the FindServer interface does the same thing that was done automatically in Chapter 6 when you clicked on the Connect to Server button on the main menu screen. The discussion in the Chapter 6 section called ServerScreen Code Module describes how the Connect to Server button operations are performed, which is the same as how the Query LAN button operations work here.

ChatBox Interface

In order to display chat messages from other players, we need to put a control in our main player interface. We also need to have a control that will allow us to type in messages to be sent to other players, as depicted in Figure 23.5.

Open the file C:\koob\control\client\Initialize.cs and add the following lines to the function InitializeClient:

Figure 23.4 FindServer interface.

Figure 23.5 ChatBox interface.

Team LRN

Client Interfaces

637

Exec("./interfaces/ChatBox.gui");

Exec("./interfaces/MessageBox.gui");

These exec statements load the new files that will provide our chat interface. You can copy them from C:\3DGPAi1\RESOURCES\CH23 and put them into the directories under the C:\koob\control\client\ directory in the subdirectories specified in the exec statements.

Now open the file C:\koob\control\client\misc\presetkeys.cs and add the following keyboard input binding statements to the end of the file:

function pageMessageBoxUp( %val )

{

if ( %val ) PageUpMessageBox();

}

function pageMessageBoxDown( %val )

{

if ( %val ) PageDownMessageBox ();

}

PlayerKeymap.bind(keyboard, "t", ToggleMessageBox );

PlayerKeymap.bind(keyboard, "PageUp", PageMessageBoxUp );

PlayerKeymap.bind(keyboard, "PageDown", PageMessageBoxDown );

The first two functions are glue functions that are called by two of the key bindings at the bottom and then make the appropriate call to the functions that scroll the messages in the message box. We need these functions in order to filter out the key up and key down signals from the engine. We only want the action to take place when the key is pressed. We can do this by checking the value of %val when we enter the function—it will be nonzero when the key is pressed and zero when it is released.

Then there is a binding that calls ToggleMessageBox, which is defined in MessageBox.cs (one of the files we've recently copied that we will examine shortly).

In the interface files there are a couple of concepts you should note. To illustrate, look at the definition of the ChatBox interface, contained in ChatBox.gui:

new GuiControl(MainChatBox) {

profile = "GuiModelessDialogProfile"; horizSizing = "width";

vertSizing = "height"; position = "0 0"; extent = "640 480"; minExtent = "8 8"; visible = "1";

modal = "1";

Team LRN