AiPlayer run animation fix
by Manoel Neto · 09/05/2006 (11:23 pm) · 31 comments
In TGE/TSE, AiPlayers seem unable to keep the forward animation playing properly (it keeps resetting, causing a jerky movement, or making the bots "skate" completly) when one of the following conditions are met:
- The bot is moving very slowly;
- The framerate is very low;
- The network is overloaded (lag, packet loss, etc.)
After some debugging, it turned out that AI-controlled players were setting their velocity to (0,0,0) in client-side during some proccessTick() calls, causing the root animation to be played instead of the run one. Since this only happens sometimes, it causes the run animation to reset, and the rate at which zero'ed velocities are generated increases a lot when the bot's speed decreases (as example, when you use the slowDown flag in setMoveDestination), and there are framerate/network performance issues.
The problem happens due to Player::updateMove() being called on AiPlayer ghosts. AiPlayers generate a move in processTick(), but only on the server. On client-side, they are supposed to move based only on velocity/rotation/delta information sent from the server. Since their ghosts never generate moves, updateMove always calculate zero velocities on the client side.
When the framerate is high enough, and when the network isn't lagging, a packet will always arrive with the correct movement information before the AiPlayer can decide which animation to play. But if a packet gets too late, the animation will be decided based on zero velocity (I'm not entirely sure why it simply fails when the AiPlayer is moving slowly enough).
To view the problem, load the starter.fps demo, enter the editor and view kork's ID, then type this on the console:
Now go watch Kork walking around. He can barely play the run animation at that speed, and will mostly "skate" along the path.
To fix the issue, add these mere two lines on top of the Player::updateMove() method in player.cc:
This prevents updateMove from being called on AiPlayer ghosts once for all. Load the starter.fps again and make Kork walk slowly again. He should play the animation without problems now, not matter how slow it's moving.
--EDIT--
With the advent of TGEA 1.7, the fix might cause AiPlayers to not animate when moving randomly. This is caused by mJetting. To fix this, add this to Player::Player():
- The bot is moving very slowly;
- The framerate is very low;
- The network is overloaded (lag, packet loss, etc.)
After some debugging, it turned out that AI-controlled players were setting their velocity to (0,0,0) in client-side during some proccessTick() calls, causing the root animation to be played instead of the run one. Since this only happens sometimes, it causes the run animation to reset, and the rate at which zero'ed velocities are generated increases a lot when the bot's speed decreases (as example, when you use the slowDown flag in setMoveDestination), and there are framerate/network performance issues.
The problem happens due to Player::updateMove() being called on AiPlayer ghosts. AiPlayers generate a move in processTick(), but only on the server. On client-side, they are supposed to move based only on velocity/rotation/delta information sent from the server. Since their ghosts never generate moves, updateMove always calculate zero velocities on the client side.
When the framerate is high enough, and when the network isn't lagging, a packet will always arrive with the correct movement information before the AiPlayer can decide which animation to play. But if a packet gets too late, the animation will be decided based on zero velocity (I'm not entirely sure why it simply fails when the AiPlayer is moving slowly enough).
To view the problem, load the starter.fps demo, enter the editor and view kork's ID, then type this on the console:
(kork id).setMoveSpeed(0.1);
Now go watch Kork walking around. He can barely play the run animation at that speed, and will mostly "skate" along the path.
To fix the issue, add these mere two lines on top of the Player::updateMove() method in player.cc:
if (!getControllingClient() && isGhost())
return;This prevents updateMove from being called on AiPlayer ghosts once for all. Load the starter.fps again and make Kork walk slowly again. He should play the animation without problems now, not matter how slow it's moving.
--EDIT--
With the advent of TGEA 1.7, the fix might cause AiPlayers to not animate when moving randomly. This is caused by mJetting. To fix this, add this to Player::Player():
mJetting = false;The darn thing relied on UpdateMove to get a value, so it used memory garbage instead for fixed AiPlayers. If you want your AiPlayers to jet, you'll need to add mJetting to packUpdate() and unpackUpdate(), as well as set the flag to true in AiPlayer::getAiMove().
About the author
#22
04/20/2007 (8:13 am)
This really helped the movement, thanks! However, it seemed to have caused my bots to get jerky when trying to stay facing each other (with setAimObject()). Hmmmm...
#23
there still jerky movements in the setmovedestination..
02/04/2008 (3:33 am)
Doesnt work for me.. using TGEA with Object selection, advance camera and mouse controlled player resourcesthere still jerky movements in the setmovedestination..
#24
02/05/2008 (1:24 pm)
this worked beautifully - thanks!
#25
Or, you have some other problem....
02/05/2008 (2:19 pm)
@Ariel: Are you sure you implemented it correctly? I've used this fix several times in different versions of TGE and TGEA and it worked fine. Or, you have some other problem....
#26
This problem had been a thorn in my side for a month and to think it was solved by two lines...
Thanks for posting this :)
02/26/2008 (3:13 pm)
Good lord! I can't believe I stumbled upon this! This problem had been a thorn in my side for a month and to think it was solved by two lines...
Thanks for posting this :)
#27
03/11/2008 (8:51 am)
This resource is very helpful. Thanks.
#28
08/06/2008 (7:36 am)
Nice resource ... you get a 5 and thanks for solving my problem with my Zombies ... fools are so slow that don't even know they are animated. :)
#29
01/23/2009 (6:34 pm)
I tried it, but the NPC sometimes walks and sometimes doesnt when i open up the game.
#30
I'll explain the resource a bit more, since that might help those who are integrating other resources or doing their own changes:
What the resource does is prevent updateMove() from being called on non-controlled ghosts. Why? Well, updateMove() takes a move. For Player controlled by a client, these moves are generated from player input (in the client) and sent via network to the server using maximum priority.
For players *not* controlled by a client (AiPlayers), the server generates a move using getAiMove(), but this move is never sent back to clients. An AiPlayer ghost always work with a null move (stopped) on their UpdateMove() calls, and the only thing that keeps them moving and animating is PackUpdate(), which sends variables that override most of the values calculated by UpdateMove(). However, very small velocity values are not sent, and when a packet is missed, the AiPlayer ghost's updateMove() will stop the bot, because it always work with null moves. This causes the stuttering.
But UpdateMove might be doing a few things which don't depend on the move, and that's what can cause issues on a few cases.
Ah! mJetting! This is *not* initialized on the Player constructor, and is *only* updated in UpdateMove(), so it'll keep whatever garbage value it finds in memory when the player is created! Will update the resource description now.
04/24/2009 (7:39 am)
For those facing issues: if there is *any* kind of values being set in Player::updateMove() that isn't sent to clients via Player::packUpdate(), glitches are to happen.I'll explain the resource a bit more, since that might help those who are integrating other resources or doing their own changes:
What the resource does is prevent updateMove() from being called on non-controlled ghosts. Why? Well, updateMove() takes a move. For Player controlled by a client, these moves are generated from player input (in the client) and sent via network to the server using maximum priority.
For players *not* controlled by a client (AiPlayers), the server generates a move using getAiMove(), but this move is never sent back to clients. An AiPlayer ghost always work with a null move (stopped) on their UpdateMove() calls, and the only thing that keeps them moving and animating is PackUpdate(), which sends variables that override most of the values calculated by UpdateMove(). However, very small velocity values are not sent, and when a packet is missed, the AiPlayer ghost's updateMove() will stop the bot, because it always work with null moves. This causes the stuttering.
But UpdateMove might be doing a few things which don't depend on the move, and that's what can cause issues on a few cases.
Ah! mJetting! This is *not* initialized on the Player constructor, and is *only* updated in UpdateMove(), so it'll keep whatever garbage value it finds in memory when the player is created! Will update the resource description now.
#31
Thank's a lot
01/02/2010 (11:47 am)
Really stange... It's still the same issue and solution for T3D 1.01.Thank's a lot

Torque Owner gamer