Bot spawner object
by Jared Barger · 10/14/2004 (12:59 pm) · 11 comments
A short forward
I'm still very new to Torque and I'm just getting the hang of how a lot of it "flows". I already know of several points in
the following code that could, and should, be updated. That's one of the primary reasons I wanted to submit this in the first
place. It seems everyday I come across something new that could make my work better and easier to accomplish so I was hoping
for feedback on what could be improved and at the same time share something that could be useful to others.
One thing I have found a touch frustrating when trying to tackle all this mountain of knowledge about Torque is that a large
percentage of the tutorials provided are pretty much "drop in" tutorials. Cut and paste and it works. This is great if you're
just looking to add something to your game without having to take the time to do it yourself. It's not always the best way to
go if you want to learn how it works, and therefore expand upon it, though. To that ends I've tried to explain this and build
it up in pieces. That being said it will, no doubt, be rather long by the time I'm finished so I will be splitting it up into
sections as follows.
1. Building the basic spawner object
2. Randomize the spawner
Building the basic spawner object
The idea here is to get a physical object into the editor that we can drop into a level and use to spawn our bots.
GenericSpawner.cs
Alright, so I said it was going to be basic...
All this does is create a bot derived from PlayerShape (imo why not derive any mobile from PlayerShape) and create an object
that inserts that into your world.
Next we need to setup some generic support functions for our spawners.
SpawnFuncs.cs
Now all we need to do is execute SpawnFuncs.cs during the server startup. This will be ~/server/game.cs, ~/server/scripts/
game.cs, or (if you're using a setup from Ken's book, which if you don't have it yet then you should!) ~/server/server.cs depending on which "base" app
you're building off of. The parent and children variables are there because I wasn't sure if I would want to add respawning
for any reason. They are, for now, excess baggage though and could be removed if you didn't want to do any respawning. If you
do you would want to make sure to add some sort of KillSpawn() function at the beginning of Spawn();
Randomize the spawner
At this point the spawner pretty much sucks.It does get a bot into the world...but that's pretty much it. So lets spice
things up with a lil randomization.
First we're going to add some variables to our spawner object (GenericSpawner) in GenericSpawner.cs
Ok, we've set the groundwork to have the spawner kick out a random number of bots and for it to potentially use more than one
datablock. Now let's update the bot datablock(s) in the same file.
The variable names are pretty self explanatory imo so moving right along to SpawnFuncs.cs. First we need to make some changes
to the spawn function.
ALrighty. Now we need to add that nudgespawn function. I haven't been able to get this perfect but it's way better than
nothing. If anyone knows of a way to call this recursively until each bot is on the ground please pop that info up here.
Once again in SpawnFuncs.cs
These two little fuctions here have scooted our spawns around a bit. Assuming we aren't spawning a lot from one spawn point
then they're all doing alright and standing on the ground now. The other function we called was GetFullNPCName() so we'll
look at that next.
IMO load times are a trivial matter unless you're talking about a LOT of time (into the minutes) as most gamers are much more
concerned with how the game performs while they're actually using it rather than how long it takes to load a mission/scene. I
say that because this quick and dirty name generator has a large amount of string compares assuming you go with exactly how I
have coded it. You could change some datablock values to be integers rather than strings and that would speed things up some,
but make the code much less readable. It's your call. Also keep in mind that gender is only one of many naming options that
would be present in a full application. I used it here because it's the most obvious, but in reality a more verbose name gen
would have a lot more options (and thus the string compares) than this one.
Now our spawners have a random amount of bots to spawn that are all assigned a random name and a random location around the
spawner. Adding a GuiShapeNameHud object to the play hud will now show your random names over the heads of the mobs. Also, if
you're short on naming ideas google "baby names" and you'll hit too many sites to count that have thousands of names listed.
I had intended to add more to this but it's getting rather long and it's getting late =P
Best of luck,
-Zann
I'm still very new to Torque and I'm just getting the hang of how a lot of it "flows". I already know of several points in
the following code that could, and should, be updated. That's one of the primary reasons I wanted to submit this in the first
place. It seems everyday I come across something new that could make my work better and easier to accomplish so I was hoping
for feedback on what could be improved and at the same time share something that could be useful to others.
One thing I have found a touch frustrating when trying to tackle all this mountain of knowledge about Torque is that a large
percentage of the tutorials provided are pretty much "drop in" tutorials. Cut and paste and it works. This is great if you're
just looking to add something to your game without having to take the time to do it yourself. It's not always the best way to
go if you want to learn how it works, and therefore expand upon it, though. To that ends I've tried to explain this and build
it up in pieces. That being said it will, no doubt, be rather long by the time I'm finished so I will be splitting it up into
sections as follows.
1. Building the basic spawner object
2. Randomize the spawner
Building the basic spawner object
The idea here is to get a physical object into the editor that we can drop into a level and use to spawn our bots.
GenericSpawner.cs
// GenericSpawner object and bot
datablock PlayerData(GenericBotShape: PlayerShape){
shapeFile = "~/data/shapes/generic.dts"; // Whatever you want here
category = "bot";
aiPlayer = true;
};//GenericBotShape
datablock StaticShapeData(GenericSpawner){
shapeFile = "~/data/shapes/markers/octahedron.dts";
category = "spawner";
botDataBlock = GenericBotShape; // Point to what you want to spawn
};//GenericSpawner
function GenericSpawner::OnAdd(%this, %obj){
AddSpawner(%this, %obj);
}//GenericSpawner::OnAddAlright, so I said it was going to be basic...
All this does is create a bot derived from PlayerShape (imo why not derive any mobile from PlayerShape) and create an object
that inserts that into your world.
Next we need to setup some generic support functions for our spawners.
SpawnFuncs.cs
// Spawner support functionality
// Execute our spawner objects here
exec("./GenericSpawner.cs");
$SpawnList[0] = 0; // To hold onto all our spawners. Sub 0 will equal the count.
// Add Spawner ----------------------------------------------
function AddSpawner(%this, %obj){
$SpawnList[0]++; // Inc spawn count
$SpawnList[$SpawnList[0]] = %obj; // Point to spawner
%obj.setHidden(true); // Hide the spawner for now
}//AddSpawner
// View Spawners --------------------------------------------
function ViewSpawners(%bool){ // Hide/show all the spawner objects
if(%bool) Echo("Making all spawners visible");
else Echo("Hiding all spawners");
for(%i = 1; %i <= $SpawnList[0]; %i++){
$SpawnList[%i].setHidden(!%bool);
}//for
}//ViewSpawners
// Spawn ----------------------------------------------------
function Spawn(%spawner){
// Get the datablock
%dblock = %spawner.getDataBlock().botDataBlock;
// Build the bot
%bot = new AIPlayer(){
datablock = %dblock;
parent = %spawner; // Tie it to its parent
};//new AIPlayer
// Add it to be deleted
MissionCleanup.Add(%bot);
// Put it where the spawner is
%bot.setTransform(%spawner.getTransform());
// Tie spanwer to the child
%spawner.children[0]++;
%spawner.children[%spawner.children[0]] = %bot;
Echo("Spawned: " @ %bot @ " at " @ %bot.getPosition() @ " from " @ %spawner);
}//Spawn
// Spawn all -----------------------------------------------
function SpawnAll(){
Echo("*** Performing global spawn ***");
for(%i = 1; %i <= $SpawnList[0]; %i++){
Spawn($SpawnList[%i]);
}//for
Echo("*** Global spawn of " @ %i @ " bots complete ***");
}//SpawnAllNow all we need to do is execute SpawnFuncs.cs during the server startup. This will be ~/server/game.cs, ~/server/scripts/
game.cs, or (if you're using a setup from Ken's book, which if you don't have it yet then you should!) ~/server/server.cs depending on which "base" app
you're building off of. The parent and children variables are there because I wasn't sure if I would want to add respawning
for any reason. They are, for now, excess baggage though and could be removed if you didn't want to do any respawning. If you
do you would want to make sure to add some sort of KillSpawn() function at the beginning of Spawn();
Randomize the spawner
At this point the spawner pretty much sucks.It does get a bot into the world...but that's pretty much it. So lets spice
things up with a lil randomization.
First we're going to add some variables to our spawner object (GenericSpawner) in GenericSpawner.cs
datablock StaticShapeData(GenericSpawner){
shapeFile = "~/data/shapes/markers/octahedron.dts";
category = "spawner";
spawnMin = 1; // Min to spawn
spawnMax = 10; // Max to spawn
botDataBlock[0] = 2;
botDataBlock[1] = GenericBotShape;
botDataBlock[2] = GenericBotShape2;
};//GenericSpawnerOk, we've set the groundwork to have the spawner kick out a random number of bots and for it to potentially use more than one
datablock. Now let's update the bot datablock(s) in the same file.
datablock PlayerData(GenericBotShape: PlayerShape){
shapeFile = "~/data/shapes/generic.dts"; // Whatever you want here
category = "bot";
aiPlayer = true;
gender = "male";
defaultName = "Error";
randomName = true;
};//GenericBotShape
datablock PlayerData(GenericBotShape2: GenericBotShape){
shapeFile = "~/data/shapes/generic_female.dts";
gender = "female";
};//GenericBotShape2The variable names are pretty self explanatory imo so moving right along to SpawnFuncs.cs. First we need to make some changes
to the spawn function.
function Spawn(%spawner){
// Figure out how many we want to spawn
%count = GetRandom(%spawner.getDataBlock().spawnMin, %spawner.getDataBlock().spawnMax);
if(%count == 0) return;
for(%i = 1; %i <= %count; %i++){
// Pick a datablock to use for the bot
%block = GetRandom(1, %spawner.getDataBlock().botDataBlock[0]);
%dblock = %spawner.getDataBlock().botDataBlock[%block];
%bot = new AIPlayer(){
datablock = %dblock;
parent = %spawner;
name = %dblock.defaultName;
};//new AIPlayer
// Get a random name if necessary
if(%dblock.randomName == true){
%tempName = GetFullNPCName(%dblock.gender);
%bot.SetShapeName(%tempName);
}//if
// Add it to be deleted
MissionCleanup.Add(%bot);
// Set transform
%bot.setTransform(NudgeSpawn(%spawner.getTransform())); // Nudgespawn will keep them from standing
// on top of each other (for the most part)
}//for
}//SpawnALrighty. Now we need to add that nudgespawn function. I haven't been able to get this perfect but it's way better than
nothing. If anyone knows of a way to call this recursively until each bot is on the ground please pop that info up here.
Once again in SpawnFuncs.cs
// Nudge Spawn -----------------------------------------------------------------
function NudgeSpawn(%origTransform){
// X & Y are to move the position
%wordx = Nudge(GetWord(%origTransform, 0));
%wordy = Nudge(GetWord(%origTransform, 1));
%origTransform = SetWord(%origTransform, 0, %wordx);
%origTransform = SetWord(%origTransform, 1, %wordy);
return %origTransform;
}//NudgeSpawn
function Nudge(){
%high = 10; // Min/Max value we can move the spawn in any direction
%low = -10;
%val = GetRandom(%low, %high);
return %val;
}//NudgeThese two little fuctions here have scooted our spawns around a bit. Assuming we aren't spawning a lot from one spawn point
then they're all doing alright and standing on the ground now. The other function we called was GetFullNPCName() so we'll
look at that next.
IMO load times are a trivial matter unless you're talking about a LOT of time (into the minutes) as most gamers are much more
concerned with how the game performs while they're actually using it rather than how long it takes to load a mission/scene. I
say that because this quick and dirty name generator has a large amount of string compares assuming you go with exactly how I
have coded it. You could change some datablock values to be integers rather than strings and that would speed things up some,
but make the code much less readable. It's your call. Also keep in mind that gender is only one of many naming options that
would be present in a full application. I used it here because it's the most obvious, but in reality a more verbose name gen
would have a lot more options (and thus the string compares) than this one.
function GetFullNPCName(%gender){
%firstName = GetFirstName(%gender);
%lastName = GetLastName();
return %firstName SPC %lastName;
}//GetFullNPCName
function GetFirstName(%gender){
if(strcmp(%gender, "male") == 0) return GetMaleFirstName();
return "Error: Unknown gender";
}//GetFirstName
function GetMaleFirstName(){
%names[0] = 2; // As before, sub zero has the string count in it
%names[1] = "Joe";
%names[2] = "Bob";
%rnd = GetRandom(1, %names[0]);
return %names[%rnd];
}//GetMaleFirstName
function GetLastName(){
%names[0] = 2; // Same as the first name function, but not gender specific
%names[1] = "Johnson";
%names[2] = "Smith";
%rnd = GetRandom(1, %names[0]);
return %names[%rnd];
}//GetLastNameNow our spawners have a random amount of bots to spawn that are all assigned a random name and a random location around the
spawner. Adding a GuiShapeNameHud object to the play hud will now show your random names over the heads of the mobs. Also, if
you're short on naming ideas google "baby names" and you'll hit too many sites to count that have thousands of names listed.
I had intended to add more to this but it's getting rather long and it's getting late =P
Best of luck,
-Zann
#2
I was under the impression that i could spawn a bot with a click of an editor button.
I get nothing.
maybe i did somthing wrong
10/26/2004 (5:20 am)
the name of the resource sounds cool, so i put it in, but i guess i dont understand, what its for, does the object that gets spawn on the map take the place of "spawning on a path" ?I was under the impression that i could spawn a bot with a click of an editor button.
I get nothing.
maybe i did somthing wrong
#3
10/27/2004 (12:16 pm)
Are you calling the SpawnAll function or calling spawn passing the ID of a spawner?
#4
The code you provided is great except for one major problem.
I hope the problem is self inflicted, so that I can fix it.
The Nudge Spawn and Nudge functions do not seem to append the random position onto the position of the spawn object.
The spawner creates a perfectly spread out spawn... but the position of Nudge is relative to 0,0 and not to the position of the GenericSpawner object.
Here is the code I have put in, it should look familiar.
Any help is much appreciated.
I call it like this:
// Set transform
%bot.setTransform(NudgeSpawn(%spawner.getTransform()));
// Nudge Spawn -----------------------------------------------------------------
function NudgeSpawn(%origTransform){
// X & Y are to move the position
%wordx = Nudge(GetWord(%origTransform, 0));
%wordy = Nudge(GetWord(%origTransform, 1));
%origTransform = SetWord(%origTransform, 0, %wordx);
%origTransform = SetWord(%origTransform, 1, %wordy);
return %origTransform;
}//NudgeSpawn
function Nudge(){
%high = 10; // Min/Max value we can move the spawn in any direction
%low = -10;
%val = GetRandom(%low, %high);
echo(%val);
return %val;
}//Nudge
11/24/2004 (1:12 am)
Hey Jared,The code you provided is great except for one major problem.
I hope the problem is self inflicted, so that I can fix it.
The Nudge Spawn and Nudge functions do not seem to append the random position onto the position of the spawn object.
The spawner creates a perfectly spread out spawn... but the position of Nudge is relative to 0,0 and not to the position of the GenericSpawner object.
Here is the code I have put in, it should look familiar.
Any help is much appreciated.
I call it like this:
// Set transform
%bot.setTransform(NudgeSpawn(%spawner.getTransform()));
// Nudge Spawn -----------------------------------------------------------------
function NudgeSpawn(%origTransform){
// X & Y are to move the position
%wordx = Nudge(GetWord(%origTransform, 0));
%wordy = Nudge(GetWord(%origTransform, 1));
%origTransform = SetWord(%origTransform, 0, %wordx);
%origTransform = SetWord(%origTransform, 1, %wordy);
return %origTransform;
}//NudgeSpawn
function Nudge(){
%high = 10; // Min/Max value we can move the spawn in any direction
%low = -10;
%val = GetRandom(%low, %high);
echo(%val);
return %val;
}//Nudge
#5
It seems this wonderful code had an error, and I finally get to help by correcting it.
Nudge was not receiving a value and the value was not appended.
Here's my fix for Jared's awsome spawners.
Just replace the Nudge function with the one below.
function Nudge(%val){
%high = 10; // Min/Max value we can move the spawn in any direction
%low = -10;
%val = %val + GetRandom(%low, %high);
echo(%val);
return %val;
}//Nudge
11/24/2004 (1:27 am)
Ok, I fixed it.It seems this wonderful code had an error, and I finally get to help by correcting it.
Nudge was not receiving a value and the value was not appended.
Here's my fix for Jared's awsome spawners.
Just replace the Nudge function with the one below.
function Nudge(%val){
%high = 10; // Min/Max value we can move the spawn in any direction
%low = -10;
%val = %val + GetRandom(%low, %high);
echo(%val);
return %val;
}//Nudge
#6
I am new to the torque and am having a bit of trouble with this. I can't seem to get a player to spawn. All I get is an empty Generis Spawner object. I was wondering if someone coudl help me with this.
Thanks,
Drove171
11/30/2004 (2:36 pm)
Hi, I am new to the torque and am having a bit of trouble with this. I can't seem to get a player to spawn. All I get is an empty Generis Spawner object. I was wondering if someone coudl help me with this.
Thanks,
Drove171
#7
Try SpawnAll(); in the console after you have placed a spawner.
Do you have AI allready?
12/12/2004 (12:31 am)
@Drove171Try SpawnAll(); in the console after you have placed a spawner.
Do you have AI allready?
#8
01/25/2006 (5:06 pm)
Excellent resource, I had almost no problems implementing it. However, I was wondering how I could get the bots to follow a path after they have been spawned. I'm currently using the followPath function from the Bot Path-Finding tutorial by Kevin Harris, but the bots will only move from the point where they are spawned to the first node in the path (out of three total). Anyone have any ideas?
#9
You must have the RPGDialog resource installed.
Add this to the end of ~/server/scripts/RPGDialog.cs
Drop a bot spawner object and note the object number in the editor (like 4147).
Edit an NPC answer and add the Spawn() function to the actions list like: Spawn(4147)
Save the NPC script (in game).
When you talk to the NPC and get that answer the bot spawner object spawns bots.
Use trade/reward system for mission items, etc.
Instant missions, enjoy.
01/30/2006 (3:45 am)
Here's a fun piece of code.You must have the RPGDialog resource installed.
Add this to the end of ~/server/scripts/RPGDialog.cs
//<ActionList>Spawn(spawner)
function Spawn(%spawner,%client,%sender,%npcFile)
{
Spawn(%spawner);
CloseDialog(%client,%sender,%npcFile);
}Drop a bot spawner object and note the object number in the editor (like 4147).
Edit an NPC answer and add the Spawn() function to the actions list like: Spawn(4147)
Save the NPC script (in game).
When you talk to the NPC and get that answer the bot spawner object spawns bots.
Use trade/reward system for mission items, etc.
Instant missions, enjoy.
#10
edit::
Ok so i fixed the problem, it was rather simple but I suck at scripting so it took some time........
right bellow the ::onadd function in GenericSpawner.cs I put this:
function PlayerData::create(%block)
{
%obj = new AiPlayer() {
dataBlock = LightMaleHumanArmor; // datablock for player object
};
return(%obj);
}
That did the trick, btw nice tutorial.......keep up the good work Community!!
04/25/2007 (7:49 pm)
I'm having a hard time putting this into TGEA/TSE. I keep getting this error in the console: unable to find playerdata::create Any ideas?? Thanksedit::
Ok so i fixed the problem, it was rather simple but I suck at scripting so it took some time........
right bellow the ::onadd function in GenericSpawner.cs I put this:
function PlayerData::create(%block)
{
%obj = new AiPlayer() {
dataBlock = LightMaleHumanArmor; // datablock for player object
};
return(%obj);
}
That did the trick, btw nice tutorial.......keep up the good work Community!!
#11
12/09/2007 (7:37 am)
I put this in, but when I called the SpawnAll(); function in the concol it told me "input (0): unable to find function SpawnAll". And so no bots. 
Ari Rule
You have written most of the features I was about to start on.
This is why I love the GGC.
Thanks so much!
The code I'm working with is not very standard, but I'll see what I can post back.
Ari Rule (BrokeAss Games)