   Time-Based Movement Problem
  I'm having issues with my implementation of a time-based movement system. It's not making the player move at the same rate on different computers. The player is moving faster/slower when I run the game on different computers, and I don't understand why...I have a threaded timer calling the movePlayers function separately from the rendering function...I check the time at the end of the function and store it, to use at the beginning of the next time it gets launched.(so I can try to know how much the player should move the next time). Here is the code...clock_t lastFrameTime;void movePlayers(void){clock_t start;start = clock();float delta = (float)(start - lastFrameTime) / CLOCKS_PER_SEC;float distance = (MOVEMENT_SPEED * delta);//printf("%2.5f seconds\n", duration);float moveX;float moveY;int i;for (i = 0; i &lt; 100; i++) {if (players.getMoving() == true) {int direction = players.getDirection();switch (direction) {case DIR_UP:moveY = players.getY() - distance;printf("BACK: %f\n", moveY);if (players.getY() &gt; 0) {players.setY(moveY);if (players.getY() &gt;= (0 + (WINDOW_HEIGHT / 2)) && players.getY() &lt;= ((MAP_SIZE_Y * 32) - (WINDOW_HEIGHT / 2))) {cameras.setCameraOffsetY(WINDOW_HEIGHT - (players.getY() + (WINDOW_HEIGHT / 2)));}}break;case DIR_DOWN:moveY = players.getY() + distance;printf("FORWARD: %f\n", moveY);if (players.getY() &lt; (MAP_SIZE_Y * 32)) {players.setY(moveY);if (players.getY() &lt;= ((MAP_SIZE_Y * 32) - (WINDOW_HEIGHT / 2)) && players.getY() &gt;= (0 + (WINDOW_HEIGHT / 2))) {cameras.setCameraOffsetY(WINDOW_HEIGHT - (players.getY() + (WINDOW_HEIGHT / 2)));}}break;case DIR_LEFT:moveX = players.getX() - distance;printf("BACK: %f\n", moveX);if (players.getX() &gt; 0) {players.setX(moveX);if (players.getX() &gt;= (0 + (WINDOW_WIDTH / 2)) && players.getX() &lt;= ((MAP_SIZE_X * 32) - (WINDOW_WIDTH / 2))) {cameras.setCameraOffsetX(WINDOW_WIDTH - (players.getX() + (WINDOW_WIDTH / 2)));}}break;case DIR_RIGHT:moveX = players.getX() + distance;printf("FORWARD: %f\n", moveX);if (players.getX() &lt; (MAP_SIZE_X * 32)) {players.setX(moveX);if (players.getX() &gt;= (0 + (WINDOW_WIDTH / 2)) && players.getX() &lt;= ((MAP_SIZE_X * 32) - (WINDOW_WIDTH / 2))) {cameras.setCameraOffsetX(WINDOW_WIDTH - (players.getX() + (WINDOW_WIDTH / 2)));}}default:break;}}}lastFrameTime = clock();}This should be moving the players at the same right on all computers, because I'm multiplying the movement speed by the time since the last loop through...I don't understand why it's moving players faster/slower on some computers than on others. If anyone could help me out here, that'd be wonderful.If you need any other details or information about my code, just ask, I'll be happy to supply it. Thanks in advance!   
  You shouldn't assign lastFrameTime to clock() after having done all your movement. When computing the delta you want to know exactly how long it was since you were last there so the proper way to do it is to assign lastFrameTime to start right before giving start a new value. That way lastFrameTime is actually the "start time" from your last frame. Something like:clock_t lastFrameTime;void movePlayers(void){clock_t start;start = clock();float delta = (float)(start - lastFrameTime) / CLOCKS_PER_SEC;   lastFrameTime = start; // Assign lastFrameTime to the current frame time, which will be the last frame time next time we use it....};  Alright, I see your point there. I fixed that though, and the movement speed is still different on my two computers...What could be causing it to be different?   ;  God, how awful. Make the "delta" calcuations out of the loop please.Quote:Original post by Sam GrayThis should be moving the players at the same right on all computers, because I'm multiplying the movement speed by the time since the last loop through...I don't understand why it's moving players faster/slower on some computers than on others. If anyone could help me out here, that'd be wonderful.This is a discrete simulation, not continuous, therefore by measuring the time spent:a) Slow machines will take more time between one frame and the other one; thus delta will be bigger. Suppose Computer A runs at 60fps, Computer B runs at 25fps. Suppose the player moves at 1 meter per second (1 m/s), and we want to move 1m, so that in theory should happen after 1 second After one second, they should've walked 1 meter, but let's see what actually happens:Meters walked in Computer A:Frame 0: 0mFrame 1: 0.016667mFrame 2: 0.033333mFrame 3: 0.05m....Frame 30: 0.5m...Frame 60: 1mMeters walked in Computer B:Frame 0: 0mFrame 1: 0.04mFrame 2: 0.08mFrame 3: 0.12m....Frame 12: 0.48mFrame 13: 0.52m...Frame 25: 1mSo, after 1 second, they should be on the same place, but they don't move exactly the same way. Also note that in computer B, after 0.5 seconds, he didn't travel 0.5 meters, he either traveled 0.48m or 0.52mNow let's add FPS spikes to Computer A. The game is running at 60fps, the antivirus pop up and for 2ms the framerate was waaaaaay low, for example, 0.25fps:Meters walked in Computer A:Frame 0: 0mFrame 1: 0.016667mFrame 2: 0.033333mFrame 3: 0.05m....Frame 30: 0.5m...Frame 59: 0.983333mFPS spike in the midleFrame 60: 4.98333m  ((1/0.25 Frames/s) * 1 m/s + 0.98333)Ooops, due to that spike, the unit ended up doing 4.98333m, while the guy in computer B ended up doing 1m.So, in other words, fix your timestepsI hope this helps youCheersDark SylincEdit: Also you should call clock() after and before rendering and all the other stuff (aka "the game loop"). By doing this inside movePlayers(), you're only measuring the time spent inside movePlayers(), which probably takes the same time in all machines, while the whole thing may be running at different speeds (i.e. 120fps in one machine, 20fps in another)   ;  I'm not certain, but I suspect that your delta is very small since you do very little work when not moving and therefore a lot of frames will pass in a second. While this shouldn't be a problem in an ideal world it could be a problem since clock() may not provide a high enough precision for this kind of movement, and the precision may differ on your two computers. I would try to:1) Limit my framerate to 30FPS (I don't recommend this as a permanent limit, but just to see if this fixes the issue).2) Try printing your information such as "FORWARD: .." to a file instead of the console. Printing to a console will result in significant slow down which gives you a very uneven delta. If you're on a platform where you know how to perform an asynchronous write to the console that would work as well.Anyway how big are your discrepancies? It might help if you posted the output of the two sessions so we can see how they differ.   ;  I read the stuff in the link you sent me Matias, and I've updated my code. It's still not working correctly though...And I don't see how I can take out the delta time calculations from the movePlayers function. Also, the reason I don't call the clock() stuff before and after the entire rendering loop, is because it's handled by a separate timer as the movePlayers function is on...so I don't see why I should. I have one timer for the movePlayers function, and another to update(re-render) the screen.Here is my updated movePlayers code, that still doesn't work correctly...It's still giving different speeds on different computers. I also have tired commenting out the printf statements to see if that messed with the speed, it didn't change anything.I'm not completely sure if I implemented what you linked me to Matias correctly. This is my first time trying to do something like this, so I apologize for my noobiness. lolvoid movePlayers(void){const float dt = 0.01f;clock_t currentTime = clock();float accumulator = 0.1f;float delta = (float)(currentTime - lastFrameTime) / CLOCKS_PER_SEC;lastFrameTime = currentTime;accumulator += delta;float distance = (MOVEMENT_SPEED * delta);//printf("%2.5f seconds\n", duration);float moveX;float moveY;while (accumulator >= dt){accumulator -= delta;int i;for (i = 0; i < 100; i++) {if (players.getMoving() == true) {int direction = players.getDirection();switch (direction) {case DIR_UP:moveY = players.getY() - distance;printf("BACK: %f\n", moveY);if (players.getY() > 0) {players.setY(moveY);if (players.getY() >= (0 + (WINDOW_HEIGHT / 2)) && players.getY() <= ((MAP_SIZE_Y * 32) - (WINDOW_HEIGHT / 2))) {cameras.setCameraOffsetY(WINDOW_HEIGHT - (players.getY() + (WINDOW_HEIGHT / 2)));}}break;case DIR_DOWN:moveY = players.getY() + distance;printf("FORWARD: %f\n", moveY);if (players.getY() < (MAP_SIZE_Y * 32)) {players.setY(moveY);if (players.getY() <= ((MAP_SIZE_Y * 32) - (WINDOW_HEIGHT / 2)) && players.getY() >= (0 + (WINDOW_HEIGHT / 2))) {cameras.setCameraOffsetY(WINDOW_HEIGHT - (players.getY() + (WINDOW_HEIGHT / 2)));}}break;case DIR_LEFT:moveX = players.getX() - distance;printf("BACK: %f\n", moveX);if (players.getX() > 0) {players.setX(moveX);if (players.getX() >= (0 + (WINDOW_WIDTH / 2)) && players.getX() <= ((MAP_SIZE_X * 32) - (WINDOW_WIDTH / 2))) {cameras.setCameraOffsetX(WINDOW_WIDTH - (players.getX() + (WINDOW_WIDTH / 2)));}}break;case DIR_RIGHT:moveX = players.getX() + distance;printf("FORWARD: %f\n", moveX);if (players.getX() < (MAP_SIZE_X * 32)) {players.setX(moveX);if (players.getX() >= (0 + (WINDOW_WIDTH / 2)) && players.getX() <= ((MAP_SIZE_X * 32) - (WINDOW_WIDTH / 2))) {cameras.setCameraOffsetX(WINDOW_WIDTH - (players.getX() + (WINDOW_WIDTH / 2)));}}default:break;}}}}};Quote:Original post by Sam GrayHere is my updated movePlayers code, that still doesn't work correctly...I'm not completely sure if I implemented what you linked me to Matias correctly. This is my first time trying to do something like this, so I apologize for my noobiness. lolMmm, nope you got it wrong, actually you just got the less important part of article.The important thing was that your loop should be using a fixed number (i.e. 1/60.0f or 1/30.0f or 1/25.0f) instead of using the function "clock()".Your framerate is still variable, while the point of the article is to make your framerate fixed.Quote:Original post by Sam Gray(...)I don't see how I can take out the delta time calculations from the movePlayers function. Also, the reason I don't call the clock() stuff before and after the entire rendering loop, is because it's handled by a separate timer as the movePlayers function is on...so I don't see why I should. I have one timer for the movePlayers function, and another to update(re-render) the screen.Here:clock_t start;start = clock();while( !bExit ){float delta = (float)(lastFrameTime - start) / CLOCKS_PER_SEC;start = lastFrameTime;   float accumulator += delta;    while (accumulator >= 1/60.0f)    {update( 1/60.0f );accumulator -= 1/60.0f;    }render( delta );   lastFrameTime = clock();}void update( float timeSinceLast ){movePlayers( timeSinceLast );//Some other stuff//...}void movePlayers( float delta ){float distance = (MOVEMENT_SPEED * delta);//The rest is the same...}I just wrote it so it may not compile 100%, but I hope you get the idea.You pass the "delta" to movePlayers as an input argument you get from the update loop.Remember, in the whole game you should be calling clock() at startup and then ONCE per frame: at the end. If you're calling it more often, you're doing something wrong (unless you're doing some profiling to your code, but let's just keep it there)CheersDark Sylinc[Edited by - Matias Goldberg on May 25, 2010 3:55:36 PM];  delta will be negative above...and lastFrameTime is undefined first call.. is that what you want ?   ;Quote:Original post by mrrdelta will be negative above...Fixed, thanks.Quote:Original post by mrrand lastFrameTime is undefined first call..Well, I am guiding how to do it, doesn't have to be pure working C++ out of the box expecting me to do his homework.For instance, I never declare bExit nor is it ever set to false.CheersDark Sylinc   ;  Ok, I see your points now Matias. It all makes sense to me now...but it's still not working correctly. It's still giving different speeds on different computers. Here is my updated code:void drawToScreen(void){clock_t start;start = clock();lastFrameTime = clock() + 2;while (1 > 0){float delta = (float)(lastFrameTime - start) / CLOCKS_PER_SEC;start = lastFrameTime;float accumulator = 0.0;accumulator += delta;while (accumulator >= 1.0/60.0) {movePlayers(1.0/60.0);accumulator -= 1.0/60.0;}glutPostRedisplay();lastFrameTime = clock();}}I'm using the drawToScreen function to put my non-ending loop in. The movement code just calculates the distance(MOVEMENT_SPEED * delta) and moves the players accordingly...however it's still moving players at different rates on different computers.   