Adding simple AI players or NPCs
by Dreamer · in RTS Starter Kit · 11/10/2005 (2:43 am) · 14 replies
I finally managed to implement a really simple AI system for RTS entirely in script.
The best part is AI based players can use all the same commands as you would use for live players.
Here it is.
In server/scripts/core/gameConnection.cs add the following code,
Now replace the RTSConnection::createPlayer function with the following
Finally at the bottom of RTSConnection::onClientEnterGame add
Thats it thats all there is, you can of course add a for loop into the MakeAI function to make more AI Players.
The best part is AI based players can use all the same commands as you would use for live players.
Here it is.
In server/scripts/core/gameConnection.cs add the following code,
function MakeAI(){
$AIManager = new RTSConnection() {};
$AIManager.units = new SimSet();
$AIManager.buildings = new SimSet();
%clientIndex = $AIManager.getClientIndex();
$AIManager.setTeam(%clientIndex);
%loc = getRandomLocation(); //You will have to script this function for yourself
$AIManager.createPlayer(%loc, 2,1);
MissionCleanup.add($AIManager);
}Now replace the RTSConnection::createPlayer function with the following
function RTSConnection::createPlayer(%this, %spawnPoint, %index,%ai)
{
switch(%index % 3)
{
case 0:
%data = botBlock;
case 1:
%data = riflemanBlock;
case 2:
%data = shockerBlock;
}
%player = new RTSUnit()
{
scale = "1 1 1";
dataBlock = %data;
shapeFile = "~/data/shapes/player/player.dts";
path = "";
};
MissionCleanup.add(%player);
%player.isAI =%ai;
%player.setControllingConnection(%this);
%player.setSkinName( getWord($Pref::Server::TeamInfo[%this.getTeam()], 3) );
%player.setTeam(%this.getTeam());
%player.setTransform(%spawnPoint);
%player.client = %this;
%player.stats["Kills"] = (getRandom() * 5) % 5;
%player.stats["Damage Delt"] = (getRandom() * 1000) % 1000;
// Add the unit to the group of units
%this.units.add(%player);
}Finally at the bottom of RTSConnection::onClientEnterGame add
if(!isObject($AIManager)){
MakeAI();
}Thats it thats all there is, you can of course add a for loop into the MakeAI function to make more AI Players.
#2
as an aside, I'm trying to implement neutral creeps into the game similar to warcraft3. dumb AI monsters who sit in one spot until the player comes within a certain radius and attack the player. the ideal way for level designers to go about adding these guys into the maps would be if they could place them so I'm suspecting that this will require some codework. any good starting points? or has anyone done this yet?
thanks,
dan
01/05/2006 (7:27 pm)
So, who calls makeAI()? as an aside, I'm trying to implement neutral creeps into the game similar to warcraft3. dumb AI monsters who sit in one spot until the player comes within a certain radius and attack the player. the ideal way for level designers to go about adding these guys into the maps would be if they could place them so I'm suspecting that this will require some codework. any good starting points? or has anyone done this yet?
thanks,
dan
#3
The way to make monsters who sit in one place is to first determine where you want them to sit.
Spawn them there.
Then do a radius search (or a line of sight search if you preffer that instead), about once a second to see if the player is within range.
01/05/2006 (9:29 pm)
You call MakeAI wherever you choose to in your game.The way to make monsters who sit in one place is to first determine where you want them to sit.
Spawn them there.
Then do a radius search (or a line of sight search if you preffer that instead), about once a second to see if the player is within range.
#4
I added this code in and although I see that the unit is being created, I don't see it drawn. I'm tracking it down now to see what the problem is. I'm sure my client doesn't think it exists or something.
01/05/2006 (10:46 pm)
I see that you were calling it for example when your client enters the game which is all well and good, but placing these AIs in the level via the level editor would be much nicer. I remember the standard torque SDK having player start points, which I should perhaps take a look at. I added this code in and although I see that the unit is being created, I don't see it drawn. I'm tracking it down now to see what the problem is. I'm sure my client doesn't think it exists or something.
#5
01/05/2006 (11:29 pm)
Oh, for some reason, my vision isn't getting updated from my .cs files and it's using the default value of 20 from the constructor. all other vars are getting updated properly. grr.
#6
void RTSUnitData::initPersistFields()
{
...
addField("vision", TypeF32, Offset(mVision, RTSUnitData));
...
}
01/05/2006 (11:46 pm)
Just as a warning, the code drop that I downloaded 2 weeks ago is missing the line for vision. thus, my unit's vision was getting overwritten with the default value.void RTSUnitData::initPersistFields()
{
...
addField("vision", TypeF32, Offset(mVision, RTSUnitData));
...
}
#7
I generally preffer setting down a few static objects in the game, and then looking at their location in the .mis file. Then use those in a simgroup to create a series of spawn points.
01/06/2006 (12:01 am)
You could do player spawn points in the level editor, or you could hardcode them by hand.I generally preffer setting down a few static objects in the game, and then looking at their location in the .mis file. Then use those in a simgroup to create a series of spawn points.
#8
01/06/2006 (12:55 am)
*deleted OT*
#9
01/06/2006 (1:29 am)
It happens, anyways lets clean the discussion up, I'll post this and delete my previous posts up to this point, that way no one knows how silly we look.
#10
And on a similar note. I'm trying to get a unit to attack if an enemy unit comes within a certain radius. Now my question is where can I put this code? You make it sound "trivial", and I hope it is, but what am I missing? Basicly I want my units to be "constantly" looking around within their vision radius, and if they see an enemy unit, attack it.
I think I how to have them look around and attack if they see an enemy. But my question is where can I put this code? I basicly need the units to look for an enemy every second or couple of seconds. How can I do this? Any ideas?
Thanks in advance,
-Nick
04/11/2006 (10:38 pm)
Ok, I'm "new" to Torque and the RTS-SK in general. I've been working with it for a couple months now and now I'm trying to get a basic AI in my game. Now please forgive my noobness here, but what does this do exactly?And on a similar note. I'm trying to get a unit to attack if an enemy unit comes within a certain radius. Now my question is where can I put this code? You make it sound "trivial", and I hope it is, but what am I missing? Basicly I want my units to be "constantly" looking around within their vision radius, and if they see an enemy unit, attack it.
I think I how to have them look around and attack if they see an enemy. But my question is where can I put this code? I basicly need the units to look for an enemy every second or couple of seconds. How can I do this? Any ideas?
Thanks in advance,
-Nick
#11
RTS ships with no such seperation of functionality.
In RTSKit you the player control a group of AIPlayer objects called "units" or "bots" if you will.
However there is no computer controlled player to play against.
What this does is creates an extremely primitive AIManager which controls it's own team of bots.
This resource here gets them to spawn, and adds them to the AIManager's team.
I have a couple of additional resources posted in this same forum you can add to this which gives the primitive AIManager a little more "smarts", and will cause the bots to get pretty violent. Look for "AI Total Warfare" mod, to accomplish what you are talking about.
Basically all that one does is wander aimlessly around the zone, when it reaches it's destination it does a radius search, and starts attacking anything within x units of the bot. When a bot comes under fire it "yells" for help and any nearby units come to it's aid.
Regards,
Dreamer
04/11/2006 (11:09 pm)
Stock TGE ships with a computer controlled called an AIPlayer and a client controlled player called simply Player.RTS ships with no such seperation of functionality.
In RTSKit you the player control a group of AIPlayer objects called "units" or "bots" if you will.
However there is no computer controlled player to play against.
What this does is creates an extremely primitive AIManager which controls it's own team of bots.
This resource here gets them to spawn, and adds them to the AIManager's team.
I have a couple of additional resources posted in this same forum you can add to this which gives the primitive AIManager a little more "smarts", and will cause the bots to get pretty violent. Look for "AI Total Warfare" mod, to accomplish what you are talking about.
Basically all that one does is wander aimlessly around the zone, when it reaches it's destination it does a radius search, and starts attacking anything within x units of the bot. When a bot comes under fire it "yells" for help and any nearby units come to it's aid.
Regards,
Dreamer
#12
This checkAIAttack() method would probably want to either do a container search for closeby enemy objects, or even better integrate with the VisManager and iterate over the units there to see if any are nearby. This would give you at least basic "hey, I see an enemy--attack!" capability, but be forwarned:100's of units will hit you pretty strongly with performance issues. In my personal tests, using the Torque profiling system, I found that once you get about roughly 200 units on screen, the majority of your slowdown is not in fact rendering, but simply RTSUnit::processTick() for all of those units--it does a lot of stuff, and it starts to add up.
04/11/2006 (11:09 pm)
One location (probably not the best performance wise to be honest, but it's a start) is simply in the RTSUnit::processTick() function. Each unit is already being polled for things like movement, animation, attacking, etc., and you could write a basic RTSUnit::checkAIAttack() method which would be called from ::processTick().This checkAIAttack() method would probably want to either do a container search for closeby enemy objects, or even better integrate with the VisManager and iterate over the units there to see if any are nearby. This would give you at least basic "hey, I see an enemy--attack!" capability, but be forwarned:100's of units will hit you pretty strongly with performance issues. In my personal tests, using the Torque profiling system, I found that once you get about roughly 200 units on screen, the majority of your slowdown is not in fact rendering, but simply RTSUnit::processTick() for all of those units--it does a lot of stuff, and it starts to add up.
#13
Then I pick a time in seconds between min & max, do a radius search, look for anything to attack and then reschedule the same command.
This way you aren't polling the radius every single tick.
I have successfully ran around a zone with 250+ AIPlayers all with Gomer Pyle levels of awareness (5 10 50), and not noticed a whole lot of difference.
But yeah processing ticks on AIPlayers or anything in which you are going to have 100's of spawns of is going to take some horsepower.
04/11/2006 (11:17 pm)
In my awareness mod for TGE 1.4 which was made from the Tit for Tat or AI TotalWarfare mod, I have a min and max value as well as a radius.Then I pick a time in seconds between min & max, do a radius search, look for anything to attack and then reschedule the same command.
This way you aren't polling the radius every single tick.
I have successfully ran around a zone with 250+ AIPlayers all with Gomer Pyle levels of awareness (5 10 50), and not noticed a whole lot of difference.
But yeah processing ticks on AIPlayers or anything in which you are going to have 100's of spawns of is going to take some horsepower.
#14
I'll have to look into some of this tomorrow. I was hoping not to have to climb into the engine and start editing stuff again. But it'll be fun! :]
-Nick
04/11/2006 (11:28 pm)
Wow. Those were some quick respones there! Thank you!I'll have to look into some of this tomorrow. I was hoping not to have to climb into the engine and start editing stuff again. But it'll be fun! :]
-Nick
Torque Owner Tom Richardson
You can use this same setup to create scripted AI logic that doesnt apply to your normal players. Anywhere where you might want to implement AI-only logic just wrap it in a if(%obj.isai == "1") block and program away to your hearts content. With a little work you should be able to implement simple little "ant" ai that meanders about on it's own and attacks anything that comes within a certain radius.
If you want to give your players a certain advantage without an autoattack option, you can just create an avatar especially for your avatar with a shorter view/firing range, so if the player is clever he can sneak up on the AI and kill him before he auto-attacks.
However, with just a little more work it is very easy to give players an actual view cone rather than just doing a radius attack.
Have fun!