Tpf and movement speed

Hi all

Here's a section of my update() method that moves the player character:

Vector3f loc = playerNode.getLocalTranslation();
Vector3f testloc = new Vector3f(loc.x, loc.y, loc.z);
Vector3f rot = playerNode.getLocalRotation().toRotationMatrix().getColumn(2);
rot.y = 0f;
testloc.addLocal(rot.multLocal((64f * tpf)));
if(!world.detectCollision(testloc)) {
    loc.addLocal(rot.multLocal((64f * tpf)));

I basically add a distance in the direction the player is facing to a test Vector3f. I use this to test for collisions, and then move the player if there was no collision. All good. However, in low fps areas (like my shader vegetation areas - 40fps) the player moves super fast and in high fps areas (100fps+) the player moves as intended.

I understood that tpf would give me the time between frames and therefore if a frame was taking longer to render then the player would need to move further. Hence the 64f * tpf. Have I got it all wrong ?



no, you're right. constantvelocity*tpf = distance to move. (it does not work for accelerated movements.)

possible causes for your bug:

  • check if tpf is correct (maybe you are calling update on the timer at a wrong place) and the method is called only once per frame
  • you're using the players local translation elsewhere. when calling getLocalTranslation(), every modification to the returned vector results in a change of the nodes position. therefore, the last line of your code does absolutely nothing.

This question already has been asked a lot, i don't know the answer, maybe try searching for it. But logically, if distance * tpf on a high framerate is low, and vice versa, what about dividing?

@SeySayux - I'm pretty sure distance * tpf is correct. Also, sorry if this has been asked before, I couldn't find anything conclusive when searching the forums.

@Hamster - Thanks for this. You're absolutely right, the last line does nothing :wink: As far as calls to the timer go, I extend SimplePassGame so that's all taken care of for me. Is it possible that the tpf calculation is being "smoothed" by the engine at all ? It seems that the increase in distance covered by the player is just after the low fps areas as if it is trying to compensate after the bad fps area has been negotiated.


Is it possible that the tpf calculation is being "smoothed" by the engine at all ?

yes, it is. the tpf is "fluctuating" when changing from low to high fps according to another thread i'm too lazy to look for, but this would not explain a constant different in speed.

I think however that it might explain my issue. The change in fps between the two areas that I am "walking" is so marked that I think the "smoothing" is not keeping up. I need a more immediate change. Is there any way to turn the "smoothing" off ?


You can set your timer field to a new instance of NanoTimer.

Well, introducing a NanoTimer makes no difference to my issue. It's a really odd one.

Edit: Right, this is crazy ! I tried to fraps it for you guys, but the decrease in fps when frapsing only demostrated the issue even clearer. When I have a low fps, I run very fast over my terrain, when I have a high fps I move at the speed I want to move at. Something very strange is happening here.


Ok, here's where I'm now at …

If I just run around on my terrain with a constant FPS of around 100, I run at the speed I want to. It's a good speed that matches the animation and everything looks good.

If I start up some background process on my PC (in my case a Paint Shop Pro image slice) just to take up a bit of CPU, my FPS drops to around 15 FPS and I run across the terrain like a mad thing !

My formula for the distance to move is as we discussed above: 64f * nanotpf

Wherer nanotpf is got from a call to getTimePerFrame() on my NanoTimer.

I've system outed the nanotpf value and it seems totally valid. Higher nanotpf for a lower FPS.

I'm totally out of ideas now guys.


Curiouser and curiouser …

If I split out a portion of the movement math to be a static amount and only use the tpf for part of the movement math, I get a very similar movement speed across all FPS's:

0.5f + (24f * nanotpf)

Insane !

i know this probably isnt the cause of ur problem. but it might help u get around it.

use the formula direction(unit vector) * speed * tpf = change in distance per frame.

then add the change to the local translation.

this is what im using, and it works fine in all kinds of conditions.

Makaveli said:

Curiouser and curiouser ...

If I split out a portion of the movement math to be a static amount and only use the tpf for part of the movement math, I get a very similar movement speed across all FPS's:

0.5f + (24f * nanotpf)

Insane !

try adding one and ignore the  the tpf.

@Hamster - tpf is going to have to come into play somewhere otherwise the player really slows down in low FPS areas.

@neakor - this is exactly what I am doing.

The directional vector is normalized:

Vector3f rot = playerNode.getLocalRotation().toRotationMatrix().getColumn(2);
rot.y = 0f;

Then I multipy by the speed (64f) and tpf:

rot.multLocal((64f * tpf))

I think the very fact that you're having success using the same thing means that I must have an issue elsewhere. Though I can't see why that would be the case. It's all pretty straightforward.

Thanks anyway guys


let me rephrease my suggestion:

when something is totally weird, my first step is to ask for help. the second one is to give the X which is acting weird random/arbitrary input and see how it reacts to deduce what it's actually doing.

if tpf64 gives you worse results than 0.5+32tpf, i'd try what happend if i simply add 1.

my guess:

your move method is called at constant intervals, independent from the framerate, and tpf is still depenend on it. this would explain the behaviour.

Thanks Hamster

I use the same technique myself. Hence the (0.5 + 32*tpf). I've tried simply putting a fixed movement in there. I tried to simply add 1 and it behaved as I'd expect. Fast in high FPS areas, slow movement in low FPS areas.

As for the method being called at constant intervals, that's a really nice guess. However, it's all handled in simpleUpdate() which I understand was called each frame.

Thanks for the continued interest though Hammy.

maybe. there are some simplegame-classes which call it in constant intervals while spamming calls on render.

As you say, it would certainly explain my problem. However, I'm pretty sure that SimplePassGame calls simpleUpdate() with every frame update.