Search Unity

Cubic Spline for Client Side Prediction and Dead Reckoning

Discussion in 'Multiplayer' started by acropole, Jul 20, 2013.

  1. acropole

    acropole

    Joined:
    Aug 13, 2009
    Posts:
    171
    Hi,

    EDIT : I solved some bugs. But I still have problems.
    If I constantly change my direcation, the server update my position and everythings works fine.
    But if I move on the same direction (like pressing only forward) at some point the client goes slower than the server.
    The code :

    Code (csharp):
    1.  
    2. // List of vectors used to calculate curve
    3.     private List<Vector3> m_Positions = new List<Vector3>() { Vector3.zero, Vector3.zero, Vector3.zero };
    4.     public List<Vector3> Positions
    5.     {
    6.         get
    7.         {
    8.             return m_Positions;
    9.         }
    10.         set
    11.         {
    12.             m_Positions = value;
    13.         }
    14.     }
    15. // Times when a new vector is received. Each one is the time for the above corresponfing vector.
    16.     private List<float> m_LocalTime = new List<float>() { 0.0f, 0.0f, 0.0f, 0.0f };
    17.     public List<float> LocalTime
    18.     {
    19.         get
    20.         {
    21.             return m_LocalTime;
    22.         }
    23.         set
    24.         {
    25.             m_LocalTime = value;
    26.         }
    27.     }
    28. // Curve constants
    29.     float[,] P = new float[3,4]{
    30.                     { 0.0f, 0.0f, 0.0f, 0.0f },
    31.                     { 0.0f, 0.0f, 0.0f, 0.0f },
    32.                     { 0.0f, 0.0f, 0.0f, 0.0f }
    33.                 };
    34. // Calculating new curve constants every times a new position is recieved
    35.     public void SetPolynomial(Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3)
    36.     {
    37.         P[0,0] = v3.x - 3.0f * v2.x + 3.0f * v1.x - v0.x;
    38.         P[0,1] = 3.0f * v2.x - 6.0f * v1.x + 3.0f * v0.x;
    39.         P[0,2] = 3.0f * v1.x - 3.0f * v0.x;
    40.         P[0,3] = v0.x;
    41.  
    42.         P[1,0] = v3.y - 3.0f * v2.y + 3.0f * v1.y - v0.y;
    43.         P[1,1] = 3.0f * v2.y - 6.0f * v1.y + 3.0f * v0.y;
    44.         P[1,2] = 3.0f * v1.y - 3.0f * v0.y;
    45.         P[1,3] = v0.y;
    46.  
    47.         P[2,0] = v3.z - 3.0f * v2.z + 3.0f * v1.z - v0.z;
    48.         P[2,1] = 3.0f * v2.z - 6.0f * v1.z + 3.0f * v0.z;
    49.         P[2,2] = 3.0f * v1.z - 3.0f * v0.z;
    50.         P[2,3] = v0.z;
    51.     }
    52. // get one position's float (x, y or z)
    53.     private float GetPosition(float time, int axis)
    54.     {
    55.         return
    56.             P[axis, 0] * Mathf.Pow(time, 3)
    57.             + P[axis, 1] * Mathf.Pow(time, 2)
    58.             + P[axis, 2] * time
    59.             + P[axis, 3];
    60.     }
    61. // get position vector
    62.     public Vector3 GetPosition(float delaTime)
    63.     {
    64.         Vector3 position = new Vector3();
    65.  
    66.         position.x = GetPosition(delaTime, 0);
    67.         position.y = GetPosition(delaTime, 1);
    68.         position.z = GetPosition(delaTime, 2);
    69.  
    70.         return position;
    71.     }
    72.  
    73. // get position vector with time set to current delta time from first vector
    74.     public Vector3 GetPosition()
    75.     {
    76.         float delaTime = Time.time - LocalTime[0];
    77.         return GetPosition(delaTime);
    78.     }
    79.  
    80. // add a new position and recalculate the spline
    81.     public void Add(Vector3 position)
    82.     {
    83.         float
    84.             time = Time.time,
    85.             deltaTime = time - LocalTime[1];
    86.  
    87.         SetPolynomial(Positions[0], Positions[1], Positions[2], position);
    88.         Positions.RemoveAt(0);
    89.         Positions.Add(position);
    90.  
    91.         LocalTime.RemoveAt(0);
    92.         LocalTime.Add(time);
    93.  
    94.         return;
    95. }
    96.  
    97. // Apply position in Update
    98. transform.localPosition = Path.GetPosition(); // Vector3.Slerp(transform.localPosition, transform.localPosition + Velocity / UpdateRate, 1.0f);
    99.  
    100.  
    Code (csharp):
    1.  
    2. // Server update. Only send updates when velocity changes
    3.     public void FixedUpdate()
    4.     {
    5.         if (uLink.Network.isServer)
    6.         {
    7.             LastUpdate++;
    8.             if (LastUpdate >= Path.UpdateRate)
    9.             {
    10.                 // Only send required data
    11.                 bool
    12.                     accelerate = rigidbody.velocity != CurrentSpeed,
    13.                     rotate = rigidbody.angularVelocity != AngularVelocity;
    14.  
    15.                 if (accelerate  rotate)
    16.                     NetworkView.RPC("ServerSendPhysics", uLink.RPCMode.Others, transform.localPosition, transform.localRotation);
    17.                 else if (accelerate)
    18.                     NetworkView.RPC("ServerSendPosition", uLink.RPCMode.Others, transform.localPosition);
    19.                 else if (rotate)
    20.                 {
    21.                     if (Pawn.Controller.PlayerInput.MouseDelta != Vector2.zero)
    22.                         NetworkView.RPC("ServerSendRotation", uLink.RPCMode.Others, transform.localRotation);
    23.                     else NetworkView.RPC("ServerStopRotation", uLink.RPCMode.Others, transform.localRotation);
    24.                 }
    25.                 LastUpdate = 0;
    26.                 CurrentSpeed = rigidbody.velocity;
    27.                 AngularVelocity = rigidbody.angularVelocity;
    28.             }
    29.         }
    30.  
    31.  
     
    Last edited: Jul 21, 2013