Monday, August 8, 2011

Enhancement: Smoother Movement

A while ago I found an article while searching for reasons why some of my movement code was a bit choppy and had some jitter problems. I found this article Fix Your Timestep! it's a bit abrupt but it has helped. While I wasn't able to completely fix the propagation errors since I haven't mastered the interpolation concept completely or how exactly to work it into my designs.


The Concept

Make sure that your game updates only in discrete blocks as to not cause erroneous errors in movement and to account for time missed or wait until time has accumulated.

The interpolation

Used to compensate for formula errors in translational movement which add up overtime eventually causing objects to be positioned unrealistically. Though I haven't figured out how different it makes things using interpolation versus without it.

The Code

I took the Character 8 directional-movement snippet and changed the updating thread code, check it out, not perfect but much better than it was before works pretty well at least on my PC.

// our main task for handling the rendering and for updating and
  // handling input and movement events.
  renderTask = new Thread() {
   // no local variables in a constant loop.
   long lasttime = -1;
   long msDelta  = 0;
   double dt   = 0.01;
   long time;
   double deltaTime = 0;
   double accumulator = 0;

   @Override
   public void run() {
    final Object sync = new Object();
    while (true) {
     synchronized (sync) {
      // use nano time, for more accuracy
      time = System.nanoTime();

      // record the initial last time
      if (lasttime == -1) {
       lasttime = time;
      }

      // delta in milliseconds
      msDelta = (long) ((time - lasttime) * 0.000001d);
      
      // delta in seconds
      deltaTime = (time - lasttime) * 0.000000001d;

      // cap the number of update loops needed to keep up with
      // high frame-rates.
      if (deltaTime > 0.25) {
       deltaTime = 0.25;
      }

      lasttime = time;

      accumulator += deltaTime;

      // accurate update rates, loop for each fixed 
      while (accumulator > deltaTime) {
       update(dt);
       accumulator -= dt;
      }

      //check to make sure that the renderstrategy is valid
      if(SmoothMovement.this.isShowing()) {
       render();
      }

      // if there is any time left due to quick updating and
      // rendering then the thread can sleep
      long timeLeft = (10 - msDelta);
      if (timeLeft > 0) {
       try {
        sync.wait(timeLeft);
       } catch (InterruptedException e) {
       }
      }
     }
    }

   }
  };

Give it a Try

Test it out for yourself and let me know if you still find jitter or notice any places for improvement. I try to always look for ways to improve code and will go back to code I've done previously and see a lot of new optimization's I can make.

Full Source

Here's the whole file for you to take a look at.

No comments:

Post a Comment