big performence drop after switching to time corrected movement

up until now, my game (a side scroller) worked on fixed-time movement, meaning the amount of movement done every gameloop iteration was of fixed size.
this was achieved by creating a method Move() in my Entity class, from which all other game entities inherit:
class Entity
{
//…
public void Move()
{
X+=XSpeed;
Y+=YSpeed;
}
}
class Main
{
Entity[] Entities;
public void Move()
{
for(int i=0;i<Entities.length;i++)
{
Entities[i].Move();
}
}
public void Draw()
{
for(int i=0;i<Entities.length;i++)
{
Entities[i].Draw();
}
}
public void run()
{
while(true)
{
Move();
Draw();
try
{
Thread.sleep(1);
}
catch(Exception e)
{
}
}
}
public static void Main(String[] args)
{
Thread t=new thread(this);
t.start();
}
}
(this is just a simplified version, the real move() method is a little more complicated)
now, i know this is isn’t the correct method for doing this, because i move the Entities by a fixed amount regardless of how much time has passed. so i’ve started using time-corrected movement, that meant turning Entity.Move() to
public void Move(float Time)
{
X+=XSpeedTime;
Y+=YSpeed
Time;
}
and calling this method with the Time Difference from the last game loop iteration as an argument.
problem is, when i did this, my performence have dropped significally-
my game loop worked at 2 miliseconds (without rendering), and now it has dropped to 30 miliseconds…
three questions:

  1. what do you think caused the drop? the another argument in the method call, or the extra calculations (they haven’t gotten that complicated when i added the time factor)?.
  2. maybe i’m doing something wrong and i shouldn’t experience such a drop if i work correctly?
  3. maybe it’s worth reverting back to fixed time movement and trying to stabalize the game loop? after all, a 28 milisec difference is quite alot…
    Thanks in advance, and sorry for the extra long post,
    noam :slight_smile:

Don’t rely on System.currentTimeMillis() as it is not accurate (30 ms delay in some OSes, 2ms in others)

Use System.nanoTime() instead, or the Gage Timer, or any other accurate timer.

If you have to stick to currentTimeMillis(), add a “frame step” variable, calculated upon previous frames durations (e.g. sum up the last 100 frames and divide by 100) to your time if it hasn’t changed till the last loop.

Lilian

i’m doing exactly that- summing up the time differences and dividing them by the number of frames passed… the time difference between the first method and the sceond is consistently about 28 milisec…

Which timer are you using ? (it’s not visible from your sample code)

Could you post your full game loop ?

Lilian

not using a timer.
i’m using a while loop that at the end of i call Thread.sleep to prevent starvation… the actuall gameloop looks almost exactly as the one on the example from the first message. the difference is in the Entity.Move(float Time) method. in the real case, it does a little more calculaion than what was shown there, as i have some movement methods that the Move(float Time) method calls, for example, i have a Fly(float Time) method that is called by flying objects. an amphibious creature’s move(float time) method would look something like this:
class Amphibious extends Entity
{
//Override of Entity.Move(float Time)
public void Move(float Time)
{
if(UnderWater())
{
Swim(Time);
}
else
{
Walk(Time);
}
}
}
i hope i’m getiing through… :slight_smile:

Strange you have a loop that depends on a time factor and you don’t use a timer to know how much time has passed… I must be missing something…

Are you using a Thread.sleep(n) where n!= 1 ?

Oh sorry, i misunderstood you. i thought you asked what Timer am i using as a thread, such as java.swing.Timer…
i meausre my time inside Move() in class Main, like so:
class Main
{
long Current;
long Last;
public void Move()
{
Current=system.nanoTime();
Long T=(float)(Current-Last)/10000000;//Convert to milisec
Last=Current;
for(int i=0;i<Entities.length;i++)
{
Entities[i].Move(T);
}
}
}
is this wrong for any reason?

How long do you sleep? Have you tried Thread.yield instead?

Ok it makes more sense.

There are some typos/errors in your sample code :

  • “Last” should be initialized before move()
  • I don’t undersand the use of “long”, I 'd rather use “double” as it’s the format of nanotime() and the type cast to float might be problematic. this is certainly where your problem comes from
  • you should divide by 1e9 or 1e6 to work with seconds or millis, but not 1e7 (certainly a typo)

i don’t have alot of knowledge about when it’s better to cast and when not to.
for example, if i use Math.PI, i usually cast it to a float… i thought that would be easier to process, since you need to preform the operation on fewer Bytes…
and if i have a method that goes like this:
public float DistanceOnX()
{
return (float)Math.sin(angle);
}
would it be faster if turned it to
public doubleDistanceOnX()
{
return Math.sin(angle);
}
?
i thought that because a double was larger than a float it would be faster to return a float and not a double. am i wrong again?

besides that, you’re right- all typos, sorry for being so sloppy :slight_smile:

Some comments about your coding style… Since you are writing Java, it would be best to write in Java style. It would make it easier for others to read your code. Here are the code conventions by Sun: http://java.sun.com/docs/codeconv/

Some coding style things that stick to my eyes from your code:

  • The names of methods and variables should start with a lowercase letter.
  • You should use more blank spaces and empty lines (see chapter 8 in the code conventions).
  • The opening brace should be at the end of the line that begins the compound statement, like this:
    if (condition) {
    statements;
    }
  • Your main method is capitalized and “new thread” has the class name in lowercase?! Shouldn’t those give a compile error?

Also good practice would be (in your run() method) not to catch Exception, but instead InterruptedException or whatever is the actual exception being thrown. Also in most cases leaving a catch block empty is a bad practice.

the format of nanotime() is long.

Hmm, yeah, thread without capital T is rather strange. And what about the Main method? What’s going on?

I know no solution to the problem, but I wouldn’t use a variable time step. The game model should be completely deterministic in my humble opinion, i.e. no random effects from the sleep stuff. One could always introduce corrections for “sleeping over”.

The obvious way to go would be to run a profiler and see where the 28 milliseconds are actually lost.

it’s just an example… surely, with all the lower\upper case mistakes the code wouldn’t compile.

i think you misunderstood me, i’m not using Thread.sleep to try and adjust the speed of the loop, but to prevent other threads starvation. i could have gone and used Thread.yield instead.
anyway, what are you saying? that i should try and stabalize the gameloop, or are you saying i should check how much time has passed and move the objects accordingly?

Oops, I’ve mistaken it with sun.misc.Perf timer :slight_smile:

You could start profiling your app just to have a clue where time is spent… may be in the move() methods ? (I use the netbeans profiler)
Also, are you sure of your 28ms duration… how did you measure it ? and dit you try Thread.yield() instead of sleep() ?

Lilian

yes, im sure. i just save the result i get from nanoTime() and the result before that and subtract the two, than add up the result to another variable that i then devide by the number of runs to get the average time:

LastTime=CurrentTime;
CurrentTime=System.nanoTime();
Sum+=CurrentTime-LastTime;
NumberOfRuns++;
System.out.println(Sum/NumberOfRuns);
Move();

and i’m using yield, and it didnt’ make a difference :slight_smile:

I give up… try to profile your app to know where time is spent …

sorry :frowning:

Lilian

Note that your launcher class should be named identically as your application. Using class main as launcher looks horrible. And I hope your slowdown wasn’t caused by printing on console. System.out … is pretty slow
You could use // for your code until you’d increase frame rate again, however if this will not be tested with drawing on screen, it will be useless.