Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Entity Interpolation


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
5 replies to this topic

#1 rpiller   Members   -  Reputation: 706

Like
0Likes
Like

Posted 17 April 2014 - 06:27 AM

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;
                    }
                }
            }
        }
    }
}

Edited by rpiller, 17 April 2014 - 06:28 AM.


Sponsor:

#2 rpiller   Members   -  Reputation: 706

Like
-1Likes
Like

Posted 19 April 2014 - 10:33 AM

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



#3 hplus0603   Moderators   -  Reputation: 5723

Like
0Likes
Like

Posted 19 April 2014 - 11:45 AM

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 };

#4 rpiller   Members   -  Reputation: 706

Like
0Likes
Like

Posted 19 April 2014 - 12:29 PM


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.



#5 Angus Hollands   Members   -  Reputation: 722

Like
1Likes
Like

Posted 19 April 2014 - 01:31 PM

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).


Edited by Angus Hollands, 19 April 2014 - 01:32 PM.


#6 hplus0603   Moderators   -  Reputation: 5723

Like
3Likes
Like

Posted 19 April 2014 - 02:35 PM

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?

Edited by hplus0603, 19 April 2014 - 02:37 PM.

enum Bool { True, False, FileNotFound };




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS