Constant Animation Speeds

Hello all,

I’m new here, so I apologize in advance if this is irrelevant or obviously answered in another thread. :-\

I’ve been working on a 2D gravity simulator, and I’ve found that when I run the code on my laptop (which is reasonably fast), it goes at the speed that I want it to. However, when I run the code on my PC (which is slow), I find that it goes at about half the speed that I want it to.

The physics for the game is done inside the paint() method of JComponent, which is indirectly called by javax.swing.Timer every 10 milliseconds.

My question is this: Is there any way to animate with Graphics2D so that the animation speed is constant, no matter how fast the computer is? Or, if I’m using the wrong classes for animation, what is a good alternative for what I’m trying to do?

You update your simulation a number of times per second, and draw in the remaining time, if drawing takes too much time you compensate by skipping drawing and updating less.
Search on how to write a good game loop.

The util.timer has been shown to be a better choice than the swing.timer. Chapter two of “Killer Game Programming” compares the two. This chapter also has some good discussion on game loops that don’t use timers.

The big issue with the swing.timer is that everything it does is queued onto the Event Dispatch Thread. This thread can get kind of backed up if there is too much going on. The utility timer creates new threads.

Another issue is that many Microsoft OS setups will only resolve to about 15 or 16 msecs. Thread.sleep(), scheduling for the timer, and System.currentTimeMillis() all suffer from this. System.nanoTime(), in contrast, uses the JVM’s “high resolution time source”. In any event, scheduling the events for every 10ms is kind of problematic. Something more on the range of 60fps is more reasonable (16.6 milliseconds) in terms of fitting with the OS’s that I know about anyway.

A “newish” class might even be a better choice than the utility timer:

[quote=""]
“ScheduledThreadPoolExecutor which is a thread pool for repeatedly executing tasks at a given rate or delay. It is effectively a more versatile replacement for the Timer/TimerTask combination, as it allows multiple service threads, accepts various time units, and doesn’t require subclassing TimerTask (just implement Runnable). Configuring ScheduledThreadPoolExecutor with one thread makes it equivalent to Timer.”

You can set it to recur at the exact interval rather than at a delta interval. Utility timer has this too: use the method sheduleAtFixedRate() instead of schedule().

I would put the physics in its own method. I would have the timer or game loop call an “update()” for the physics and a “render()” for the draw, as two commands. In this case, the render() might only consist of a repaint() for the JComponent being used for the display.

If I recall correctly there’s been some discussion that one should prefer to overwrite paintComponent() instead of paint(). I think there are notes in the API that explain why. It might not matter in your case. I don’t know.

Huh?

I quote from the javadoc:

“Corresponding to each Timer object is a single background thread that is used to execute all of the timer’s tasks, sequentially”

Thanks for the correction.

I do speed in ticks

  @Override
  public void run() {
    long timeNow;
    long lastTime = System.nanoTime();

    final double nsPerTick = 1000000000D / 60D;	// 1 Billion Double

    double delta = 0;

    while (running) {
      timeNow = System.nanoTime();
      delta += (timeNow - lastTime) / nsPerTick;
      lastTime = timeNow;

      // Throttle FPS
      while (delta >= 1) {
        shouldTick = true;
        ticks++;
        tick();
        delta -= 1;
      }
      
      try {
        Thread.sleep(2);
      } catch (InterruptedException ex) {
        Logger.getLogger(Game.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
      }

      render();

      if (tickTime - lastTimeMillis >= 1000) { // One Second has Passed
        lastTimeMillis = tickTime;
       }
    }
 
    stop();
  }

The above example does 60 ticks per second which is easily changeable (just change the nsPerTick “/ 60D” value) and no limit on rendering frames