Getting Ai to Use Poses
by Steve Acaster · 08/04/2011 (9:42 am) · 12 comments
Disclaimer: WestCoastCollege was instrumental in helping me work this out as I was sticking my code in the wrong place - so it's not all my own work.
2nd Disclaimer: I thought this was already a resource ... but apparently it isn't.
First up, let's expose the stock getPose function to script so we have an easy way to find out what pose the Ai is already in. At the end of player.cpp add:
[edit 17 oct 12] Apparently this defineEngineMethod is now in stock 1.2
Now open up AiPlayer.cpp, and near the end of AIPlayer::getAIMove function:
Expose this new function to script:
And finally declare the new function at the end AiPlayer.h:
So, you can now set the pose of an Ai by using:
[edit 17 oct 12] www.garagegames.com/community/forums/viewthread/130955/1#comment-831144 should fix the issues listed below
Now let's talk about issues with it not working as desired:
The main one is that there seems to be some sort of hiccup in the passing of the actual animation, so whilst the the boundingbox resizes correctly, the animation requires a "bump". This has been reported and confirmed as a bug.
But in the meantime, we'll use a workaround and "jumpstart" the animation.
It's the setTransform at the end which helps to "jumpstart" the animation into the new pose, and it also helps if there is a slight delay - hence the schedule.
And there you go, you can now change the Ai's pose (as long as the model is set up with the correct animation0 by using any of the following:
This also helps prevent previous issues where having a "prone-able" Ai could see them default to prone instead of standing.
2nd Disclaimer: I thought this was already a resource ... but apparently it isn't.
First up, let's expose the stock getPose function to script so we have an easy way to find out what pose the Ai is already in. At the end of player.cpp add:
[edit 17 oct 12] Apparently this defineEngineMethod is now in stock 1.2
//yorks
DefineEngineMethod( Player, getPose, S32, (),,
"0=standPose, 1=crouchPose, 2=pronePose, 3=swimPose" )
{
return object->getPose();
}Now open up AiPlayer.cpp, and near the end of AIPlayer::getAIMove function:
/...
// Replicate the trigger state into the move so that
// triggers can be controlled from scripts.
for( int i = 0; i < MaxTriggerKeys; i++ )
{
movePtr->trigger[i] = getImageTriggerState(i);
//yorks in start
switch (mPose)
{
case StandPose:
movePtr->trigger[3] = false;
movePtr->trigger[4] = false;
break;
case CrouchPose:
movePtr->trigger[3] = true;
movePtr->trigger[4] = false;
break;
case PronePose:
movePtr->trigger[3] = false;
movePtr->trigger[4] = true;
break;
}
//yorks in end
}
mLastLocation = location;
return true;
}
//yorks - new function!
void AIPlayer::changePose(S32 poseNumber)
{
Pose Pose = StandPose;
if(poseNumber == 1)
{
Pose = CrouchPose;
}
else if(poseNumber == 2)
{
Pose = PronePose;
}
setPose(Pose);
}
//yorksExpose this new function to script:
//yorks
ConsoleMethod( AIPlayer, setPose, void, 3, 3, "()"
"(int pose) StandPose=0,CrouchPose=1,PronePose=2")
{
object->changePose(dAtoi(argv[2]));
}Anyone want to change my ConsoleMethod to a DefineEngineMethod feel freeAnd finally declare the new function at the end AiPlayer.h:
//... void stopMove(); void changePose(S32 poseNumber);//yorks }; #endif
So, you can now set the pose of an Ai by using:
//set the pose! %myBotID.setPose(%pose); //and return the pose %myBotID.getPose();
[edit 17 oct 12] www.garagegames.com/community/forums/viewthread/130955/1#comment-831144 should fix the issues listed below
Now let's talk about issues with it not working as desired:
The main one is that there seems to be some sort of hiccup in the passing of the actual animation, so whilst the the boundingbox resizes correctly, the animation requires a "bump". This has been reported and confirmed as a bug.
But in the meantime, we'll use a workaround and "jumpstart" the animation.
function AiPlayer::doStand(%this)
{
echo(%this.getname() @ " AiStand");
if(%this.getPose() != 0)
{
%this.setPose(0);
%this.schedule(50, "kickStartPose", 0);
}
}
function AiPlayer::doCrouch(%this)
{
echo(%this.getname() @ " AiCrouch");
if(%this.getPose() != 1)
{
%this.setPose(1);
%this.schedule(50, "kickStartPose", 1);
}
}
function AiPlayer::doProne(%this)
{
echo(%this.getname() @ " AiProne");
if(%this.getPose() != 2)
{
%this.setPose(2);
%this.schedule(50, "kickStartPose", 2);
}
}
//and our kickstart bugfix workaround solution
function AiPlayer::kickStartPose(%this, %pose)
{
echo("kickstart pose " @ %pose);
if(%pose == 0)
%this.setPose(0);
if(%pose == 1)
%this.setPose(1);
if(%pose == 2)
%this.setPose(2);
%this.setTransform(%this.getTransform());
}It's the setTransform at the end which helps to "jumpstart" the animation into the new pose, and it also helps if there is a slight delay - hence the schedule.
And there you go, you can now change the Ai's pose (as long as the model is set up with the correct animation0 by using any of the following:
%myBotId.doStand(); %myBotId.doCrouch(); %myBotId.doProne();
This also helps prevent previous issues where having a "prone-able" Ai could see them default to prone instead of standing.
About the author
One Bloke ... In His Bedroom ... Making Indie Games ...
#2
08/04/2011 (12:48 pm)
Nice work Steve, works great.
#3
http://www.garagegames.com/community/forums/viewthread/115567
was deleted and all of the post made with it were also deleted so you wont find it by searching, or all the hundred other things I posted :(
08/05/2011 (12:35 am)
@Steve the account I used to reply to your other post: http://www.garagegames.com/community/forums/viewthread/115567
was deleted and all of the post made with it were also deleted so you wont find it by searching, or all the hundred other things I posted :(
#4
Anyhow, accreditation where it belongs unlike LA Noire ...
08/05/2011 (7:08 am)
That'll explain why when I found that thread it looked like I was talking to myself ... which confused me slightly ...Anyhow, accreditation where it belongs unlike LA Noire ...
#5
Thanks!
NB: I read at over 500 wpm....lol.....
08/07/2011 (6:22 am)
...you know me, Steve, I have to ask: does this work across the network? Single Player is 'fine', MultiPlayer is FTW! Can I be on a dedicated server and have this work?Thanks!
Quote:%myBotId.doStand);.....missing opening parenthesis of 'doStand' function.
NB: I read at over 500 wpm....lol.....
#6
I suppose a foolproof way would be to call the pose change as a serverCommand.
Easiest way to find out is to test! I've only got the one box ...
And typo fixed.
08/07/2011 (7:57 am)
It should work over a network as it's updating inside the Ai Class getAiMove function - plus the Ai are going to be on the server and not the client.I suppose a foolproof way would be to call the pose change as a serverCommand.
commandToServer('AiStand', %botID);
function serverCmdGoStand(%client, %ai)
{
%ai.AiStand();
}Easiest way to find out is to test! I've only got the one box ...
And typo fixed.
#7
08/07/2011 (10:58 pm)
Nice work Steve =) Handy resource!
#8
08/09/2011 (9:53 am)
Great tutorial on AI Steve. :)
#9
Works great and yes, it works fine with UAISK ... for those using it.
I just had my AI "crouch" after getting hit, if they can't find cover.
11/22/2011 (11:25 am)
Steve @ Player::getPose is already a defined engine method in T3D 1.2 (fyi) ... testing out the rest of this resource.Works great and yes, it works fine with UAISK ... for those using it.
I just had my AI "crouch" after getting hit, if they can't find cover.
#10
Note: Guy Allard's update warp fix means that you no longer have to call via serverCommand nor use the setTransform() workaround.
10/16/2012 (6:20 pm)
www.garagegames.com/community/forums/viewthread/130955/1#comment-831144Note: Guy Allard's update warp fix means that you no longer have to call via serverCommand nor use the setTransform() workaround.
#11
" it also helps if there is a slight delay - hence the schedule."
steve,
just for curiosity,in which cases there would be delay?
02/28/2013 (9:38 am)
function AiPlayer::doProne(%this)
{
echo(%this.getname() @ " AiProne");
if(%this.getPose() !$= "Prone")
{
%this.setPose(2);
//%this.schedule(50, "kickStartPose", 2);
%this.setTransform(%this.getTransform());
}
}without schedule it is working fine." it also helps if there is a slight delay - hence the schedule."
steve,
just for curiosity,in which cases there would be delay?
#12
but it failed to work with t3d 2.0
after adding "Guy Allard's update warp fix" it is now working.
so to make it work with t3d 2.0 we have to use that fix instead of script side fix.
02/28/2013 (6:35 pm)
with script side fix it was working fine in t3d 1.2but it failed to work with t3d 2.0
after adding "Guy Allard's update warp fix" it is now working.
so to make it work with t3d 2.0 we have to use that fix instead of script side fix.

Torque Owner Robert Fritzen
Phantom Games Development