Jump to content

Entity interpolation with Pixi.js


ijonatron
 Share

Recommended Posts

Hey everyone! Just joined this forum hoping someone could help me out here...

I'm working on a test project to try out some of these concepts. I'm currently working on entity interpolation and I think I'm pretty close to it working, but the moving objects still seem jittery. On the back end I'm sending snapshots of player positions every 50ms...

// send snapshots
setInterval(() => {
  const snapshot = { timestamp: Date.now(), players };

  ws.clients.forEach(client => {
    client.send(pack('snapshot', snapshot));
  });
}, 50);

These snapshots are being received on the client like so...

const sync = snapshot => {
  // keep the last 2 snapshots
  if (snapshots.length === 2) snapshots.shift();
  snapshots.push(snapshot);

  snapshot.players.forEach(player => {
    let manager = playerManagers.find(mngr => mngr.id === player.id);
    ...
    manager.updateRemote(player);
  });

  t = 0;
};

The manager here is a class instance associated with each player that controls the sprite's position, rotation, etc. Here is that updateRemote method...

updateRemote = player => {
  this.local = this.remote ? this.remote : player;
  this.remote = player;
}

What this does is set the manager's local and remote properties. These are the states that the sprite should interpolate between.

Then here is the Pixi.js ticker...

let t = 0;
ticker.add(() => {
  t += ticker.deltaTime;

  let lag = 50;
  if (snapshots.length >= 2) lag = snapshots[1].timestamp - snapshots[0].timestamp;

  playerManagers.forEach(manager => manager.interpolate(t / lag));
});

Here I am increasing t by the ticker's deltaTime and dividing that by the time between the two snapshots (or the intended time if there aren't two snapshots available). Remember above that t is reset each time a snapshot is received. This means when a snapshot was just received, t will be 0 and start counting up. When another snapshot is received, t will be at 50 (or whatever the real lag is) then be set back to 0 and repeat. In other words, t / lag will be between 0 and 1 for the lerp function...

Here is that interpolate method...

interpolate = delta => {
  this.sprite.position.set(
    lerp(this.local.pos.x, this.remote.pos.x, delta),
    lerp(this.local.pos.y, this.remote.pos.y, delta),
  );

  this.sprite.rotation = lerp(this.local.direction, this.remote.direction, delta);
}

And the lerp function is the second formula here.

 

AFAIK this should give me smooth movement between the past snapshot (local) and the new one (remote), but movement still seems choppy and jittery. I'm fairly new to interpolation, prediction, and other game networking concepts so hopefully someone can help me out here. Please let me know if any more information is needed.

Link to comment
Share on other sites

(-‸ლ)

Just realized I was using the wrong ticker value...

Instead of adding ticker.deltaTime to t I should have been adding ticker.elapsedMS. Still very new to Pixi ? Maybe someone else will have the same problem and find this...

Link to comment
Share on other sites

  • 3 weeks later...

Hey man, I didn't familiar with Pixi.js a lot, but I did my own implementation of lag interpolation in my game.
Maybe it will help you some how.

const MAX_FPS_MS = 1000 / 60


// some class implementation below.

class Renderer {

_fpsThresholdInMs = MAX_FPS_MS; // 60 fps in ms ~16.66666ms
_accumulator = 0; // Accumulates delta times.

render() {
   let dt = this._timer.checkpoint(); // Will get delta between current and prev frames.
   this._accumulator += dt; // Add delta time to accumulator.
   dt = Math.max(dt, this._fpsThresholdInMs); // Set top threshold to 60 FPS.

    if (this._accumulator >= this._fpsThresholdInMs) {
      // RENDER FRAME HERE.

      this._accumulator -= this._fpsThresholdInMs;
       
      // Usually we have delta time equal to 16.6666ms
      // In a case if more, that would be lag or frame degradation.
      // We need to scale speed by lag to predict transformation.
      const dtInterpolationFactor = dt / MAX_FPS_MS;

     // Multiply interpolation factor for any of your game objects transformations.
      scene.update(dtInterpolationFactor);
    }

   // SKIP FRAME.
}
}

I apologise for content quality, I just copied some lines from my project.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...