3D Game Programming All in One (Course Technology PTR Game Development Series)

Weapon sounds are an interesting study. Weapons have specific support in Torque, through the use of a programming construct called a state machine. The basic idea is that we break the operation of a weapon down into different stages, called states, and we define a specific set of behaviors for each state. Within each state, we are not aware of what the previous state was, only what needs to be done in this state.

Using this system, we can quite readily define some rather complex behaviors.

To set up for this, go find the Tommy gun model you created back in Chapter 16, and copy the model (the DTS file) and the artwork (the PNG file) that goes with the model to C:\koob\control\data\models\weapons\. Then locate the directory C:\3DGPAi1\ RESOURCES\CH20\ and copy the file tommygun.cs into C:\koob\control\server\ weapons\.

Next, from the same directory, copy the following files to C:\koob\control\data\models\weapons\:

ammo.jpg bullethole.png muzzleflash.png tgammo.dts tgprojectile.dts tgshell.dts tommygun.cs tommygun.dts tommygun.jpg

Now for the sounds. I'm not going to make you record your own sounds. You can copy them from the same directory.

ammo_pickup.wav dry_fire.wav short_reload.wav tommy_gun.wav weapon_pickup.wav weapon_switch.wav

Deposit these sound files into C:\koob\control\data\sound\.

Next, open the file C:\koob\control\server\server.cs and find the line that reads as follows:

$Game::StartTime = 0;

Just beyond that line is a block of exec() statements. Insert the following at the top or bottom of that block of statements:

Exec("./weapons/tommygun.cs");

This tells the engine to load our Tommy gun definition file.

Next, open the file C:\koob\control\server\players\player.cs and find the line that reads as follows:

datablock PlayerData(HumanMaleAvatar)

At the end of the datablock that starts with that line, before the closing brace ("}") that ends the datablock, insert the following lines:

maxInv[Tommygun] = 1; maxInv[TommygunAmmo] = 20;

This indicates how many of the listed items the player can have in his possession, or inventory, at any given time.

And finally, open the file you copied earlier, C:\koob\control\server\weapons\tommygun.cs, and add the following lines to the end:

datablock AudioProfile(TommyGunMountSound) { filename = "~/data/sound/shortreload.wav"; description = AudioClose3d; preload = true; }; datablock AudioProfile(TommyGunReloadSound) { filename = "~/data/sound/shortreload.wav"; description = AudioClose3d; preload = true; }; datablock AudioProfile(TommyGunFireSound) { filename = "~/data/sound/tommygun.wav"; description = AudioClose3d; preload = true; }; datablock AudioProfile(TommyGunDryFireSound) { filename = "~/data/sound/dryfire.wav"; description = AudioClose3d; preload = true; }; datablock AudioProfile(WeaponSwitchSound) { filename = "~/data/sound/Weapon_switch.wav"; description = AudioClose3d; preload = true; }; //-------------------------------------------------------------------------- // TommyGun image which does all the work. Images do not normally exist in // the world, they can only be mounted on ShapeBase objects. datablock ShapeBaseImageData(TommyGunImage) { shapeFile = "~/data/models/weapons/TommyGun.dts"; offset = "0 0 0"; mountPoint = 0; emap = true; className = "WeaponImage"; item = TommyGun; ammo = TommyGunAmmo; projectile = TommyGunProjectile; projectileType = Projectile; casing = TommyGunShell; armThread = "look2"; // State Data stateName[0] = "Preactivate"; stateTransitionOnLoaded[0] = "Activate"; stateTransitionOnNoAmmo[0] = "NoAmmo"; stateName[1] = "Activate"; stateTransitionOnTimeout[1] = "Ready"; stateTimeoutValue[1] = 0.7; stateSequence[1] = "Activated"; stateSound[1] = WeaponSwitchSound; stateName[2] = "Ready"; stateTransitionOnNoAmmo[2] = "NoAmmo"; stateTransitionOnTriggerDown[2] = "Fire"; stateScript[2] = "onReady"; stateTransitionOnReload[2] = "Reload"; stateName[3] = "Fire"; stateTransitionOnTimeout[3] = "Ready"; stateTimeoutValue[3] = 0.096; stateFire[3] = true; stateRecoil[3] = LightRecoil; stateAllowImageChange[3] = false; stateSequence[3] = "Fire"; stateScript[3] = "onFire"; stateSound[3] = TommyGunFireSound; stateEmitter[3] = TommyGunFireEmitter; stateEmitterTime[3] = 1.0; stateEmitterNode[3] = "muzzlePoint"; stateName[4] = "Reload"; stateTransitionOnNoAmmo[4] = "NoAmmo"; stateTransitionOnTimeout[4] = "FinishedReloading"; stateTimeoutValue[4] = 3.5; // 0.25 load, 0.25 spinup stateAllowImageChange[4] = false; stateSequence[4] = "Reload"; stateScript[4] = "onReload"; stateSound[4] = TommyGunReloadSound; stateName[5] = "FinishedReloading"; stateTransitionOnTimeout[5] = "Activate"; stateTimeoutValue[5] = 0.04; stateScript[5] = "onFinishedReloading"; stateName[6] = "NoAmmo"; stateTransitionOnAmmo[6] = "Reload"; stateSequence[6] = "NoAmmo"; stateScript[6] = "onNoAmmo"; stateTransitionOnTriggerDown[6] = "DryFire"; stateName[7] = "DryFire"; stateSound[7] = TommyGunDryFireSound; stateScript[7] = "onDryFire"; stateTimeoutValue[7] = 0.5; stateTransitionOnTimeout[7] = "NoAmmo"; stateName[8] = "WaitTriggerRelease"; stateScript[8] = "onWaitTriggerRelease"; stateTransitionOnTimeout[8] = "WaitTriggerRelease"; stateTimeoutValue[8] = 0.01; stateTransitionOnTriggerUp[8] = "Ready"; autoFire = true; weaponDamage = 60; minSpread = 0.01; maxSpread = 0.045; spreadRate = 0.019; // amount spread should increase per shot spreadRecoverRate = 0.003; };

