2D Beat´em Up synchronization issue

Hello,

I am currently working on a 2.5D Beat´em Up/Brawler using Photon Cloud/Server and ran into some problems with the multiplayer synchronization.

At this moment in development the clients are completely responsible for moving and are updating their position using a custom script which is observed via a PhotonView component.

The problem is that with my current implementation the movement is more or less accurate but the transition(lerp) between the different updates is not optimal. Especially in this kind of action-paced game I need to display a smooth movement with as accurate as possible positioning.

This is the script I am using right now:

using UnityEngine;
using System.Collections;

public class NetworkedPlayer : Photon.MonoBehaviour
{
	// how far back to rewind interpolation?
	public float InterpolationBackTime = 0.1f;

	// a snapshot of values received over the network
	private struct networkState
	{
		public Vector3 Position;
		public double Timestamp;

		public networkState( Vector3 pos, double time )
		{
			this.Position = pos;
			this.Timestamp = time;
		}
	}

	// we'll keep a buffer of 20 states
	networkState[] stateBuffer = new networkState[ 20 ];
	int stateCount = 0; // how many states have been recorded

	void Update()
	{
		Debug.Log (PhotonNetwork.sendRate);
		Debug.Log (PhotonNetwork.sendRateOnSerialize);
		if( photonView.isMine == true ) return; // don't run interpolation on the local object
		if( stateCount == 0 ) return; // no states to interpolate

		double currentTime = Network.time;
		double interpolationTime = currentTime - InterpolationBackTime;


		// the latest packet is newer than interpolation time - we have enough packets to interpolate
		if( stateBuffer[ 0 ].Timestamp > interpolationTime )
		{
			for( int i = 0; i < stateCount; i++ )
			{
				// find the closest state that matches network time, or use oldest state
				if( stateBuffer[ i ].Timestamp >= interpolationTime || i == stateCount - 1 )
				{
					// the state closest to network time
					networkState lhs = stateBuffer[ i ];

					// the state one slot newer
					networkState rhs = stateBuffer[ Mathf.Max( i - 1, 0 ) ];

					// use time between lhs and rhs to interpolate
					double length = rhs.Timestamp - lhs.Timestamp;
					float t = 0f;
					if( length > 0.0001 )
					{
						t = (float)( ( interpolationTime - lhs.Timestamp ) / length );
					}

					transform.position = Vector3.Lerp( lhs.Position, rhs.Position, t );

					break;
				}
			}
		}
	}

	void OnPhotonSerializeView( PhotonStream stream, PhotonMessageInfo info )
	{
		Vector3 position = Vector3.zero;
		if( stream.isWriting )
		{
			position = transform.position;
			stream.Serialize( ref position );
		}
		else
		{
			stream.Serialize( ref position );
			bufferState( new networkState( position, info.timestamp ) );
		}
	}

	// save new state to buffer
	void bufferState( networkState state )
	{
		// shift buffer contents to accomodate new state
		for( int i = stateBuffer.Length - 1; i > 0; i-- )
		{
			stateBuffer[ i ] = stateBuffer[ i - 1 ];
		}

		// save state to slot 0
		stateBuffer[ 0 ] = state;

		// increment state count (up to buffer size)
		stateCount = Mathf.Min( stateCount + 1, stateBuffer.Length );
	}
}

Using such a buffer system is my latest attempt to fight the latency/laag issues.
I guess that this will work for a 3D game just fine, but tweaking the interpolationBackTime did not get me acceptable results.

Do you have any tips what I might add/change in order to get it working properly?

Additional info: My player has a rigidbody2D and gets moved by changing it´s velocity value.

Thanks,

CineTek

Tweaking interpolationBackTime is not what you need to do. You need to add extrapolation.