T3D/Tutorials/SimpleFPSTutorial/Part7

From TDN

SIMPLE FPS TUTORIAL for Torque 3D



Back to Part Six: Custom Player

Part SEVEN




Create a Custom GameType:

Boot up the Tutorial level that you made in Part ONE.

The stock data for spawning and equipping the player is spread across a few files, but comes together in "game/scripts/server/gameCore.cs". This spawns a stock player with a rocketlauncher and rocketlauncherAmmo, from a SpawnPoint under a simGroup (folder in the "Scene Tree-> Scene-> MissionGroup") that in stock is called "PlayerDropPoints". This is where your player has just spawned.

Except, we want to use our custom TutorialPlayer, and not the stock one. First switch to camera (CTRL C) and back up a little until you can see the player from behind. Now open up the World Editor (F11) and select the SpawnSphere (the transparent diamond shape at the player's location). In the Object Inspector select "SpawnDatablock" and type into the field TutorialPlayer. The next time you spawn, you'll spawn as our custom Player character, will be able to pick up our custom weapons and ammo, and not be able to climb out of the side of our route through the terrain.

Whilst we're in the editor, select and edit the "PlayerDropPoints" simGroup/folder in the Scene Tree. Change the name to TutorialDropPoints. Hit enter and then save the level.

Finally, select "theLevelInfo" in the Scene Tree. In the inspector, go all the way down to the bottom and in the "Dynamic Fields" section, press the green "+" button. Find the new "dynamic Field" and "defaultValue" variable. Change "dynamic Field" to "gameType" and edit "defaultValue" to "SimpleFPSTutorial".

gameType   --->   SimpleFPSTutorial

Save the level and now quit T3D.

Back to scripting.

Copy and paste "game/scripts/server/gameDM.cs" and rename it "gameSFPST.cs". Open it up and change every reference of "DeathmatchGame" to "SimpleFPSTutorialGame".

Next, set up our custom spawnPoint group by adding "TutorialDropPoints" to both "defaultPlayerSpawnGroup" and "defaultCameraSpawnGroups". Without these the player would spawn at "origin" (0 0 0 + Z offset in spawn.cs).

   $Game::defaultPlayerClass = "Player";
   $Game::defaultPlayerDataBlock = "DefaultPlayerData";
   $Game::defaultPlayerSpawnGroups = "PlayerSpawnPoints PlayerDropPoints TutorialDropPoints";

   $Game::defaultCameraClass = "Camera";
   $Game::defaultCameraDataBlock = "Observer";
   $Game::defaultCameraSpawnGroups = "CameraSpawnPoints PlayerSpawnPoints PlayerDropPoints TutorialDropPoints";



Next comment out or delete the four gameplay parameters - we're not point scoring, or time limited.

   // Set the gameplay parameters
   //%game.duration = 30 * 60;
   //%game.endgameScore = 20;
   //%game.endgamePause = 10;
   //$Game::EndGameScore = 20;


Now go down to "SimpleFPSTutorialGame::preparePlayer" and comment out "parent:preparePlayer(%game, %client);" so that we can override that function in "gameCore.cs". This is where we handle the actual spawning of the player as well as equipping them, and you want to copy the two spawning functions over from "gameCore.cs".

   %playerSpawnPoint = pickPlayerSpawnPoint($Game::DefaultPlayerSpawnGroups);
   %game.spawnPlayer(%client, %playerSpawnPoint);

Comment out or delete EVERYTHING inside of the "checkScore" function because we don't want to cycle the game. Finally change "onDeath" function and copy over much of the version from "gameCore.cs" but comment out %game.checkScore(%sourceClient);" and the "parent::onDeath" link. The whole file should something look like this:

function SimpleFPSTutorialGame::onMissionLoaded(%game)
{
   //echo (%game @"\c4 -> "@ %game.class @" -> SimpleFPSTutorialGame::onMissionLoaded");

   $Server::MissionType = "SimpleFPSTutorial";
   parent::onMissionLoaded(%game);
}

function SimpleFPSTutorialGame::initGameVars(%game)
{
   //echo (%game @"\c4 -> "@ %game.class @" -> SimpleFPSTutorialGame::initGameVars");

   $Game::defaultPlayerClass = "Player";
   $Game::defaultPlayerDataBlock = "DefaultPlayerData";
   $Game::defaultPlayerSpawnGroups = "PlayerSpawnPoints PlayerDropPoints TutorialDropPoints";

   $Game::defaultCameraClass = "Camera";
   $Game::defaultCameraDataBlock = "Observer";
   $Game::defaultCameraSpawnGroups = "CameraSpawnPoints PlayerSpawnPoints PlayerDropPoints TutorialDropPoints";

   // Set the gameplay parameters
   //%game.duration = 30 * 60;
   //%game.endgameScore = 20;
   //%game.endgamePause = 10;
   //$Game::EndGameScore = 20;
}

function SimpleFPSTutorialGame::startGame(%game)
{
   //echo (%game @"\c4 -> "@ %game.class @" -> SimpleFPSTutorialGame::startGame");

   parent::startGame(%game);
}

function SimpleFPSTutorialGame::endGame(%game)
{
   //echo (%game @"\c4 -> "@ %game.class @" -> SimpleFPSTutorialGame::endGame");

   parent::endGame(%game);
   // Inform the client the game is over
   for (%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)
   {
      %cl = ClientGroup.getObject(%clientIndex);
      commandToClient(%cl, 'GameEnd');
   }
}

function SimpleFPSTutorialGame::onGameDurationEnd()
{
   //echo (%game @"\c4 -> "@ %game.class @" -> SimpleFPSTutorialGame::onGameDurationEnd");

   // Inform the client the game is over
   for (%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)
   {
      %cl = ClientGroup.getObject(%clientIndex);
      commandToClient(%cl, 'GameEnd');
   }
   parent::onGameDurationEnd();
}

function SimpleFPSTutorialGame::onClientEnterGame(%game, %client)
{
   //echo (%game @"\c4 -> "@ %game.class @" -> SimpleFPSTutorialGame::onClientEnterGame");

   parent::onClientEnterGame(%game, %client);
}

function SimpleFPSTutorialGame::preparePlayer(%game, %client)
{
   //echo (%game @"\c4 -> "@ %game.class @" -> SimpleFPSTutorialGame::preparePlayer");
   
   %playerSpawnPoint = pickPlayerSpawnPoint($Game::DefaultPlayerSpawnGroups);
   %game.spawnPlayer(%client, %playerSpawnPoint);

   // Starting equipment
   //none!
   
   // Prepare the actual player object for spawning and beginning equipment.
//   parent::preparePlayer(%game, %client);
}

// Determine if this client has reached the $Game::EndGameScore limit,
// and if so then cycle the game.
function SimpleFPSTutorialGame::checkScore(%game, %client)
{
   //echo (%game @"\c4 -> "@ %game.class @" -> SimpleFPSTutorialGame::checkScore");

 //  echo("score: "@ %client.score @"  "@ %game.endgameScore @" "@ $Game::EndGameScore);
 //  if (%client.score >= %game.endgameScore)
 //     cycleGame();
}

function SimpleFPSTutorialGame::onDeath(%game, %client, %sourceObject, %sourceClient, %damageType, %damLoc)
{
   //echo (%game @"\c4 -> "@ %game.class @" -> SimpleFPSTutorialGame::onDeath");

 //  parent::onDeath(%game, %client, %sourceObject, %sourceClient, %damageType, %damLoc);
 //  %game.checkScore(%sourceClient);
 
    %client.RefreshWeaponHud(0, "", "");

   // Clear out the name on the corpse
   %client.player.setShapeName("");

   // Update the numerical Health HUD
   %client.player.updateHealth(%obj);

   // Switch the client over to the death cam and unhook the player object.
   if (isObject(%client.camera) && isObject(%client.player))
   {
      %client.camera.setMode("Corpse", %client.player);
      %client.setControlObject(%client.camera);
   }
   %client.player = 0;
}


Lastly, execute the file in "game/scripts/server/scriptExec.cs".

//custom scripts
exec("./semiauto.cs");
exec("./fullauto.cs");
exec("./gameSFPST.cs"); // Overrides GameCore with Simple FPS Tutorial functionality.


Now, restart T3D and load up the Tutorial level again. You should have spawned at the usual place (though now it has a custom named directory/simgroup), infact the only thing different should be that your player is unarmed (no rocketlauncher!). Now we be a perfect time to test whether or not our new weapon scripts work.

If your character still has a weapon in their hands, click on the Tutorial Player (the Gideon Model), scroll down to the Dynamic Fields section and hit the red "minus" symbol for the default weapons and ammo, the rocket launcher and grenade launcher. This will remove the weapons. Save and restart the level.

Add Custom Items To The Game:

Go into camera mode (CTRL C), move up and out a little, and then open up the World Editor (F11). Aim for a point on the depressed terrain halfway between the player/spawnsphere and the rock/doglegleft. CHeck that you have "object-> drop location-> to Terrain" set. In the "scene tree-> Library-> Scripted-> Weapon" you should see "semiauto" and double click it. A new item should appear. Aim to the side and create a "semiautoAmmo" item. Then at the other side "scene tree-> Library-> Scripted-> Health" and create a "HealthKitPatch". All of these items haev the default "static" variable checked, which means that one used they will automatically respawn after a certain time (find and check item.cs for info on that). Now you have an infinite supply of semiauto weapon, item and healthPacks at the start of your game area.

Player Spawn

Close the World Editor and "Play the Game" (button top left with the "play" symbol, and go back into player control (toggle CTRL C again). You're back as the player and unarmed. Go ahead and walk into the "semiauto weapon", you'll automatically pick it up and because you are currently unarmed, it will automatically mount as the weapon in use. A weapon icon will appear on the HUD/display. Press fire (left mouse button) and you'll hear a dull click. Guns aren't much use without bullets so go and walk into (pick up) the "semiauto Ammo".

The gun automatically loads and your HUD/display should say "Ammo: 20". Go ahead and shoot the ground a little way in front of you (releasing the fire button after pressing it!), and a decal bullethole should appear (as well as dust from our particle impact in our pooled weaponEffects.cs file).

Now, fire again but this time keep the button pressed down and you should see the weapon's reload animation stop halfway with the breach wide open. Let the fire button up and it will complete the loading of the next bullet - and that is the semi-automatic system that we created in the art file at work (state = waitForRelease).

Next test the "fullauto" weapon. Go back into camera mode (CTRL C) and the World Editor (F11) and place a "scene tree-> Library-> Scripted-> Weapon-> fullauto" near the player and then a "scene tree-> Library-> Scripted-> Ammo-> fullautoAmmo" . Close the editor and toggle back to player (CTRL C).

Firstly, run into the "fullauto weapon" item. Now press "3" no the keyboard and you should switch to this weapon. Press fire and hold it down, every second you should here a click. Let go of the fire button and pick up the "fullauto ammo" item and your HUD/display should say "Ammo: 30" with a picture of the new gun. Now press the fire button once to make sure it goes bang. Next hold down the fire button and spray bullets against one the terrain walls until you have no more ammo. Next, press "2" on the keyboard and you should now have selected the "semiauto weapon" to use.

The "fullauto weapon" has fast shooting and more bullets but short range, whilst the "semiauto weapon" has four times the range and more damage but has less bullets and takes much longer to fire a single shot. You now have two very different styles of weapon.

Now that we've tested our custom weapons, go back into the World Editor (F11) and select and then delete (delete key) the "fullauto" item and the "fullautoAmmo" item. Go into camera mode (CTRL C) and find and select the player. In the object inspector it should say "datablock | TutorialPlayer". You'd have guessed this anyway from how we set the "gameType" up and also the fact the stock player cannot pick up our new items. As one final check, go back into player mode (CTRL C) and try to run up the walls of the terrain, you shouldn't be able, and are thus confined to the game area.

Very lastly, let's place a few more objects in the game area. Back into camera mode and from the "Scene-> Library" (you should be used to this by now) find HealthKitPack. Now go and place a HealthKitPack at the deadend of each of the level's 3 side-alleys. Now go to the large Station01 model at the end of the route, and just in front of it add a "HealthKitPack", a "semiautoAmmo", "fullautoAmmo" and a "fullauto" weapon item. Now save and quit.

This might not seem like a lot of objects for the player to get hold of in-game, especially as the second weapon (fullauto) is all the way at the end. However, there is another way of aquiring objects, and that is to loot dead Ai/bots.



Part Eight: Create A Custom AIPlayer