The first thing this new code does is define a bunch of audio profiles, TommyGunMountSound, TommyGunReloadSound, TommyGunFireSound, TommyGunDryFireSound, and WeaponSwitchSound. These profiles are used in each of the different weapon firing states. Those states are defined in the next part of the new code.

That next part is a datablock of the type ShapeBaseImageData. This is what defines the gun itself and how it works.

First, there is a set of basic properties, like where to find the model that represents the image and so on. For this example, I have used the same model as the one that is used for the external view—the view of your player model that everyone else sees. You, though, only see the weapon image. This means that to do this right, you will need to make another model of the weapon for use in this image. Later on you will see why this matters.

Now we add the WeaponImage name space as a parent. The WeaponImage name space provides some hooks into the inventory system that are necessary for picking up the gun.

Next are a bunch of pointers that tell what various resources we will need in order to use this gun.

Finally, we encounter the code that defines the state machine. What happens is that when you pick up the gun, the Torque Engine sets it to the first state: Preactivate.

In the Preactivate state, we have only two variables, and they tell the state machine what to do immediately next. If the gun is loaded, it should change to the Activate state; if not, it should change to the NoAmmo state. If you scroll down until you find the line that says stateName[6] = "NoAmmo"; you will find that state's definition.

In the NoAmmo state, there are several directives that the engine must follow while in this state. If we suddenly receive some ammo, then we change to the Reload state. If the gun's trigger is pressed, we enter the DryFire state. Note that there is also a pointer to a function (the onNoAmmo function) that we can execute when we find ourselves in this state. This can also be called the state handler.

All of the rest of the states operate in a similar way, and the directives are quite easy to read and follow. The important ones for this chapter are the stateSound directives, which tell the engine which audio profiles to use when we arrive in that state.

The state machine definition in the TommyGunImage datablock you've just seen is really quite easy to follow. You can modify it in all sorts of ways to accommodate any variation you can imagine.

Now after getting C:\koob\control\server\weapons\tommygun.cs typed in and double-checking it all, let's try it out.

Launch your Koob game. Once you have spawned in, we are going to use the World Editor to insert a Tommy gun and some ammo into the game world.

  1. Press F8. This will set your player into camera fly mode.

  2. Press F11. This will open up the World Editor, as shown in Figure 20.1.

    Figure 20.1: World Editor.

  3. Press F4. This will open up the World Editor Creator, as shown in Figure 20.2. The Creator frame is at the lower-right corner of the window.

    Figure 20.2: World Editor Creator.

  4. In the Creator frame, click the plus sign next to the entry Shapes. This will expand the listing.

  5. Locate Weapon and click the plus sign to open it as well. You should now have a Tree view similar to Figure 20.3.

    Figure 20.3: The Creator Tree view.

  6. Make sure that the center of the view is located in an open area about 10 virtual feet in front of you. To move the view in the World Editor, hold down the right mouse button, and move the mouse.

  7. Click Tommygun in the Tree view. The Tommy gun model will appear; it will probably be somewhat embedded in the ground, as shown in Figure 20.4, and it will be rotating.

    Figure 20.4: Tommy gun model.

  8. Move the cursor over on top of the vertical line (labeled Z) that sprouts from the top of the gun model. The Z label will become highlighted, as shown in Figure 20.5.

    Figure 20.5: The Z label.

  9. Click the vertical Z line and drag it up just a few pixels, until the gun is completely out of the ground, as depicted in Figure 20.6.

    Figure 20.6: Repositioned Tommy gun.

    Note that this is the reason why you needed to switch to camera fly mode before entering the World Editor. If you had stayed in normal FPS view mode, you would not have been able to grab the Z line and move it.

  10. Now turn your view slightly to the side, and repeat the same process by placing an ammo box, as shown in Figure 20.7. The ammo box can be found in the Tree view at Shapes, Ammo, TommygunAmmo.

    Figure 20.7: Placing ammo box.

  11. Now press F11 to toggle out of the World Editor.

Okay, now run on over and pick up the ammo and the Tommy gun by just passing right over on top of them.

You will immediately notice that the gun doesn't carry properly. However, go ahead and shoot it, and listen to the firing sequence and all of the sounds we've been dealing with. You can make another model to act as the mounted (carried) version of the gun. Also, you will need to adjust your model animations to ensure the model will carry the gun properly—the provided example character doesn't do that.

You can go back to your ShapeBaseImageData in the tommygun.cs file and fiddle with the state machine and other variables and see how they affect your gun's behavior.

Категории