Advertisement

Entity Interpolation

Started by April 17, 2014 12:27 PM
4 comments, last by hplus0603 10 years, 7 months ago

I'm using the idea from https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking about entity interpolation. I have a javascript game using SignalR for the network traffic. The server sends position updates 5 times a second and I store them in an array via unshift() so the newest position data is at index 0 and I only store 4 elements total. I go back 400 ms for rendering positions.

Then on the client when ready to render I get the interpolated position for each remote client.

The issue is the code I have is creating a rubber band effect. The remote clients do move, but they sort of jerk back and forth. Can anyone see what I may be doing wrong or does a rubber band effect raise any flags about what it could be?


function updateRemoteClients() {
    var currentTime = new Date().getTime();


    // loop over all our remote clients and find the interpolated position to draw them at
    for (var c in remoteClients) {
        var actor = remoteClients[c];
        
        for (var i = 0; i < actor.snapshots.length; i++) {
            // make sure we don't go out of bounds with our checks
            if (i + 1 < actor.snapshots.length) {
                var diff = currentTime - 400 - actor.snapshots[i].timestamp;
                var nextDiff = currentTime - 400 - actor.snapshots[i + 1].timestamp;


                // find the change over from neg to pos which tells us we are between the 2 timestamps we need to look at
                if (diff < 0) {
                    if (nextDiff > 0) {
                        // we have our 2 snapshots to interpolate with
                        var total = actor.snapshots[i].timestamp - actor.snapshots[i + 1].timestamp;
                        var perc = currentTime - 400 - actor.snapshots[i + 1].timestamp;


                        var percentage = perc / total;


                        var ss1 = actor.snapshots[i].position;
                        var ss2 = actor.snapshots[i + 1].position;


                        // calc the interpolated position
                        finalPos = ss1.lerp(ss2, percentage);


                        // set this actors position
                        actor.x = finalPos.x;
                        actor.y = finalPos.y;
                    }
                }
            }
        }
    }
}

Ton of views but no responses. Am I doing something wrong with the way I posted this or do people just not care :)

Advertisement
You haven't shown us what you've done to try to debug the problem, nor have you told us why that particular piece of code would be interesting in context of the bug. Nobody will just read and debug your code for you.

I would suggest logging (to the console) the time stamps that you receive your updates for, and what those positions are, and what timestamps you're trying to generate positions for, and what positions get generated for those time stamps. Then you can compare your log to the behavior you see, and narrow in on the problem.
enum Bool { True, False, FileNotFound };


Nobody will just read and debug your code for you.

Really? I've done that for people before. Not that I haven't been working on it either, but it's small enough code and I think a fairly common task in multiplayer code I was sort of hoping someone saw something strange.

You might want to split it into more functions, so it can be easier maintained and checked for errors:


function interpolateClientState(stateA, stateB, interpolationFactor)
{
	// Interpolate between the two states
	var interpolatedPosition = previousSnapshot.position.lerp(nextSnapshot.position, interpolationFactor);

	// Create interpolated state
	State interpolatedState;

	// Set the position from the state
	interpolatedState.position = interpolatedPosition;
	
	return interpolatedState;
}

function applyState(state, actor)
{
	// ...
}

function updateRemoteClients() {
	var currentTime = new Date().getTime();
	var renderLatency = 400;
	var delayedTime = currentTime - renderLatency;

	// loop over all our remote clients and find the interpolated position to draw them at
	for (var c in remoteClients) {
		var actor = remoteClients[c];
		
		for (var i = 0; i < actor.snapshots.length; i++) {
			// make sure we don't go out of bounds with our checks
			if (!(i + 1 < actor.snapshots.length))
				break;
			
			// Get snapshots
			previousSnapshot = actor.snapshots[i];
			nextSnapshot = actor.snapshots[i + 1];
			
			// Get timestamps
			var previousTimestamp = previousSnapshot.timestamp;
			var nextTimestamp = nextSnapshot.timestamp;

			//  Determine if we straddle the delayed timestamp
			if (!(previousTimestamp < delayedTime) or !(nextTimestamp > delayedTime))
				continue;
				
			// Calculate the factor (0.0 <= factor <= 1.0) to interpolate by
			var interpolationFactor = (delayedTime - previousTimestamp) / (nextTimestamp - previousTimestamp);
			
			// Get new state
			var interpolatedState = interpolateClientState(previousSnapshot, nextSnapshot, interpolationFactor);
			
			// Apply new state
			applyState(interpolatedState, actor);
				
		}
	}
}
 

Be aware this is psuedocode (I can't remember all the Javascript object creation information).

Really? I've done that for people before.


Okay, let me re-phrase that:
- How do you know this particular function is the problem?
- What are the expected inputs, outputs, and state of this function?
With JavaScript this is much harder to determine from the code than with a statically typed language.

If you were to write some unit tests for this function in question, what would they look like?
Actually, do you have any unit tests? If not, perhaps you should start there? :-)
What is the behavior of lerp?
Is your percentage negative?
Are you using any asserts at all?
How did the previous suggestion of logging all the appropriate information to console.log turn out?
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement