How to make an AI player look at the player?
by Ahmed Zamen · in Technical Issues · 02/28/2008 (5:42 am) · 28 replies
Hi, im trying to get an Ai player to spawn on the map, look and turn to face the player and move only in his place to swivel around to keep the player in view. How would I go about doing this?
Thanks!
Thanks!
#2
03/01/2008 (9:50 am)
AIPlayer has a function called AimAt that will turn him to whatever object you want. If you want it to track, you'll probably have to schedule it to repeat.
#3
Wherever the player goes, the AI player will keep aiming at him.
03/02/2008 (8:07 am)
You don't need scheduling to track the player. just use [b]AIPlayerId[/b].setAimObject(localclientconnection.player);
Wherever the player goes, the AI player will keep aiming at him.
#4
I remember now that it does track because you can use ClearAim to turn it off.
03/02/2008 (8:48 am)
It looks like AimAt calls setAimObject, so there you are...I remember now that it does track because you can use ClearAim to turn it off.
#5
03/02/2008 (1:31 pm)
Sorry, been away from ai code for a while :-)
#6
Maybe im just using the code in the wrong way, im still kinda new to all this. Thanks again.
03/02/2008 (3:44 pm)
Right, sorry if this sounds stupid but im a tad confused. Do I use the AimAt function with the setAimObject or not, ive been playing around with it and tried both in numerous ways but still no luck whatsoever, the bot just kinda stands there, if its any help im testing the code out in codesamplers bot path finding tutorial. Maybe im just using the code in the wrong way, im still kinda new to all this. Thanks again.
#7
@Newport,
Maybe you could post the excact code you're using? Are you sure your objects are valid? Bryce's example should work fine. AimAt is used exactly the same way but is meant to be used with the Task List system.
03/03/2008 (8:11 am)
@Bryce, It's been a while since I've done anything in script myself.@Newport,
Maybe you could post the excact code you're using? Are you sure your objects are valid? Bryce's example should work fine. AimAt is used exactly the same way but is meant to be used with the Task List system.
#8
Thats the code im using, im not sure where its suppose to be put or if i need anything deleted. Thanks again
03/03/2008 (11:04 am)
datablock PlayerData( MyBot : PlayerShape )
{
patrol = true;
attack = false;
};
function MyBot::onReachDestination( %this, %obj )
{
// Moves to the next node on the path.
if( %obj.path !$= "" )
{
if( %obj.currentNode == %obj.targetNode )
%this.onEndOfPath( %obj, %obj.path );
else
%obj.moveToNextNode();
}
else
echo( "MyBot::onReachDestination warning - Path is blank!" );
}
function MyBot::onEndOfPath( %this, %obj, %path )
{
%obj.nextTask();
}
//-----------------------------------------------------------------------------
// AIPlayer static functions
//-----------------------------------------------------------------------------
function AIPlayer::spawn( %name, %spawnPoint )
{
// Create the A.I. driven bot object...
%player = new AIPlayer()
{
dataBlock = MyBot;
path = "";
};
MissionCleanup.add( %player );
%player.setShapeName( %name );
%player.setTransform( %spawnPoint );
return %player;
}
function AIPlayer::spawnOnPath( %name, %path )
{
// Spawn a bot and place him on the first node of the path
if( !isObject( %path ) )
{
echo( "AIPlayer::spawnOnPath failed - Bad Path!" );
%this.path = "";
return;
}
%node = %path.getObject(0);
%player = AIPlayer::spawn( %name, %node.getTransform() );
return %player;
}
function AIPlayer::followPath( %this, %path, %node )
{
// Start the bot following a path
%this.stopThread(0);
if( !isObject( %path ) )
{
echo( "AIPlayer::followPath failed - Bad Path!" );
%this.path = "";
return;
}
if( %node > %path.getCount() - 1 )
%this.targetNode = %path.getCount() - 1;
else
%this.targetNode = %node;
if( %this.path $= %path )
%this.moveToNode(%this.currentNode);
else
{
%this.path = %path;
%this.moveToNode(0);
}
}
function AIPlayer::moveToNextNode( %this )
{
if( %this.targetNode < 0 || %this.currentNode < %this.targetNode )
{
if( %this.currentNode < %this.path.getCount() - 1 )
%this.moveToNode( %this.currentNode + 1 );
else
%this.moveToNode( 0 );
}
else
{
if( %this.currentNode == 0 )
%this.moveToNode( %this.path.getCount() - 1 );
else
%this.moveToNode( %this.currentNode - 1 );
}
}
function AIPlayer::moveToNode( %this, %index )
{
// Move to the given path node index
%this.currentNode = %index;
%node = %this.path.getObject(%index);
%this.setMoveDestination( %node.getTransform(), %index == %this.targetNode );
}
//-----------------------------------------------------------------------------
// AIManager static functions
//-----------------------------------------------------------------------------
function AIManager::think( %this )
{
if( !isObject( %this.player ) )
%this.player = %this.spawn();
%this.schedule( 500, think );
}
function AIManager::spawn( %this )
{
// Bot_1 simply spawns without a path to follow. Since he has no path to
// follow, he'll simply spawn at the same spot that you do. This means that
// you'll have to move around to see him when the game first starts because
// he'll be right on top of you.
AIPlayer.setAimObject(localclientconnection.player);
%bot = AIPlayer::spawn( "Bot_1", pickSpawnPoint() );
// Bot_2 has a path to follow, so we'll help him out by having him spawn
// by the Path's first Path Marker. Once he spawns, he'll begin to follow
// the path using the A.I. helper functions defined here in this file.
//%bot = AIPlayer::spawnOnPath( "Bot_2", "MissionGroup/myPath" );
//%bot.followPath( "MissionGroup/myPath", -1 );
return %bot;
} Thats the code im using, im not sure where its suppose to be put or if i need anything deleted. Thanks again
#9
AIPlayerId.setAimObject(localclientconnection.player); right before the return %bot; area. Everything works great except the next step is to get the AI to have the capability to use a weapon.
03/03/2008 (3:30 pm)
I have had a simular issue with the blueguy. The Blue does not look at the player no matter what I did. I switched the AI Avatar to the SpaceOrk's. You can find the space ork in the Demo. The only lines I changed in the AI file (after porting over the script and object files) that you have above is putting PlayerBody instead of PlayerShape. I put AIPlayerId.setAimObject(localclientconnection.player); right before the return %bot; area. Everything works great except the next step is to get the AI to have the capability to use a weapon.
#10
03/03/2008 (4:23 pm)
Yeah, PlayerShape could be the problem depending on what your base PlayerData is called. In the demo code I think it's always PlayerBody.
#11
03/04/2008 (2:29 am)
No luck again im afraid guys, tried all you have told me but nothings working.
#12
03/04/2008 (7:53 am)
I don't know what to tell you at this point. You seem to working on something very similar to the starter.fps demo. I'd try a side-by-side comparison and see if you can't noodle it out that way.
#13
03/04/2008 (4:34 pm)
Any error messages? You've probably got a goof that some well placed echo statements might help find.
#14
03/04/2008 (7:50 pm)
Ok, this may be stupid or it may work so whatever...AIPlayer.setAimObject(localclientconnection.player); %bot = AIPlayer::spawn( "Bot_1", pickSpawnPoint() );In here aren't you setting the AIPlayer's aim before he's even spawned?
#15
EDIT: Ive also found some code from the aiPlayer.cs file in the fps starter kit:
Would I need to delcare that in my bot.cs file while using the setobject code?
03/08/2008 (6:33 am)
Ive changed that part of the code now but the code still aint working and im not getting any error messages in the console so by all accounts it should be working, but its not.EDIT: Ive also found some code from the aiPlayer.cs file in the fps starter kit:
function AIPlayer::aimAt(%this,%object)
{
echo("Aim: " @ %object);
%this.setAimObject(%object);
%this.nextTask();
}Would I need to delcare that in my bot.cs file while using the setobject code?
#16
AIPlayer being the class, not an object. %bot being the bot (Bot_1) spawned on the point. And assuming that the client.player is indeed set to player.
The sample code has poor name choices in my opinion, so I think it can confusing. AIManager::Think is creating on AIPlayer called AIManager.player rather than AIMAnager.AIPlayer or AIManager.bot or something.
Anyway, if you spawn him in the Spawn method and then have him Aim at an object, it should work assuming the objects are all valid.
03/08/2008 (12:29 pm)
Morrock is right. I didn't notice it earlier. It should look more like:%bot = AIPlayer::spawn( "Bot_1", pickSpawnPoint() ); [b]%bot[/b].settAimObject( localclientconnection.player);
AIPlayer being the class, not an object. %bot being the bot (Bot_1) spawned on the point. And assuming that the client.player is indeed set to player.
The sample code has poor name choices in my opinion, so I think it can confusing. AIManager::Think is creating on AIPlayer called AIManager.player rather than AIMAnager.AIPlayer or AIManager.bot or something.
Anyway, if you spawn him in the Spawn method and then have him Aim at an object, it should work assuming the objects are all valid.
#17
03/08/2008 (3:16 pm)
Which cs file would I need to check to set player to client.player, this is probably the reason why it isnt working. Nothing I looked at mentioned it.
#18
When a client is attached to a player, you have two objects there--the client and the player. Most game operations are going to take place on the player, which you can generally find by referencing %client.player, where %client is the client object simID on the server. Or, you can generally get the client by referencing %player.client.
For example, at the beginning of a lot of my script functions, I've started recontexting the variables. So if I'm giving only the client as a paramater (such as %this), I might have a little section like this:
%player = %this.player; //now I can do stuff to the %player object more easily
%vehicle = %this.getControlObject(); //if I have vehicles
Or, conversely, if I'm fed only the player or vehicle object, and I need to do work on the client, I might do:
%client = %obj.client;
Point being, you can generally work out where you are on the object hierarchy from any point on the tree, and assemble references as you need them. %obj, %client, %player and such are simply convenient naming conventions, and what you get passed to your function is not necessarily what you expect. For example, I could call a function:
foo (%obj, %client, %player);
And even though the function is written:
function foo (%client, %player, %obj) ....
Within the function, even though my first paramater is labeled %client, it's being passed whatever was in %obj by my function call.
If I'm way off base, I beg your pardon. I merely interpreted your question to be about this common misconception about TS.
03/08/2008 (5:25 pm)
It's really more a matter of calling the action on the right object in your script. Each function exists in it's own context, so this isn't something you would necessarily want to try to change universally.When a client is attached to a player, you have two objects there--the client and the player. Most game operations are going to take place on the player, which you can generally find by referencing %client.player, where %client is the client object simID on the server. Or, you can generally get the client by referencing %player.client.
For example, at the beginning of a lot of my script functions, I've started recontexting the variables. So if I'm giving only the client as a paramater (such as %this), I might have a little section like this:
%player = %this.player; //now I can do stuff to the %player object more easily
%vehicle = %this.getControlObject(); //if I have vehicles
Or, conversely, if I'm fed only the player or vehicle object, and I need to do work on the client, I might do:
%client = %obj.client;
Point being, you can generally work out where you are on the object hierarchy from any point on the tree, and assemble references as you need them. %obj, %client, %player and such are simply convenient naming conventions, and what you get passed to your function is not necessarily what you expect. For example, I could call a function:
foo (%obj, %client, %player);
And even though the function is written:
function foo (%client, %player, %obj) ....
Within the function, even though my first paramater is labeled %client, it's being passed whatever was in %obj by my function call.
If I'm way off base, I beg your pardon. I merely interpreted your question to be about this common misconception about TS.
#19
Sorry most of your post confused me but all this help is much appreciated.
03/09/2008 (5:55 am)
So if im getting the jist of this right where:(localclientconnection.player);is I would have to put somethin along the lines of %player.client or something?
Sorry most of your post confused me but all this help is much appreciated.
#20
The problem appears to be that you are not acting on the right game object. Put echo's in your functions to echo out the object id's they are dealing with, and see if that matches what you see in the Mission Editor.
Localclientconnection only works in certain scenario's, I've found--and definitely won't work in a real client/server scenario. So I think the answer is yes, more or less.
All I can really do is point you in the right direction....
03/09/2008 (6:35 am)
You're right--not my best post, ever. But on the other hand, keep reading it until it makes sense.The problem appears to be that you are not acting on the right game object. Put echo's in your functions to echo out the object id's they are dealing with, and see if that matches what you see in the Mission Editor.
Localclientconnection only works in certain scenario's, I've found--and definitely won't work in a real client/server scenario. So I think the answer is yes, more or less.
All I can really do is point you in the right direction....
Torque Owner Lee Latham
Default Studio Name
2345.dump
and it will show you all the members and methods of the object. I would suspect one of the methods starting with "set" may be of interest to you.
My terminology is probably ignorant and wrong, but the dump command is dang handy.