Immersive AI Engine by Gavin Bunney discussion
by Fyodor -bank- Osokin · in Torque Game Engine · 02/27/2007 (4:46 am) · 191 replies
Let's discuss the iAI engine here, not spamming the .blog is good :)
The first question - is it based on standard AIPlayer.cc from SDK?
May be it's written in documents, but I haven't read all of them yet..
The first question - is it based on standard AIPlayer.cc from SDK?
May be it's written in documents, but I haven't read all of them yet..
About the author
Game developer.
Recent Threads
#122
@Roland: This sounds like a problem with how your calling the functions, and how they are being loaded at start up in your scripts. If a call to a function is listed in a cs file, and it was loaded at statup after the function in a script that wants to call it, it wont find it.
12/21/2007 (10:37 am)
@Mat: Have you tried what I did when I had torque crash on a path create? It may be that there are no nodes close by to create at the locations that is listed from the error. Also try toggledisplay to see where the nodes are and how close/far they are from your player model.@Roland: This sounds like a problem with how your calling the functions, and how they are being loaded at start up in your scripts. If a call to a function is listed in a cs file, and it was loaded at statup after the function in a script that wants to call it, it wont find it.
#123
12/21/2007 (11:11 am)
Hi Rich, I have toggleDisplay set and I can see all the nodes and they're around my player and aiPlayer.
#124
12/25/2007 (12:29 pm)
@Rick: Thanks for the tip, i will have to go into my cs files and make sure the calls are in the right place to initialize the AI.
#125
iAIAgent.cc
If it is not obvious, the significance of the code is to remove the overhead of scheduling events via the console and posting them directly in the engine. Are there any client/server implications implementing it like this ?
The logic for the scheduled tasks could also be handled in the SimEvent instead of the schedule command, reducing the number of event classes, changing AgentThinkEvent to AgentEvent
12/27/2007 (12:24 pm)
The port to c++, for those interested, is almost complete. Some related code-bits down to the goal-specific handlers are all that need be ported. Below is a code segment which needs some scrutiny, is there a better way of doing it ?iAIAgent.cc
...
class AgentThinkEvent : public SimEvent
{
public:
AgentThinkEvent( )
{
}
void process( SimObject *object ){
((iAIAgent*)object)->think();
}
};
...
void iAIAgent::schedule ( U32 delay, const char * task ){
SimEvent *evt;
if ( task == "think" ) {
evt = new AgentThinkEvent( );
Sim::postEvent( this, evt, Sim::getCurrentTime() + delay );
}
}
...
void iAIAgent::think( ){
...
}
...If it is not obvious, the significance of the code is to remove the overhead of scheduling events via the console and posting them directly in the engine. Are there any client/server implications implementing it like this ?
The logic for the scheduled tasks could also be handled in the SimEvent instead of the schedule command, reducing the number of event classes, changing AgentThinkEvent to AgentEvent
#126
Thanks. This seems like an interesting topic to read up on. I am in the process of defining a simple AI for an RPG setting so some actual code of something that works is always nice to look at.
Thanks again,
Frank
12/30/2007 (12:00 am)
Gavin,Thanks. This seems like an interesting topic to read up on. I am in the process of defining a simple AI for an RPG setting so some actual code of something that works is always nice to look at.
Thanks again,
Frank
#127
Yeah that was the problem. I was initializing the AI to late. Bumping it up to be called right after the exec of the player.cs fixed the problem. I now have the AI working. Thanks again.
12/30/2007 (9:54 am)
@RickYeah that was the problem. I was initializing the AI to late. Bumping it up to be called right after the exec of the player.cs fixed the problem. I now have the AI working. Thanks again.
#128
12/30/2007 (2:22 pm)
Has anyone tested the scalability of this AI kit? I read in the writeup that they could get 100 NPCs working using the A* pathfinding. I don't remember seeing something about the whole system together. If A* is the speed bottleneck then I will leave it out and use something more lightweight. Even if it sacrifices some "intelligence" for the NPC.
#129
01/02/2008 (6:05 am)
The bottleneck is not the A* pathfinding in any of the routines found here at garagegames. Its the use of the scripting that is the bottleneck, and is need of an overhaul to pure c++. Greg Davis is busy working on this right now. This is the only reason I have been keeping an eye on this project. Scripting is good to knock something out, but there is a huge problem with things getting broken, or turning into noodle soup when your trying to speed things up.
#130
01/02/2008 (6:23 am)
The c++ upgrade is getting there. One item needing moving is the setting of the datablock(PlayerData, etc), does anyone know how to do it efficiently in c++ ?
#131
One particular note of interest is how the movement is determined in aiplayer from this function:
01/02/2008 (10:48 am)
I think that a study of how calls are made to/from the aiplayer.cc file may help. I tried once to do this, but other things came up, and I lost my work. If I remember right, this class is inherited from the player.cc file, (which a check from the aiplayer.h should reveal), which the old ai class used or aiplayer.ccOne particular note of interest is how the movement is determined in aiplayer from this function:
bool AIPlayer::getAIMove(Move *movePtr)I think an examination of how Mark Holocomb did his CTF bots which is scripted would be cool to port to c++ or even his aiguard or aipatrol bot scripts.
#132
In c++ they are created as such:
The question is, how is the datablock member setup in this circumstance ?
01/02/2008 (1:26 pm)
The aiguard and aipatrol are created at script level:%player = new AIPatrol() {
dataBlock = PatrolPlayer;
marker = %obj;
path = %obj.pathname;
botname = %name;
isbot=true;
fov=$AI_PATROL_FOV;
attentionlevel = $AI_PATROL_MAX_ATTENTION/2;
};In c++ they are created as such:
iAIAgent *newAgent;
...
case 1 : newAgent = new iAIAgentBandit(); break;
...
SimGroup * simGroup = dynamic_cast<SimGroup*>(Sim::findObject(Con::getVariable("$missionCleanup")));
simGroup->addObject( newAgent );The question is, how is the datablock member setup in this circumstance ?
#133
If you study the simbase.h file, it has a lot of commenting on how to implement things like your posted call to create a new instance of of a new iAIAgentBandit:
01/03/2008 (5:58 am)
Ok, after trolling through some of the code, I discovered this in the aiplayer.h file:class AIPlayer : public Player {
typedef Player Parent;
...
// more code to followso it stands to reason, that you can set up your ai player based upon the player.cc cod from inheritence. I am pretty sure the immersive ai is doing just the same thing.If you study the simbase.h file, it has a lot of commenting on how to implement things like your posted call to create a new instance of of a new iAIAgentBandit:
/// When you subclass, you should define a typedef in the class, called Parent,
/// that references the class you're inheriting from.
///
/// @code
/// class mySubClass : public SimObject {
/// typedef SimObject Parent;
/// ...
/// @endcode
///
/// Then, when you override a method, put in:
///
/// @code
/// bool mySubClass::onAdd()
/// {
/// if(!Parent::onAdd())
/// return false;
///
/// // ... do other things ...
/// }
/// @endcodefurther down in the simbase.h file we find:/// @code /// // Three examples of registering an object. /// /// // Method 1: /// AIClient *aiPlayer = new AIClient(); /// aiPlayer->registerObject();dont know if the above helps any
#134
Right you are ! And thanks for looking !
Earlier, the code below seemed to work pretty well :
registerObject does not work correctly unless a shape is defined for the object. The onAdd in iAIAgent requires an extension ...
... otherwise preload problems occur if a game connection has not yet been established.
After creating sim objects via c++ it became apparent that further configuration and setup would require migrating(ie. the remainder of the datablock configuration, which is vastly applied in the script layer).
Realising that there is much work in doing so, that the process would consume time required for the ultimate goal of extending the agent count and that no real gain would be accomplished as loading a sim object via script is once-off, the following command was implemented:
This calls a modified version of the script level iAIAgentBandit::spawn, thereafter, the AI manager acquires the objects handle and all code bits resume in c++.
btw, each test scenario currently uses 90 agents, lag is at a minimum( most lag occurs when an agent is added to the scene ). There are still calls to script which need to migrate.
01/03/2008 (12:08 pm)
@rick:Right you are ! And thanks for looking !
Earlier, the code below seemed to work pretty well :
... GameBaseData * data = new PlayerData(); ... data->preload( true, errorBuffer ); ... this->setDataBlock( data ); this->setAgentType( "bandit" ); this->pickSpawnPoint(); if ( !this->registerObject() ) Con::iAIMessagef( "Unable to register Bandit !!!!" ); ...
registerObject does not work correctly unless a shape is defined for the object. The onAdd in iAIAgent requires an extension ...
...
GameConnection* conn = GameConnection::getConnectionToServer();
if(!conn || !Parent::onAdd())
return false;
...... otherwise preload problems occur if a game connection has not yet been established.
After creating sim objects via c++ it became apparent that further configuration and setup would require migrating(ie. the remainder of the datablock configuration, which is vastly applied in the script layer).
Realising that there is much work in doing so, that the process would consume time required for the ultimate goal of extending the agent count and that no real gain would be accomplished as loading a sim object via script is once-off, the following command was implemented:
...
iAIAgent *newAgent;
const char * id = "";
...
case 1 :
id = Con::executef( 3, "iAIAgentBandit_spawn", name, pickSpawnPoint() );
newAgent = dynamic_cast<iAIAgent*>(Sim::findObject(id));
break; //$iAIAgentType_Bandit_Code
...This calls a modified version of the script level iAIAgentBandit::spawn, thereafter, the AI manager acquires the objects handle and all code bits resume in c++.
btw, each test scenario currently uses 90 agents, lag is at a minimum( most lag occurs when an agent is added to the scene ). There are still calls to script which need to migrate.
#135
01/03/2008 (1:05 pm)
Sounds good! One of the better bot ai that was homebrewed that I used to use a lot in Mod development was based on the Half Life original game by valve might be of use to you. If you look up Botman and his source code you may find something of use. I based some of my experiments off a few routines that seem to serve me well for getting the bots to decide how to navigate inside of an interior. This of course was in the old half life game and I never ported it to torque.
#136
Let me know if you need help. I am no stranger to the player code. I have built a few objects and may be able to figure stuff out. My gut feel is to let the datablock assignment be done in script as it only happens once. Once it is loaded any number of objects will use that object.
01/03/2008 (6:57 pm)
How many bots are looking to get into the sim? I was hoping of upwards of 200 to 300, but only a few of those would even need to be calculating their path at any one time. So maybe A* would work if they only used it during critical times such as fleeing or attacking. It could be switched on and off. That would work for me.Let me know if you need help. I am no stranger to the player code. I have built a few objects and may be able to figure stuff out. My gut feel is to let the datablock assignment be done in script as it only happens once. Once it is loaded any number of objects will use that object.
#137
01/04/2008 (5:01 am)
250+ is definately the mark, once the code is ported to c++, it will be uploaded, thereafter timing code will be added to see where all the processing happens.
#138
01/04/2008 (6:05 am)
I may have some code that you could use for the modern processor class when you get to that point. Let me know.
#139
These are the outstanding items needing converting to c++:
-doDefend
-doExplore
-doHunt
-doRest
-getFood
-getHealth
-goHome
-haveFun
( agent, agent_seek, agent_combat, goal_manager, library, agent_manager ... have all been migrated )
Basically all the goals. Based on the complexity of these compared to agent and agent_manager, they should be a walk in the park. Not too much longer, a few days surely.
01/04/2008 (10:53 am)
Modern processor class ? Any help will be great. The goal was to "hack" as best as possible the exact architecture of the script into c++, then share it so that more brains can be tasked with optimization. If there is something obvious which can be changed in the interim, lets do it !!These are the outstanding items needing converting to c++:
-doDefend
-doExplore
-doHunt
-doRest
-getFood
-getHealth
-goHome
-haveFun
( agent, agent_seek, agent_combat, goal_manager, library, agent_manager ... have all been migrated )
Basically all the goals. Based on the complexity of these compared to agent and agent_manager, they should be a walk in the park. Not too much longer, a few days surely.
#140
eg.
01/07/2008 (8:21 am)
All code is now upgraded to c++. Preliminary debugging verifies that thinking and goal evaluation occurs successfully. There is one problem, the agent does not move, setMoveDestination is the command used in c++. Help is really appreciated.eg.
void iAIAgent::think_combat()
{
// clear last attacked
this->lastAttackedBy = NULL;
if (this->isCombat_InCombat() == true)
{
// agent is in combat; randomly sidestep
if (gRandGen.randI(0,1) == 1)
this->sideStep();
// check for LOS
if (this->hasLOS( this->getHunt_Object()))
{
// if not sidestepping, stop moving as have LOS now
if (this->combat_IsSideStepping == false)
this->stopMove();
// fire
this->setImageTrigger( 0, true );
// increase inventory (never ending ammo)
//this->incInventory("CrossbowAmmo", 1);
// schedule the trigger stop
this->schedule( 2, 1500, "setImageTrigger", 0, false);
} else
{
// don't have LOS start moving towards player
[b]this->setMoveDestination( this->getHunt_Object()->getPosition(), true );[/b]
}
}
}
Torque Owner Roland Orr
Roland Dynamics