Thanks legend, that was it.
Using NetworkRigidbody the movement is smooth.
Ran into some new problems with the player screen wrapping + NetworkRigidbody = trail across the screen. Improvised a fix by disabling render for a shot time.
How can the NetworkRigidbody buffer be cleared?
NetworkRigidbody code:
using UnityEngine;
using System.Collections;
public class NetworkRigidbody : MonoBehaviour {
public double m_InterpolationBackTime = 0.1;
public double m_ExtrapolationLimit = 0.5;
internal struct State
{
internal double timestamp;
internal Vector3 pos;
internal Vector3 velocity;
internal Quaternion rot;
internal Vector3 angularVelocity;
}
// We store twenty states with “playback” information
State[ ] m_BufferedState = new State[20];
// Keep track of what slots are used
int m_TimestampCount;
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
// Send data to server
if (stream.isWriting)
{
Vector3 pos = transform.position;
Quaternion rot = transform.rotation;
//Vector3 velocity = Vector3.zero; //rigidbody.velocity;
//Vector3 angularVelocity = Vector3.zero; // rigidbody.angularVelocity;
stream.Serialize(ref pos);
//stream.Serialize(ref velocity);
stream.Serialize(ref rot);
//stream.Serialize(ref angularVelocity);
}
// Read data from remote client
else
{
Vector3 pos = Vector3.zero;
Vector3 velocity = Vector3.zero;
Quaternion rot = Quaternion.identity;
Vector3 angularVelocity = Vector3.zero;
stream.Serialize(ref pos);
//stream.Serialize(ref velocity);
stream.Serialize(ref rot);
//stream.Serialize(ref angularVelocity);
// Shift the buffer sideways, deleting state 20
for (int i=m_BufferedState.Length-1;i>=1;i–)
{
m_BufferedState = m_BufferedState[i-1];
-
}*
-
// Record current state in slot 0*
-
State state;*
-
state.timestamp = info.timestamp;*
-
state.pos = pos;*
-
state.velocity = velocity;*
-
state.rot = rot;*
-
state.angularVelocity = angularVelocity;*
-
m_BufferedState[0] = state;*
-
// Update used slot count, however never exceed the buffer size*
-
// Slots aren’t actually freed so this just makes sure the buffer is*
-
// filled up and that uninitalized slots aren’t used.*
-
m_TimestampCount = Mathf.Min(m_TimestampCount + 1, m_BufferedState.Length);*
-
// Check if states are in order, if it is inconsistent you could reshuffel or*
-
// drop the out-of-order state. Nothing is done here*
-
for (int i=0;i<m_TimestampCount-1;i++)*
-
{*
if (m_BufferedState*.timestamp < m_BufferedState[i+1].timestamp)
_ Debug.Log(“State inconsistent”);_
_ } _
_ }_
_ }*_
* // We have a window of interpolationBackTime where we basically play*
* // By having interpolationBackTime the average ping, you will usually use interpolation.*
* // And only if no more data arrives we will use extra polation*
* void Update () {*
* // This is the target playback time of the rigid body*
* double interpolationTime = Network.time - m_InterpolationBackTime;*
* // Use interpolation if the target playback time is present in the buffer*
* if (m_BufferedState[0].timestamp > interpolationTime)
_ {_
_ // Go through buffer and find correct state to play back*_
* for (int i=0;i<m_TimestampCount;i++)
_ {_
if (m_BufferedState.timestamp <= interpolationTime || i == m_TimestampCount-1)
_ {
// The state one slot newer (<100ms) than the best playback state*
* State rhs = m_BufferedState[Mathf.Max(i-1, 0)];*
* // The best playback state (closest to 100 ms old (default time))_
State lhs = m_BufferedState;*
* // Use the time between the two slots to determine if interpolation is necessary*
* double length = rhs.timestamp - lhs.timestamp;*
* float t = 0.0F;*
* // As the time difference gets closer to 100 ms t gets closer to 1 in*
* // which case rhs is only used*
* // Example:*
* // Time is 10.000, so sampleTime is 9.900*
* // lhs.time is 9.910 rhs.time is 9.980 length is 0.070*
* // t is 9.900 - 9.910 / 0.070 = 0.14. So it uses 14% of rhs, 86% of lhs*
* if (length > 0.0001){*
* t = (float)((interpolationTime - lhs.timestamp) / length);*
* }*
* // Debug.Log(t);*
* // if t=0 => lhs is used directly*
* transform.localPosition = Vector3.Lerp(lhs.pos, rhs.pos, t);*
* transform.localRotation = Quaternion.Slerp(lhs.rot, rhs.rot, t);*
* return;*
* }*
* }*
* }*
* // Use extrapolation*
* else*
* {*
* State latest = m_BufferedState[0];*
* float extrapolationLength = (float)(interpolationTime - latest.timestamp);*
* // Don’t extrapolation for more than 500 ms, you would need to do that carefully*
* if (extrapolationLength < m_ExtrapolationLimit)
_ {
float axisLength = extrapolationLength * latest.angularVelocity.magnitude * Mathf.Rad2Deg;
Quaternion angularRotation = Quaternion.AngleAxis(axisLength, latest.angularVelocity);*_
_ transform.position = latest.pos + latest.velocity * extrapolationLength;
transform.rotation = angularRotation * latest.rot;
* //rigidbody.velocity = latest.velocity;
//rigidbody.angularVelocity = latest.angularVelocity;
}
}
}
}*_