Weird Run Speeds on Different Computers

For my 2 dimensional Tower Defense game I decided to try it out on a different computer. This turned out to be a disaster… The game runs completely different. randomely lags and everything goes much faster. I am guessing it is the way I do my animations and game loop. Here is the code for the loop:

	public void run() {
		while (inRealGame) {
			if (inGame) {
				if (!isFirst) {
					room.physic();
					mobSpawner();
					for (int i = 0; i < currLevel.mobs.length; i++) {
						if (currLevel.mobs[i].inGame) {
							currLevel.mobs[i].physic();
						}
					}
					if (currLevel.levelOver) {
						getNextLevel(currLevel);
					}
				}
			}
			try {
				Thread.sleep(gameSpeed);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			repaint();

		}
	}

And the way I do my animations is I have two variables and an if loop seeing if the first lvariables has become larger than the other and if it has than set that to zero, switch the image. If not increment the variable by one. Any ideas??

I don’t see anything on this code that could lead to such behaviors, except for Thread.sleep()

You shouldn’t trust that little bugger. He asks for a time, but guess what: He can’t count!
So you should do that for him. In the meantime, check THIS out.

TL;DR:

[quote]Thread.sleep is not always going to be accurate, plus if you’ve got any other threads hogging processor it won’t necessarily allow your thread to resume in time.
[/quote]

Yes, I have read that thread through and through before but I cant figure out why its acting like this!

If gameSleep isn’t much bigger than the actual time spent in your code, you start to notice the different run speeds. You should sleep for (time consumed - time between frames) instead of a fixed time, to get closer to a constant speed. If the difference becomes negative you have a performance problem.

Basically, When you call Thread.sleep(2), it’s not guaranteed it will sleep for 2000ns. Sometimes it will sleep for 1000ns, or 3000ns, or something between or even beyond those values, depending on OS or hardware.
This is why you have to check how much time passed since you last called sleep(), and change the sleep amount to fix the difference between what you want and what you got

PS: Have you tried moving repaint(); to the line before the try/catch block? I just noticed you are rendering stuff after sleeping.

Are you using the time delta between frames to update your game world? I dont see an anything in your code that actually compensates for differences in processing speeds of different computers.

Maybe you could read up on timing, e.g. http://gafferongames.com/game-physics/fix-your-timestep

ahh yes I have heard of this! I knew it had something to do with the different specs of computers and all but I wasnt sure on how to fix it! I shall read up on this and get back to you, thanks

Just subtract the time it took to update the logic and repaint the screen from the “gameSpeed” variable, that is all :stuck_out_tongue:

Which is quite ugly, but it may work, kinda :smiley:

Here’s another good blog post about timing: http://www.koonsolo.com/news/dewitters-gameloop/

Different Operating Systems also have different allowed sleep times. For instance on Older windows you can get a min sleep time of 15MS or worse. On any Operating System the amount of time your thread will sleep will randomly vary as well, sometimes the OS/JVM will just decide now is the time to sleep an extra 30 MS.

What I end up doing for my game loop is counting the time between each loop. and then using a FOR statement that counts down the total time for each 15MS for update logic; so if the thread slept for 30 MS I run twice, if it slept for 5MS I don’t run at that step. However I always draw the screen even if it was too short of a step.

alright so I did some research on the pages suggested, thanks for the links, very helpful! Now I have another question: For one of the game loops I see delta being plugged into the update position method and update player sound and all that stuff… How would I implement that into the for loops that time my animations? Or is there a different way I should be animating?

Variable timesteps in game logic are bonkers, resulting in simulations that aren’t stable. Just avoid the hell out of it and take the framerate hit instead.

Have a look at Eli’s tutorial on game loops! ;D

Sorry for the late reply, had some crazy stuff going on. How would I “take the framerate hit” instead of using variable timestep, which I assume is the loop method that I am using right now.

I think he meant that using a fixed timestep by fixing the framerate. I don’t think you’re using any kind of timestep in your loop at the moment, as far as I can see. In a sense that means you’re using a fixed timestep already, only you’re not limiting the framerate. For example, at some computers your game may run at 60FPS resulting in a timestep for each update of 1/60 = 0.0166 seconds. On another computer your game may run at 120ms, resulting in a timestep for each update of 1/120 = 0.00833 seconds. In other words, the world will change twice as fast when the computer runs twice as fast.

One way to avoid this is by simply limiting the FPS. Which means that on a system that could run 120FPS your game would be limited to 60FPS (and do nothing for the rest of the time). For this I personally I like the loop that r4king’s posted some time ago, it’s here.

Makes total sense now, thank you. The only issue is that in his loop I see “update(delta)”. How do I use delta to change the positions of my mobs, and the animations of things switching images? Here is the moving method for the mobs:


	public void physic() {
		if (walkFrame >= walkSpeed) {
			if (direction == right) {
				x += 1;
			} else if (direction == upward) {
				y -= 1;
			} else if (direction == downward) {
				y += 1;
			} else if (direction == left) {
				x -= 1;
			}

			mobWalk += 1;

			if (mobWalk == Screen.room.blockSize) {
				if (direction == right) {
					xC += 1;
					hasRight = true;
				} else if (direction == left) {
					xC -= 1;
					hasLeft = true;
				} else if (direction == upward) {
					yC -= 1;
					hasUpward = true;
				} else if (direction == downward) {
					yC += 1;
					hasDownward = true;
				}

				if (!hasUpward) {
					try {
						if (Screen.room.block[yC + 1][xC].groundID == Value.groundRoad) {
							direction = downward;
						}
					} catch (Exception e) {
					}
				}

				if (!hasDownward) {
					try {
						if (Screen.room.block[yC - 1][xC].groundID == Value.groundRoad) {
							direction = upward;
						}
					} catch (Exception e) {
					}
				}

				if (!hasLeft) {
					try {
						if (Screen.room.block[yC][xC + 1].groundID == Value.groundRoad) {
							direction = right;
							// mobImage = mobImageStill;
						}
					} catch (Exception e) {
					}
				}

				if (!hasRight) {
					try {
						if (Screen.room.block[yC][xC - 1].groundID == Value.groundRoad) {
							direction = left;
							// mobImage = mobImageStill;
						}
					} catch (Exception e) {
					}
				}
				if (Screen.room.block[yC][xC].airID == Value.airCastle) {
					deleteMob();
					loseHealth();
				}

				mobWalk = 0;
				hasUpward = false;
				hasDownward = false;
				hasLeft = false;
				hasRight = false;
			}
			walkFrame = 0;
		} else {
			walkFrame += 1;
		}
	}

and here is the animation method for an explosion:


public void switchImage(Graphics g) {
		if (animIndex == 0) {
			changeImage(Screen.tileset_explosion[Value.explosion2]);
			animIndex = 1;
			return;
		} else if (animIndex == 1) {
			changeImage(Screen.tileset_explosion[Value.explosion3]);
			animIndex = 2;
			return;
		} else if (animIndex == 2) {
			changeImage(Screen.tileset_explosion[Value.explosion4]);
			animIndex = 3;
			return;
		} else if (animIndex == 3) {
			changeImage(Screen.tileset_explosion[Value.explosion5]);
			animIndex = 4;
			return;
		} else if (animIndex == 4) {
			changeImage(Screen.tileset_explosion[Value.explosion6]);
			animIndex = 5;
			return;
		} else if (animIndex == 5) {
			changeImage(Screen.tileset_explosion[Value.explosion7]);
			animIndex = 6;
			return;
		} else if (animIndex == 6) {
			changeImage(Screen.tileset_explosion[Value.explosion8]);
			animIndex = 7;
			return;
		} else if (animIndex == 7) {
			changeImage(Screen.tileset_explosion[Value.explosion9]);
			animIndex = 8;
			return;
		} else if (animIndex == 8) {
			changeImage(Screen.tileset_explosion[Value.explosion10]);
			animIndex = 9;
			return;
		} else if (animIndex == 9) {
			changeImage(Screen.tileset_explosion[Value.explosion11]);
			inGame = false;
			return;
		}
	}

Those repeated “if” statements hurt my eyes…use an array or something ::slight_smile:
Anyways, can’t you just use a gif?

Yeah man I feel you… Wrote this at like 2:30 and never revised it against my better judgement. Never thought of a using a gif though, mind explaining?

The delta is the timestep, which you need to integrate into your calculations for movement, animation etc so that with a higher FPS the movements and animations take smaller steps (instead of more steps of the same size). Here’s how I would do this in your movement code, for example:


	public void physic(float delta) {
		if (walkFrame >= walkSpeed) {
			if (direction == right) {
				x += WALK_SPEED * delta;
			} else if (direction == upward) {
				y -= WALK_SPEED * delta;
			} else if (direction == downward) {
				y += WALK_SPEED * delta;

// ... and so on

And a slightly different approach in your animation code. Assuming the Value.explosion refers to a sequence of numbers you could write something like:


switchImage(Graphics g, float delta) {
   animationInterval -= delta;
   if (animationInterval <= 0) {
      changeImage(Screen.tileset_explosion[animationIndexValue]);
      animationIndexValue = (animationIndexValue + 1) % NUMBER_OF_ANIMATION_FRAMES;
      animationInterval = ANIMATION_INTERVAL;
   }
}

Now the nice thing about this approach is that you make things like walking and animation speed explicit. This means that by changing values such as ANIMATION_INTERVAL or WALK_SPEED you can tune animation and movement speed. Also, this means that your movement and animation will become independent on processor speed.

One thing to keep in mind, and which has been mentioned before: you can run into problems with this if the delta becomes too big. If you look at the simple calculation above you will see that with a very high delta the character will move a very long distance in one step, which may mean it warps outside of the screen, or right past an obstacle which it should have collided with. The discussions in the blogs that were mentioned earlier in this thread discuss this phenomenon, and how to avoid it (which is most easily done by “fixing” or maximizing the FPS, which puts an upper limit on the value of delta).

Edit: typo