Smooth mob movement

Hey there JME community,



Recently I've been implementing some mob AI:  specifically, the part

that makes them "chase" a player who aggros a mob and then runs away.

I think I've got it working pretty much as intended, but the on-screen

movement is pretty choppy and I'd like to smooth it out.  I'm betting

that this is a pretty common problem, and that there are some

industry-accepted ways to overcome it.  Please give me some tips, if

anything comes to mind.



Details…



For starters, it's important to note that the game client code is not

responsible for NPC movement:  the server is.  I have an AI thread

(will become a managed pool of threads when I get to it) that loops

every 100 ms and gives each mob a chance to do what its AI tells it to

do.  This isn't the "main game loop" – it's another thread entirely.

It needs to be because, as mentioned, in the future this loop will

actually happen on a completely different hardware node (the game

server).



So right off the bat I'm guessing 100 ms might be too slow for smooth

movement:  if the mob's position needs to update every frame (does

it?), and assuming 60 FPS, you'd want these updates taking place every

16 and 2/3 ms… or roughly 6 times faster than I'm currently doing

them.  But I'm guessing that, long-term, it may be unreasonable to

expect the server to run the AI thread(s) through every mob every 16

ms;  I just picked 100 ms (out of a hat) because it seems more

reasonable.



But honestly I don't think the complexity of this problem stops there.

I'm betting that my "main game loop" thread actually sees updates

from the AI thread even less frequently than 100 ms apart.  I'm

betting that the JVM, in the "main game loop" thread, sometimes

reports coordinates for mobs that are out-of-date… (in other words)

that other threads don't register changes to objects from within the

AI thread quite that quickly.



Should I somehow try to throttle mob movement in the "main game loop"

thread, even though the actual moves are happening in the AI thread,

to match the 60 FPS more closely?  Is that a common strategy?

Determine the direction or location goal of the mob every 100ms, then use a controller to move the mob.

nymon said:

Determine the direction or location goal of the mob every 100ms, then use a controller to move the mob.


Thanks!  :)

This seems to be the way it's done;  after I posted, I got a similar response from someone I know who works in the game industry:


The quick answer is that normally movement and AI thinking processes are split up. So in your case the AI thread at 100ms is a good place to put logic for direction of walking decisions and any pathfinding that might need to happen.  Then in the main loop where normal pawn movement is handled, it looks up the AI thread updated value for direction and speed and will update the movement at the 60fps or main speed.  That way movement is updated fast but decisions about the movement are slower.

In Aeson I created a class called "Actor" which had a variable called destination and a set method for it. During updateGeometricState, if the destination method wasn't null it would look at it and move towards it. If it was close enough, the destination would be set to null.



Here's some pseudocode:


Vector3f myDestination;

public void setDestination(Vector3f v) {
      myDestination = v;
}

updateGeometricState(float tpf, bool initiator){
      //if myDestination isn't null
             //if the distance between my position and my destination is greater than a tolerance
                     //look at the destination and move to it
}



Then in your AI thread you could just call "setDestination" on all of your mobs and the open gl thread would handle everything else.

An addition to the answer above is that you can let the decision making be handled by the server, but instead of sending position data every frame, you let the client run the movement code as well. Along with the decision from the server, (which in your case happens at (10fps) you send a position/rotation update from the server, to make sure they stay synced. In theory the client and server should have calculated the same movement in between, but in those cases they haven't, the client's position/rotation gets overridden by the servers during the update. This would save quite alot of bandwidth. Down side is that it causes rubber banding during lag, but you see this in most online games, i believe. Some interpolation code would remedy the worst of the rubber banding.



I think there should be quite a few articles written on effective network coding on the web, probably a few that handles AI over network as well, due to the MMO-boom.