Player Target Locking
by Kurt · 04/01/2003 (10:50 am) · 25 comments
Okay so you want target locking? This tutorial should get you started. I have borrowed massive amounts of great code from a variety of sources so don't think for a minute that this is all my doing. The guys at tork.zenkel are awesome and are to be commended for their sharing of knowledge.
If I have omitted something please tell me and I will do my best to resolve the issue.
What does this code do? Well first you map a key which will be your target lock key. When this key is pressed the nearest bot is locked onto. Hitting the key again locks you to the next nearest bot and so on until there are no bots left to lock. If a bot is locked onto and leaves your predetermined locking distance he will automatically be unlocked. I will leave it up to the implementer to determine this distance. When a bot is locked in the code I am running currently, I place an emitter at mount1 of my bot model so i can see who is locked onto when there is a gang of bots. I marked this code as optional.
Issues:
At the moment dead bots can be locked onto. This is also a problem in Vice-City so I do not feel so bad. :) This should be easily solveable and I will post the fix later.
First things first, you must get some bots into your mission. To do this check out Stefan's excellent tutorial at:
Bots
For this tutorial the reader should know that I add my bots by using the ctrl + b keystroke. After the mission starts I manually add some bots that immediately start following waypoints. This is important because as bots are added I keep track of them by storing them in a sim group.
In my games.cs file I add the follwing to the
GameConnection::onClientEnterGame(%this) funcion:
$totalBots = new SimGroup(totalBots);
$lockedBots = new SimGroup(lockedBots);
$unlockedBots = new SimGroup(unlockedBots);
These will be explained as we proceed.
Okay so whereever you spawn bots you need to add the bot object to the totalBots Sim group. In my funtion that gets invoked whenever I manually spawn bots (ctrl+b in my case) you can see that I add the newly created bot to the group. See below:
Okay so now everytime a bot is spawned we have him stored in our totalBots array. Cool!
Now on to the locking code!
Take the time now to bind the lock funtion to the key of your liking. In My case I used the 'L' key. So in my config.cs I added:
moveMap.bindCmd(keyboard, "l", "", "lockOn();");
and in my default.bind.cs I added:
moveMap.bindCmd(keyboard, "l", "", "lockOn();");
Okay now on to the server side player.cs file.
The first funtion I am going to add is the lockOn funtion that gets invoked when the "L" key is pressed. Here is the funtion with added comments. Note: I mark a bot as locked in this code by placing halo emitter on his mount1 node which happens to be on top of his head. You do not have to do this. I just did it for giggles. I will mark this code as optional in the following funtion. *Remember totalBots is populated in the script where the bots are spawned. *
Now we need to look at the implementation for BotStillInRange(%this, %bot ). This is pretty simple. Just a call to the AiPlayer's isObjectInView() function follwed by a schedule. Again the unmountImage only applies if you are using a mount point to mark the bot as locked. If the bot leaves the fov, unlock.
And finally the getClosestBot function. This function was borrowed from some of Stefan's code. In here
we merely determine which bot is closest among those in the unlockedBots group and return that bot.
One other note, I modified the AIPlayer::isObjectInView() funtion to accept a distance parameter. So here is my version:
Whew! Now on to the engine code.
The only files modified in the engine are player.cc and player.h. Really all I am doing is moving some
of the aiplayer functionality to the player class.
As for player.h , these lines are added:
In player.cc:
Add these lines to :
Add these three funtions:
Since we are taking over the players movement when we are locked we need to change the behavior of
ProcessTick so it now looks like this:
We need an aiMove for the player function since he is being controlled when we are locked:
And finally, expose some method to the console:
That is it. I am sure I have missed something so let me know if you hit some snags. It would also be nice to hear what could be done to improve this code.
:)
If I have omitted something please tell me and I will do my best to resolve the issue.
What does this code do? Well first you map a key which will be your target lock key. When this key is pressed the nearest bot is locked onto. Hitting the key again locks you to the next nearest bot and so on until there are no bots left to lock. If a bot is locked onto and leaves your predetermined locking distance he will automatically be unlocked. I will leave it up to the implementer to determine this distance. When a bot is locked in the code I am running currently, I place an emitter at mount1 of my bot model so i can see who is locked onto when there is a gang of bots. I marked this code as optional.
Issues:
At the moment dead bots can be locked onto. This is also a problem in Vice-City so I do not feel so bad. :) This should be easily solveable and I will post the fix later.
First things first, you must get some bots into your mission. To do this check out Stefan's excellent tutorial at:
Bots
For this tutorial the reader should know that I add my bots by using the ctrl + b keystroke. After the mission starts I manually add some bots that immediately start following waypoints. This is important because as bots are added I keep track of them by storing them in a sim group.
In my games.cs file I add the follwing to the
GameConnection::onClientEnterGame(%this) funcion:
$totalBots = new SimGroup(totalBots);
$lockedBots = new SimGroup(lockedBots);
$unlockedBots = new SimGroup(unlockedBots);
These will be explained as we proceed.
Okay so whereever you spawn bots you need to add the bot object to the totalBots Sim group. In my funtion that gets invoked whenever I manually spawn bots (ctrl+b in my case) you can see that I add the newly created bot to the group. See below:
[b]function serverCmdAddBot(%client)
{
%npcName = "Bot" @ $botCounter;
%bot = AIPlayer::spawnPlayer(%npcName);
$totalBots.add(%bot);
//%bot.setScanningPlayers(true);
echo( %bot.getShapeName() );
}[/b]Okay so now everytime a bot is spawned we have him stored in our totalBots array. Cool!
Now on to the locking code!
Take the time now to bind the lock funtion to the key of your liking. In My case I used the 'L' key. So in my config.cs I added:
moveMap.bindCmd(keyboard, "l", "", "lockOn();");
and in my default.bind.cs I added:
moveMap.bindCmd(keyboard, "l", "", "lockOn();");
Okay now on to the server side player.cs file.
The first funtion I am going to add is the lockOn funtion that gets invoked when the "L" key is pressed. Here is the funtion with added comments. Note: I mark a bot as locked in this code by placing halo emitter on his mount1 node which happens to be on top of his head. You do not have to do this. I just did it for giggles. I will mark this code as optional in the following funtion. *Remember totalBots is populated in the script where the bots are spawned. *
[b]function lockOn( )
{
echo("LOCKING ON TO TARGET");
%client = ClientGroup.getObject(0);
// Move all unlocked bots to total bots so we can
// testfor their proximity and whether or not they are
// in the FOV. New bots may have been added
// since the last time we were called so we need to
// start from scratch when determining
// the closest bot.
%i = $unlockedBots.getCount();
while( %i > 0 )
{
$totalBots.add( $unlockedBots.getObject( %i-1 ) );
echo( "Moving total bots to unlocked bots");
echo( "Total bot count = " @ $totalBots.getCount() );
echo( "Locked bot count = " @ $lockedBots.getCount() );
echo( "Unlocked bot count = " @ $unlockedBots.getCount() );
%i--;
}
// is the bot in and close enough? If so add the bot to the unlocked
// group
for( %i=0; %i < $totalBots.getCount(); %i++)
{
if( AIPlayer::isObjectInView( %client.player, $totalBots.getObject( %i ), 20 ) )
{
echo( "Adding bots to FOV unlocked");
$unlockedBots.add($totalBots.getObject( %i ));
}
echo( "Total bot count = " @ $totalBots.getCount() );
echo( "Locked bot count = " @ $lockedBots.getCount() );
echo( "Unlocked bot count = " @ $unlockedBots.getCount() );
}
// get the closest bot from those in the unlockedBots
// array.
%bot = %client.player.getClosestBot( );
// unlock currently locked bot
// ****************************************************
// OPTIONAL! This removes the halo emitter from the
// bots head
// ****************************************************
//%i = $lockedBots.getCount();
//while ( %i > 0 )
//{
// %lockedbot = $lockedBots.getObject( %i-1 );
// %lockedbot.unmountImage(0);
// echo( "unlocking current Bot");
// echo( "Total bot count = " @ $totalBots.getCount() );
// echo( "Locked bot count = " @ $lockedBots.getCount() );
// echo( "Unlocked bot count = " @ $unlockedBots.getCount() );
// %i--;
//}
// if we have a valid object lock on and schedule a function that
// determines if the bot is still in range
if( isObject( %bot ) )
{
echo( "Locking on Bot");
// ***********************************************************
// OPTIONAL! This adds the halo emitter from the bots head
// ***********************************************************
//%bot.mountImage(%data.image, 0);
//%bot.use(Halo);
$lockedBots.add( %bot );
%client.player.setAimObject( %bot );
echo( "Total bot count = " @ $totalBots.getCount() );
echo( "Locked bot count = " @ $lockedBots.getCount() );
echo( "Unlocked bot count = " @ $unlockedBots.getCount() );
// we need to schedule updates to see if this bot is out of range
Player::BotStillInRange( %client.player, %bot );
}
else
{
// no more bots left to lock. add the bots back into the
// totalbots group and wait for another lockOn
echo( "No bots left to lock!");
%client.player.setAimObject( 0 );
// we have exhausted all locked bots reset all
%i = $lockedBots.getCount();
while( %i > 0 )
{
echo( "Adding locked bots back to total bots");
$totalBots.add( $lockedBots.getObject( %i-1 ) );
echo( "Total bot count = " @ $totalBots.getCount() );
echo( "Locked bot count = " @ $lockedBots.getCount() );
echo( "Unlocked bot count = " @ $unlockedBots.getCount() );
%i--;
}
}
}[/b]Now we need to look at the implementation for BotStillInRange(%this, %bot ). This is pretty simple. Just a call to the AiPlayer's isObjectInView() function follwed by a schedule. Again the unmountImage only applies if you are using a mount point to mark the bot as locked. If the bot leaves the fov, unlock.
[b]function Player::BotStillInRange(%this, %bot )
{
if ( AIPlayer::isObjectInView( %this, %bot, 20 ) )
{
%this.schedule( 500, "BotStillInRange", %bot );
echo( "Bot still in view" );
}
else
{
%this.setAimObject( "" );
// ***********************************************************
// OPTIONAL! This removes the halo emitter from the bots head
// ***********************************************************
//%bot.unmountImage(0);
echo( "Bot left view" );
}
}[/b]And finally the getClosestBot function. This function was borrowed from some of Stefan's code. In here
we merely determine which bot is closest among those in the unlockedBots group and return that bot.
[b]function Player::getClosestBot(%this)
{
%playerPos = %this.getPosition();
for(%i = 0; %i < $unlockedBots.getCount(); %i++)
{
echo("Iterating bots");
%bot = $unlockedBots.getObject(%i);
%botPos = %bot.getLocation();
%tempDist = VectorDist(%playPos, %botPos);
if(%i == 0) {
%dist = %tempDist;
%closebot = %bot;
}
else {
if(%dist > %tempDist) {
%dist = %tempDist;
%closebot = %bot;
}
}
}
return %closebot;
}[/b]One other note, I modified the AIPlayer::isObjectInView() funtion to accept a distance parameter. So here is my version:
[b]function AIPlayer::isObjectInView(%this, %object, %dist)
{
%player = %this;
// default sight range of AI:
%this.sightRange = %dist;
if (!(isObject(%player) && isObject(%object)))
{
return false;
}
%objPos = %object.getWorldBoxCenter();
%eyePoint = %player.getWorldBoxCenter();
%distance = VectorDist(%objPos, %eyePoint);
error("**************DISTANCE FROM PLAYER = " SPC %distance);
error("**************sightRange = " SPC %this.sightRange);
if (%distance <= %this.sightRange)
{
// if the object is within 1.5 meters sometimes it can
// fall out of the field of view due to the eye height
if (%distance > 2)
{
%eyeTransform = %player.getEyeTransform();
%eyePoint = firstWord(%eyeTransform)
SPC getWord(%eyeTransform, 1)
SPC getWord(%eyeTransform, 2);
error("**************distance is greater thatn two");
}
%eyeVector = VectorNormalize(%player.getEyeVector());
//make sure we're not looking through walls...
%mask = $TypeMasks::TerrainObjectType |
$TypeMasks::InteriorObjectType |
$TypeMasks::StaticShapeObjectType;
%losResult = containerRayCast(%objPos, %eyePoint, %mask);
%losObject = GetWord(%losResult, 0);
if (!isObject(%losObject))
{
error("**************LOS!!");
//create the vector from this client to the client
%objVector = VectorNormalize(VectorSub(%objPos, %eyePoint));
// dot product to determine field of view
%dot = VectorDot(%objVector, %eyeVector);
error("**************DOT" @ %dot);
// within field of view
return (%dot > 0.6);
}
}
return false;
}[/b]Whew! Now on to the engine code.
The only files modified in the engine are player.cc and player.h. Really all I am doing is moving some
of the aiplayer functionality to the player class.
As for player.h , these lines are added:
[b]class Player: public ShapeBase
{
....
....
protected:
SimObjectPtr<GameBase> mAimObject; // Object to point at, overrides location
bool mAimLocationSet; // Has an aim location been set?
Point3F mAimLocation; // Point to look at
bool mTargetInLOS; // Is target object visible?
....
public:
....
// Targeting and aiming sets/gets
virtual void setAimObject( GameBase *targetObject );
virtual GameBase* getAimObject() const { return mAimObject; }
virtual void setAimLocation( const Point3F &location );
virtual Point3F getAimLocation() const { return mAimLocation; }
virtual void clearAim();
};[/b]In player.cc:
Add these lines to :
[b]Player::Player()
{
....
....
AimObject = 0;
mAimLocationSet = false;
mTargetInLOS = false;
}[/b]Add these three funtions:
[b]
/**
* Sets the object the player is targeting
*
* @param targetObject The object to target
*/
void Player::setAimObject( GameBase *targetObject )
{
mAimObject = targetObject;
mTargetInLOS = false;
}
/**
* Sets the location for the Player to aim at
*
* @param location Point to aim at
*/
void Player::setAimLocation( const Point3F &location )
{
mAimObject = 0;
mAimLocationSet = true;
mAimLocation = location;
}
/**
* Clears the aim location and sets it to the player's
* current destination so he looks where he's going
*/
void Player::clearAim()
{
mAimObject = 0;
mAimLocationSet = false;
}[/b]Since we are taking over the players movement when we are locked we need to change the behavior of
ProcessTick so it now looks like this:
[b]
void Player::processTick(const Move* move)
{
PROFILE_START(Player_ProcessTick);
// If we're not being controlled by a client, let the
// AI sub-module get a chance at producing a move.
Move aiMove;
if( move )
getAIMove((struct Move*) move );
else
{
if( getAIMove( &aiMove ) )
move = &aiMove;
}
...
...
...
}[/b]We need an aiMove for the player function since he is being controlled when we are locked:
[b]
/**
* This method calculates the moves for the AI player
*
* @param movePtr Pointer to move the move list into
*/
bool Player::getAIMove(Move *movePtr)
{
//*movePtr = NullMove;
// Use the eye as the current position.
Point3F location = getPosition();
Point3F rotation = getRotation();
// Orient towards the aim point, aim object, or towards
// our destination.
if (mAimObject || mAimLocationSet )
{
// Update the aim position if we're aiming for an object
if (mAimObject)
mAimLocation = mAimObject->getPosition();
F32 xDiff = mAimLocation.x - location.x;
F32 yDiff = mAimLocation.y - location.y;
if (!isZero(xDiff) || !isZero(yDiff))
{
// First do Yaw
// use the cur yaw between -Pi and Pi
F32 curYaw = rotation.z;
while (curYaw > M_2PI)
curYaw -= M_2PI;
while (curYaw < -M_2PI)
curYaw += M_2PI;
// find the yaw offset
F32 newYaw = mAtan( xDiff, yDiff );
F32 yawDiff = newYaw - curYaw;
// make it between 0 and 2PI
if( yawDiff < 0.0f )
yawDiff += M_2PI;
else if( yawDiff >= M_2PI )
yawDiff -= M_2PI;
// now make sure we take the short way around the circle
if( yawDiff > M_PI )
yawDiff -= M_2PI;
else if( yawDiff < -M_PI )
yawDiff += M_2PI;
movePtr->yaw = yawDiff;
// Next do pitch. This should be adjusted to run from the
// eye point to the object's center position. Though this
// works well enough for now.
F32 vertDist = mAimLocation.z - location.z;
F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff);
F32 newPitch = mAtan( horzDist, vertDist ) - ( M_PI / 2.0f );
Point3F headRotation = getHeadRotation();
movePtr->pitch = newPitch - headRotation.x;
}
}
else {
return false;
// Level out if we're not doing anything else
Point3F headRotation = getHeadRotation();
movePtr->pitch = -headRotation.x;
}
// Test for target location in sight if it's an object. The LOS is
// run from the eye position to the center of the object's bounding,
// which is not very accurate.
if (mAimObject) {
MatrixF eyeMat;
getEyeTransform(&eyeMat);
eyeMat.getColumn(3,&location);
Point3F targetLoc = mAimObject->getBoxCenter();
// This ray ignores non-static shapes. Cast Ray returns true
// if it hit something.
RayInfo dummy;
if (getContainer()->castRay( location, targetLoc,
InteriorObjectType | StaticShapeObjectType | StaticObjectType |
TerrainObjectType, &dummy)) {
if (mTargetInLOS) {
//throwCallback( "onTargetExitLOS" );
mTargetInLOS = false;
}
}
else
if (!mTargetInLOS) {
//throwCallback( "onTargetEnterLOS" );
mTargetInLOS = true;
}
}
// Replicate the trigger state into the move so that
// triggers can be controlled from scripts.
// beffy - commented out for Jimomighty stuff!
//for( int i = 0; i < MaxTriggerKeys; i++ )
// movePtr->trigger[i] = getImageTriggerState(i);
return true;
}[/b]And finally, expose some method to the console:
[b]
/**
* Tells the Player to aim at the location provided
*/
ConsoleMethod( Player, setAimLocation, void, 3, 3, "ai.setAimLocation( \"x y z\" );" )
{
Player *ai = static_cast<Player *>( object );
Point3F v( 0.0f,0.0f,0.0f );
dSscanf( argv[2], "%f %f %f", &v.x, &v.y, &v.z );
ai->setAimLocation( v );
}
/**
* Returns the point the AI is aiming at
*/
ConsoleMethod( Player, getAimLocation, const char *, 2, 2, "ai.getAimLocation();" )
{
Player *ai = static_cast<Player *>( object );
Point3F aimPoint = ai->getAimLocation();
char *returnBuffer = Con::getReturnBuffer( 256 );
dSprintf( returnBuffer, 256, "%f %f %f", aimPoint.x, aimPoint.y, aimPoint.z );
return returnBuffer;
}
/**
* Sets the bots target object
*/
ConsoleMethod( Player, setAimObject, void, 3, 3, "ai.setAimObject( obj );" )
{
Player *ai = static_cast<Player *>( object );
// Find the target
GameBase *targetObject;
if( Sim::findObject( argv[2], targetObject ) )
ai->setAimObject( targetObject );
else
ai->setAimObject( 0 );
}
/**
* Gets the object the AI is targeting
*/
ConsoleMethod( Player, getAimObject, S32, 2, 2, "ai.getAimObject();" )
{
Player *ai = static_cast<Player *>( object );
GameBase* obj = ai->getAimObject();
return obj? obj->getId(): -1;
}
/**
* Stop the player aiming
*/
ConsoleMethod( Player, clearAim, void, 2, 2, "ai.clearAim();" )
{
Player *ai = static_cast<Player *>( object );
ai->clearAim();
}[/b]That is it. I am sure I have missed something so let me know if you hit some snags. It would also be nice to hear what could be done to improve this code.
:)
#2
04/01/2003 (9:19 pm)
No, the code in ProcessTick will only orient the player towards the bot. If I am passed a null move pointer i use a local move struct to store the players position as returned from getAIMove. I then pass this struct along so that the player is constantly being oriented towards the bot. I thin it might do you some good to look at the attack bot code. This is more what you are looking for.
#3
I did some monkeying around last nite with my code (restored from CVS) and the processTick changes actually did what I generally want it to do. Which is to be able to make the Player class act as an AIPlayer client. :D I click on the terrain ... the avatar runs to it. Unfortunately, it has the side-effect of jerking the camera around. I have a headache trying to fix it ...
Either way, thanks again for this resource. :D
Alex
04/03/2003 (4:14 am)
Hello Kurt,I did some monkeying around last nite with my code (restored from CVS) and the processTick changes actually did what I generally want it to do. Which is to be able to make the Player class act as an AIPlayer client. :D I click on the terrain ... the avatar runs to it. Unfortunately, it has the side-effect of jerking the camera around. I have a headache trying to fix it ...
Either way, thanks again for this resource. :D
Alex
#5
THEN, you need to look in the Player::updateMove code, add if(object) {} and have it set your Z rotation to look at this object.
No, I haven't done it yet, i'm still working on making this, :p
EDIT: The key is to have the CLIENT update the "lock-on", not the SERVER
04/12/2003 (2:58 pm)
The best way to fix the "jerking" is to have the client send a servercmd() to "lockOn" and have the server send back in C++ that he can lock on, and have the client look for an object(in C++) to lock-on too :)THEN, you need to look in the Player::updateMove code, add if(object) {} and have it set your Z rotation to look at this object.
No, I haven't done it yet, i'm still working on making this, :p
EDIT: The key is to have the CLIENT update the "lock-on", not the SERVER
#6
Just the following notes on this resource:
1. The following code
2. The following code must be added to the top of "player.cc":
This resource is very helpfull for me. More so when you combine it with the GodView resource.
Just a note though:
1. Because of the following code from function AIPlayer::isObjectInView(%this, %object, %dist)
2. I still haven't solved the jerking around of the avatar and camera. :(( But thats another issue.
Thanks again for this resource. :D
Alex
04/20/2003 (9:33 am)
Hello Kurt/Everybody,Just the following notes on this resource:
1. The following code
Player::Player()
{
....
....
AimObject = 0;
mAimLocationSet = false;
mTargetInLOS = false;
}must be replaced withPlayer::Player()
{
....
....
mAimObject = 0;
mAimLocationSet = false;
mTargetInLOS = false;
}2. The following code must be added to the top of "player.cc":
#include "core/realComp.h"
This resource is very helpfull for me. More so when you combine it with the GodView resource.
Just a note though:
1. Because of the following code from function AIPlayer::isObjectInView(%this, %object, %dist)
error("**************DISTANCE FROM PLAYER = " SPC %distance);
error("**************sightRange = " SPC %this.sightRange);
if (%distance <= %this.sightRange)
{only bots within 20 units (the value of %this.sightRange) will be selected. I actually modified it it and used 100 for distance checks.2. I still haven't solved the jerking around of the avatar and camera. :(( But thats another issue.
Thanks again for this resource. :D
Alex
#7
This is a great resource, but there is a problem using "SimGroup" to hold their values. Since an object can only exist in one SimGroup at a time, the bots (which hopefully are being added to the missioncleanup group) will be removed from the missioncleanup group when the are added to the totalbot group.
I have switched to using "SimSet" to hold their values and use .add(%bot) and .remove(%bot) to manage the list. While it does require you to remove a bot from one list after adding it to another, using SimSet is better for the overall operation of the engine.
Thanks.
12/20/2004 (9:26 am)
Kurt,This is a great resource, but there is a problem using "SimGroup" to hold their values. Since an object can only exist in one SimGroup at a time, the bots (which hopefully are being added to the missioncleanup group) will be removed from the missioncleanup group when the are added to the totalbot group.
I have switched to using "SimSet" to hold their values and use .add(%bot) and .remove(%bot) to manage the list. While it does require you to remove a bot from one list after adding it to another, using SimSet is better for the overall operation of the engine.
Thanks.
#8
I am going to go back and do it again, but I wanted to see if anyone else had this problem.
02/26/2005 (9:14 pm)
I implemented this code had a problem with the bots in the level. Once this code was implemented the bots could no longer function and they would bring the framerate down to single digits when they noticed the player. They are basically stuck where they spawn and they jump around in circles shooting their weapons. It's pretty funny to watch, but kindof hampers riviting game play ;) I am going to go back and do it again, but I wanted to see if anyone else had this problem.
#9
Was wondering if you ever implemented the code to stop the jerking. I've been working with Torque for about 2 weeks now and have implemented 3 different resources into Torque and I must say i've been having a blast. If anyone else has fixed the jerking, I would love to see how you did it.
03/24/2005 (6:31 am)
Chris:Was wondering if you ever implemented the code to stop the jerking. I've been working with Torque for about 2 weeks now and have implemented 3 different resources into Torque and I must say i've been having a blast. If anyone else has fixed the jerking, I would love to see how you did it.
#10
03/27/2005 (6:46 pm)
I am wondering too. This target locking sounds good for my zelda-style hack n slash.
#11
03/28/2005 (9:01 am)
Exactly what me and a few friends are making also. Been meaning to brush up on Zelda OOT :)
#12
08/10/2005 (6:45 am)
I am wondering also if the jerking issue has been resolved. I cannot seem to figure out how to get rid of the problem myself.
#13
harddrive problems for the lose.
09/30/2005 (8:28 am)
sorry guys been away fer a while and it looks like I've lost my old camera file :|harddrive problems for the lose.
#14
09/30/2005 (9:52 am)
That code didn't seem to change much, but I did get my desired effect by combining "ThirdPersonTargetMode" from the advanced camera resource with locking on to the target at the same time.
#15
Are you saying you were able to get rid of the "jerking" by using ThirdPersonTargetMode from the advanced camera resourse and this resource?
11/20/2005 (12:56 am)
Geo,Are you saying you were able to get rid of the "jerking" by using ThirdPersonTargetMode from the advanced camera resourse and this resource?
#16
For example, in your weapon's OnFire function you could set up the script I've written below. Find the line:
%muzzleVector = %obj.getMuzzleVector(%slot);
Replace that with something like this:
%player = %obj.client.getControlObject();
%target = %obj.client.player.getAimObject(); //you just need to get the objectid of the current target
if (! isObject(%target))
%muzzleVector = %obj.getMuzzleVector(%slot); //this is the standard
else
{
%objPos = %target.getPosition();
%dif = VectorSub(%objPos, %player.getPosition());
%dif = getWord(%dif, 0) @ " " @ getWord(%dif, 1) @ " " @ getWord(%dif, 2);
%dif = VectorNormalize(%dif);
%muzzleVector = %dif; // directs the projectile towards the selected enemy
}
Now your projectiles will go towards your enemy without having to jerk the player towards them. Hope this helps.
-Robert
01/05/2006 (10:34 pm)
Rather than forcing the player to face the bot, wouldn't it be easier to just send the projectile on the correct vector when they fire? This would certainly resolve the jerking effect.For example, in your weapon's OnFire function you could set up the script I've written below. Find the line:
%muzzleVector = %obj.getMuzzleVector(%slot);
Replace that with something like this:
%player = %obj.client.getControlObject();
%target = %obj.client.player.getAimObject(); //you just need to get the objectid of the current target
if (! isObject(%target))
%muzzleVector = %obj.getMuzzleVector(%slot); //this is the standard
else
{
%objPos = %target.getPosition();
%dif = VectorSub(%objPos, %player.getPosition());
%dif = getWord(%dif, 0) @ " " @ getWord(%dif, 1) @ " " @ getWord(%dif, 2);
%dif = VectorNormalize(%dif);
%muzzleVector = %dif; // directs the projectile towards the selected enemy
}
Now your projectiles will go towards your enemy without having to jerk the player towards them. Hope this helps.
-Robert
#17
01/16/2006 (10:53 pm)
anyone tried this with aiGuard?
#18
-Jase
02/09/2006 (10:53 pm)
Nice, I was just getting ready to copy the _exact_ aiPlayer functionality over to the Player class for a prototype I'm working on. Awsome, resource. Saved me some time. :)-Jase
#19
I've been fooling around with this resource as well, and I can't get the avatar to stop jerking. I've fixed the camera using a different camera class, but the avatar isn't cooperating. Any attention would be nice.
-Griff
06/20/2006 (7:00 pm)
Hi,I've been fooling around with this resource as well, and I can't get the avatar to stop jerking. I've fixed the camera using a different camera class, but the avatar isn't cooperating. Any attention would be nice.
-Griff
#20
can this also be used to lock onto things such as shields? (like info boards) thing zelda OoT
*also the link to the bot resource by stefhan doesnt seem to work, anyone got maybe a zip they could send me? (or repare the link- either works) my email is in my profile:)
ps. looks like an amazing resource, wil implement asap
08/17/2006 (2:07 pm)
a quick question:can this also be used to lock onto things such as shields? (like info boards) thing zelda OoT
*also the link to the bot resource by stefhan doesnt seem to work, anyone got maybe a zip they could send me? (or repare the link- either works) my email is in my profile:)
ps. looks like an amazing resource, wil implement asap

Torque Owner Alex \"bathala\" Rufon
Thanks for posting this code ...
I too merged Stefan's AIPlayer bot enhancement with Justin Mette's Orbital Camera and (I forgot his name) someones Object Selection code to make a gameplay similar to NWM and Dungeon Siege. Basically, I want a mouse cursor on the screen and the Player running/attacking whatever I click.
Unfortunately I didn't get it to work ... so I just killed the code YESTERDAY!!!!
Since Im at the office (day job), I couldn't test your code but ... I would just like to know if these codes
void Player::processTick(const Move* move) { PROFILE_START(Player_ProcessTick); // If we´re not being controlled by a client, let the // AI sub-module get a chance at producing a move. Move aiMove; if( move ) getAIMove((struct Move*) move ); else { if( getAIMove( &aiMove ) ) move = &aiMove; } ... ... ... }will now allow my Player class to attack (as specified in Jimomighty's code) a target object when a key is pressed?
Actually, Im excited because the code I just highlighed is actually where I thought I was having trouble with.
Again thanks.
Alex