Search Unity

  1. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Let us know a bit about your interests, and if you'd like to become more directly involved. Take our survey!
    Dismiss Notice
  4. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  5. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Unity Multiplayer Rigidbody sync

Discussion in 'Connected Games' started by Daniiii, Oct 7, 2015.

  1. Daniiii

    Daniiii

    Joined:
    Nov 13, 2013
    Posts:
    11
    Hi, I got a question about how to sync a rigidbody using Unet.
    My setup: Player-characters (syncing fine) and a ball, all with rigidbodies. The players should be able to push the ball around.
    When using a networktransform with syncrigidbody on the ball and a remote clients tries to push the ball, it doesn't work because the position gets set by the server.


    I found the NetworkRigidbody script using the old Unity networking system
    and I tried editing it to get it to work with Unet, but to no avail.

    What is the general way to sync rigidbodies using unet/which general things would one need to change in the NetworkRigidbody script?
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class NetworkRigidbody : MonoBehaviour
    5. {
    6.  
    7.     public double m_InterpolationBackTime = 0.1;
    8.     public double m_ExtrapolationLimit = 0.5;
    9.  
    10.     internal struct State
    11.     {
    12.         internal double timestamp;
    13.         internal Vector3 pos;
    14.         internal Vector3 velocity;
    15.         internal Quaternion rot;
    16.         internal Vector3 angularVelocity;
    17.     }
    18.  
    19.     // We store twenty states with "playback" information
    20.     State[] m_BufferedState = new State[20];
    21.     // Keep track of what slots are used
    22.     int m_TimestampCount;
    23.  
    24.     void Start ()
    25.     {
    26.         foreach (NetworkView n in GetComponents<NetworkView> ()) {
    27.             n.observed = this;
    28.         }
    29.     }
    30.  
    31.     void OnSerializeNetworkView (BitStream stream, NetworkMessageInfo info)
    32.     {
    33.         // Send data to server
    34.         if (stream.isWriting) {
    35.             Vector3 pos = rigidbody.position;
    36.             Quaternion rot = rigidbody.rotation;
    37.             Vector3 velocity = rigidbody.velocity;
    38.             Vector3 angularVelocity = rigidbody.angularVelocity;
    39.            
    40.             stream.Serialize (ref pos);
    41.             stream.Serialize (ref velocity);
    42.             stream.Serialize (ref rot);
    43.             stream.Serialize (ref angularVelocity);
    44.             // Read data from remote client
    45.         } else {
    46.             Vector3 pos = Vector3.zero;
    47.             Vector3 velocity = Vector3.zero;
    48.             Quaternion rot = Quaternion.identity;
    49.             Vector3 angularVelocity = Vector3.zero;
    50.             stream.Serialize (ref pos);
    51.             stream.Serialize (ref velocity);
    52.             stream.Serialize (ref rot);
    53.             stream.Serialize (ref angularVelocity);
    54.            
    55.             // Shift the buffer sideways, deleting state 20
    56.             for (int i = m_BufferedState.Length - 1; i >= 1; i--) {
    57.                 m_BufferedState[i] = m_BufferedState[i - 1];
    58.             }
    59.            
    60.             // Record current state in slot 0
    61.             State state;
    62.             state.timestamp = info.timestamp;
    63.             state.pos = pos;
    64.             state.velocity = velocity;
    65.             state.rot = rot;
    66.             state.angularVelocity = angularVelocity;
    67.             m_BufferedState[0] = state;
    68.            
    69.             // Update used slot count, however never exceed the buffer size
    70.             // Slots aren't actually freed so this just makes sure the buffer is
    71.             // filled up and that uninitalized slots aren't used.
    72.             m_TimestampCount = Mathf.Min (m_TimestampCount + 1, m_BufferedState.Length);
    73.            
    74.             // Check if states are in order, if it is inconsistent you could reshuffel or
    75.             // drop the out-of-order state. Nothing is done here
    76.             for (int i = 0; i < m_TimestampCount - 1; i++) {
    77.                 if (m_BufferedState[i].timestamp < m_BufferedState[i + 1].timestamp)
    78.                     Debug.Log ("State inconsistent");
    79.             }
    80.         }
    81.     }
    82.  
    83.     // We have a window of interpolationBackTime where we basically play
    84.     // By having interpolationBackTime the average ping, you will usually use interpolation.
    85.     // And only if no more data arrives we will use extra polation
    86.     void Update ()
    87.     {
    88.         // This is the target playback time of the rigid body
    89.         double interpolationTime = Network.time - m_InterpolationBackTime;
    90.        
    91.         // Use interpolation if the target playback time is present in the buffer
    92.         if (m_BufferedState[0].timestamp > interpolationTime) {
    93.             // Go through buffer and find correct state to play back
    94.             for (int i = 0; i < m_TimestampCount; i++) {
    95.                 if (m_BufferedState[i].timestamp <= interpolationTime || i == m_TimestampCount - 1) {
    96.                     // The state one slot newer (<100ms) than the best playback state
    97.                     State rhs = m_BufferedState[Mathf.Max (i - 1, 0)];
    98.                     // The best playback state (closest to 100 ms old (default time))
    99.                     State lhs = m_BufferedState[i];
    100.                    
    101.                     // Use the time between the two slots to determine if interpolation is necessary
    102.                     double length = rhs.timestamp - lhs.timestamp;
    103.                     float t = 0.0f;
    104.                     // As the time difference gets closer to 100 ms t gets closer to 1 in
    105.                     // which case rhs is only used
    106.                     // Example:
    107.                     // Time is 10.000, so sampleTime is 9.900
    108.                     // lhs.time is 9.910 rhs.time is 9.980 length is 0.070
    109.                     // t is 9.900 - 9.910 / 0.070 = 0.14. So it uses 14% of rhs, 86% of lhs
    110.                     if (length > 0.0001f)
    111.                         t = (float)((interpolationTime - lhs.timestamp) / length);
    112.                    
    113.                     // if t=0 => lhs is used directly
    114.                     transform.localPosition = Vector3.Lerp (lhs.pos, rhs.pos, t);
    115.                     transform.localRotation = Quaternion.Slerp (lhs.rot, rhs.rot, t);
    116.                     return;
    117.                 }
    118.             }
    119.             // Use extrapolation
    120.         } else {
    121.             State latest = m_BufferedState[0];
    122.            
    123.             float extrapolationLength = (float)(interpolationTime - latest.timestamp);
    124.             // Don't extrapolation for more than 500 ms, you would need to do that carefully
    125.             if (extrapolationLength < m_ExtrapolationLimit) {
    126.                 float axisLength = extrapolationLength * latest.angularVelocity.magnitude * Mathf.Rad2Deg;
    127.                 Quaternion angularRotation = Quaternion.AngleAxis (axisLength, latest.angularVelocity);
    128.                
    129.                 rigidbody.position = latest.pos + latest.velocity * extrapolationLength;
    130.                 rigidbody.rotation = angularRotation * latest.rot;
    131.                 rigidbody.velocity = latest.velocity;
    132.                 rigidbody.angularVelocity = latest.angularVelocity;
    133.             }
    134.         }
    135.     }
    136.    
    137. }
    138.  
    139.  
     
  2. Artaani

    Artaani

    Joined:
    Aug 5, 2012
    Posts:
    364
    You can just add NetworkTransform component to your object with Rigidbody and it will be interpolated automatically. If client want to push the object, he should send a [Command] to server.
     
    HakJak likes this.
  3. hottabych

    hottabych

    Joined:
    Apr 18, 2015
    Posts:
    73
    The same issue...
    I do VR multiplayer. When player on the host grabs the ball (by joystick), all the players see it. But if remote client grabs ball, only he can see it, while other players see like a ball still lies on the ground.
     
  4. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    3,561
    Does the server or the client have authority over the ball object? If the server has authority, are you sending Commands to the server to move the ball or just moving the ball locally on the client?
     
    hottabych likes this.