T3D/Tutorials/SimpleFPSTutorial/Part10

From TDN

SIMPLE FPS TUTORIAL for Torque 3D



Back to Part Nine: Simple Ai Combat Scripts

Part Ten




Simple Pathed Bots:


Note: As of T3D 1.1 Final, the first "marker" in any path is "1" (previously it was "0"). So let's update the followPath function in "scripts/server/aiplayer.cs".

function AIPlayer::followPath(%this,%path,%node)
{
//...

   if (%this.path $= %path)
      %this.moveToNode(%this.currentNode);
   else
   {
      %this.path = %path;
      %this.moveToNode(1);//yorks changed to 1 from 0
   }
}


If you're not in our Tutorial level already, boot up Torque3D , load it, and open the World Editor (F11). Before increasing the gaemplay from one lone, static bot - let's clean up "missionGroup". From "Scene Tree-> Library-> Level-> System" create 4 new SimGroups (double click on SimGroup x4). Back in "missionGroup" select them one by one and name them as the following.

level_items
botDropPoints
level_Triggers
botPaths


Now select all the items in "missionGroup" and drag/drop them into "level_Items". Select "botspawn1" and drag/drop that into "botDropPoints", and finally select and drag/drop "trig1" into "level_Triggers". Now "missiongroup" looks a lot tidier and all things of one type/class are grouped together in their own Simgroup/folder.

Currently our bot is a little "static", but stock T3D does with a simple path system which can be set up for a bot to follow a path of markers (check out "AiPlayer.cs"). We're going to use our custom "spawnBot" function and have a new bot spawn on a path and then follow that path.

From "Library-> Level-> Level" create a new path and name it "botPath1" and in the Inspector find "isLooping" and uncheck it (this is just visualization in the editor). Now in Camera Mode, fly over to our first side-alley in the terrain. Check that "Object->Drop Location" is "to Terrain". Before the "HealthKitPatch" at the end, add a "Library-> Level-> Path Node". NOTE: In the "missionGroup" this will become a "Marker". At the entrance to side-alley add another. In "missionGroup" move the "markers" if they are not in the middle. It's important that the "markers" can see one another and that their line-of-sight (LOS) isn't blocked by the terrain walls which a bot cannot run over. Select the first "marker" and name it "path1start". Now select both "markers" and drag/drop them into the path we named "botPath1". Now is a good time to check the chronology of the "marker's" ID in the Object Inspector. The path will run from the lowest ID numbered (oldest) "marker" to the newest, so you don't want them the wrong way around. If "path1start" has a higher ID number than the other marker, clear it's name and rename the second "marker" as "path1start". You can also change the sequence numbers of the "marker's" themselves in the Object Inspector - but we need to make certain that the named "markers" are the first ones for our bot's spawning. The order at which they are displayed in the "missionGroup" under their path is of no relevance.

First Bot Path

Now drag/drop "botPath1" into "botPaths" to keep "missionGroup" tidy.

Now make a new trigger from "Library-> Level-> Level-> Trigger", call it "trig2" and from the "data block" drop-down menu select "TutorialTrigger". Set it's "scale" to "10 30 5" and position it so it blocks the route before the first turn right. Make sure that you can see the first side-alley entrance from the trigger's location. Now drag and drop "trig2" into the "level_Triggers" simGroup/folder. With "trig2" selected, in the Object Inspector edit "enterCommand". We'll use a similar format to last time, but this time call the new bot "pathbot1" and the spawnpoint will be the "marker" called "path1start". This time we give the "botSpawn" function a temporary variable "%newBot", so that after the bot has spawned we can make it follow the path. The stock "followPath" function uses the address of the path within "missionGroup". The final variable is that of a which "marker" on the path the bot should run to. If it's set to a number higher than than number of "markers" then the bot will simply run all along the path to the end. If it is set to "-1", the bot will loop around the path, never stopping. We want our bots to run to the end of their paths, and as we will not be using paths with many "markers" set it to "9". Though, it could just be set to "2" for this particular path.

%checkclass = %obj.getClassName();
if(%checkclass $= "Player")
   if(!isObject(pathbot1))
   {
      %newBot = aiplayer::spawnBot(pathbot1, path1start, semiauto);
      %newBot.followPath("MissionGroup/botPaths/botPath1", 9);
   }


Bot Path Trigger

Save everything, close the World Editor, and return to the player (CTRL C). Now run into the first trigger, pick up the weapon and ammo and kill "bot1" around the corner. Now walk into the second trigger, and make sure that you can see the entrance to the side-alley. Now wait, after a few seconds "pathbot1" should run into view and start shooting at you. Kill him, and then go and pick up his ammo (and healthKitPatch if you got hurt).

Toggle back to the camera, and open up the World Editor (F11). We're going to make two more paths. Follow the route round from the second right turn, past the rock set to one side of the next straight halfway down, and then the next left turn (second left overall from the start). Just round this corner create a new "Library-> Level-> Level-> Path" and call it "botpath2" and uncheck it's "isLooping" variable. Add a "Path Node" (now called a "marker" in missiongroup). Call this "path2start". Next make a second "Path Node"/"marker" and place it in the far corner of the turn (2nd left, before the second side-alley with the rock outside it). Now select both "markers" in the "missionGroup" and drag/drop them into the "botPath2" simGroup/folder. Then select "botPath2" and drag/drop that into "botPaths" to tidy up.

Now make another "Library-> Level-> Level-> Path" and call it "botpath3" and uncheck it's "isLooping" variable. Add a "Path Node" parallel with "path2start". Call this "path3start". Create another "Path Node" near the inner part of the corner and a third down the straight towards where our player will be coming from, just next to the rock. Make certain that the second "Path Node"/"marker" can see both this one and "path3start". Select these 3 "markers" in "missionGroup" and drag/drop them into "botPaths". Remember to check that the named "markers" are the lowest ID numbered in their path, and that "botPath3" has all of it's "markers" in the correct order without any doubling back on itself. If you select both "botPath2" and "botPath3", it should hopefully look something like this:

Two Bot Paths

If all is good, save and quit.

We are going to make a new trigger, but this time we are going to script the data directly into the "onEnterTrigger" function of a trigger datablock. Open up the file "TutorialTriggers.cs" and copy everything, pasting it just below what is already there. Now we have a duplicate of all of our "TutorialTrigger" datablocks and functions. Rename all of these copies "NewCustomTrigger" (don't delete or edit the ORIGINAL "TutorialTrigger" references!). Now we'll write two similar "spawnBot" functions as we did for "pathbot1". We shall also give the bot who is due to run down the longer "path3" the "fullauto" weapon. By the time he gets to his final "marker" the player should be in range at the corner. When you're done, save "TutorialTriggers.cs" and it should look like this.

datablock TriggerData(TutorialTrigger)
{
   tickPeriodMS = 1000;
};

function TutorialTrigger::onEnterTrigger(%this,%trigger,%obj)
{

}

function TutorialTrigger::onLeaveTrigger(%this,%trigger,%obj)
{

}

function TutorialTrigger::onTickTrigger(%this,%trigger)
{

}

datablock TriggerData(NewCustomTrigger)
{
   tickPeriodMS = 1000;
};

function NewCustomTrigger::onEnterTrigger(%this,%trigger,%obj)
{
	%checkclass = %obj.getClassName();
	
	if(%checkclass $= "Player")
	{
		if(!isObject(pathbot2))
		{
			%newBot2 = aiplayer::spawnBot(pathbot2, path2start, semiauto);
			%newBot2.followPath("MissionGroup/botPaths/botPath2", 1);
		}
		
		if(!isObject(pathbot3))
		{
			%newBot3 = aiplayer::spawnBot(pathbot3, path3start, fullauto);
			%newBot3.followPath("MissionGroup/botPaths/botPath3", 3);
		}
		
	}
}

function NewCustomTrigger::onLeaveTrigger(%this,%trigger,%obj)
{

}

function NewCustomTrigger::onTickTrigger(%this,%trigger)
{

}

Any trigger in-game which is assigned the "NewCustomTrigger" datablock will attempt to use these functions. This might not be terribly useful in the circumstances in which we are using it, but it could be used to create a generic "%obj.kill();" datablock trigger that can be added multiple times without having to type the same functioning in for every single instance of it.

Datablocks load at "runtime" of a level, so be aware that you can't just type new ones up in an external text editor whilst T3D is running and expect them to work (though you could manually exec a file from the console - and there is a Datablock Editor inside T3D but we are not covering it's use here).

Restart Torque and load your level. Switch to camera mode (CTRL C) and World Editor(F11). Create a new trigger (you should know how to do this by now) and name it "trig3", from the drop down menu select our new datablock "NewCustomTrigger". Place "trig3" between the first side-alley and the next (second) right turn, and scale it so that the Player will have to run into it (around 30 10 5). Drop this new trigger into the appropriate simGroup/folder in "missionGroup".

Double Path Trigger

Now save, return to "play game" and player control (CTRL C). Now fight your way past the first 2 enemies and run into the new trigger. Look around the corner and you should see 2 bots running down their paths. One bot will hold back at the end of the straight to provide cover, whilst the bot with the shorter ranged "fullauto" weapon will rush forwards so that he can be in range to shoot at the player.



Part Eleven: GamePlay, Challenge, Variation and Set-Pieces