Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Standard Assets Vehicle example in multiplayer? Wheels not syncing.

Discussion in 'Multiplayer' started by ChrisSch, Jun 12, 2015.

  1. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    So I decided to test out the new multiplayer. Having little experience with the old system, I expected it would be just as confusing to get some basics running. But it wasn't, the new network components are awesome and almost self explanatory.

    Anyway, I decided to test it out, and I guess I picked one of the harder examples to try converting to multiplayer. Getting the vehicles to spawn and each control themselves and no one else was easy. Getting each have their own camera took a few lines of code. But then I ran into a problem.

    I can't get the wheel models to appear spinning and turning for anyone. Adding a network transform on each doesn't do anything. I have no idea why, since that's pretty much all it took for the car itself to sync.

    Network identity on the car is local authority. And I tried the same for the wheels, and all other combinations I could think of, but they just won't work the same as the car itself.
     
  2. samfarhan

    samfarhan

    Joined:
    Oct 14, 2012
    Posts:
    14
    Do the wheels use an animation to show that they're turning? If so then you'll have to use a NetworkAnimator.
     
  3. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    If you make CarController a NetworkBehaviour, then do:

    Code (CSharp):
    1.     public class CarController : NetworkBehaviour
    2.     {
    3.  
    4.         [Command]
    5.         void CmdMove(float steering, float accel, float footbrake, float handbrake)
    6.         {
    7.             RpcMove(steering, accel, footbrake, handbrake);
    8.         }
    9.  
    10.         [ClientRpc]
    11.         void RpcMove(float steering, float accel, float footbrake, float handbrake)
    12.         {
    13.             if (isLocalPlayer)
    14.                 return;
    15.  
    16.             Move(steering, accel, footbrake, handbrake);
    17.         }
    18.  
    19.         int moveCount = 0;
    20.  
    21.         public void Move(float steering, float accel, float footbrake, float handbrake)
    22.         {
    23.             if (isLocalPlayer)
    24.             {
    25.                 if (moveCount++ % 10 == 0)
    26.                 {
    27.  
    28.                     CmdMove(steering, accel, footbrake, handbrake);
    29.                 }
    30.             }
    This will send the inputs from the local player to other players, which will make the remote car behave better.
     
    ChrisSch likes this.
  4. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    No they use a script, with wheel colliders.

    I was just looking into commands and rpcs in the manual, but I don't get how it works.

    I did it and it works! So thanks for that! :D
    Its a bit delayed and choppy/jagged but it works. I have a few questions tho. I made the CarController a network behaviour, and I put that into the CarController script, just added without changing anything. And I left the CarController enabled on the clients, but disabled CarUserControl. Did I do it right? But I'm not sure what's going on.

    Whats moveCount? And Isn't it always 0?
    To fix the choppiness, do I need to interpolate the wheels through code now?

    Player #1(host)
    1. Calls Move (with own input)
    2. checks if its local player, and if 10% of move count +1 is 0, which it is, in an integer I assume. But why are we checking that?
    3a, if its local player call CmdMove, and proceed with moving.
    3a. then CmdMove sends it to the server, so we can then send to other clients, because we can't send from client to client?
    4a. then RpcMove checks if its local player, and if not, moves the other side self?.

    3b. if its not just proceed with moving, which doesn't happen because CarUserControler is disabled.

    I'm finding it really hard to wrap my head around what Command and ClientRpc do, even tho I went over the manual, probably because I'm finding it hard to wrap my head around the networking too. I don't remember much about how it was done before, I only used it once in some prototype, but I remember we were serializing network views, and for simple commands we'd just use [RPC] for methods we want to send across network.
     
  5. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    The "if(moveCount++%10==0)" just makes the CmdMove be called every 10 frames, so not to spam the network 60 times a second. MoveCount is incremented each frame by the ++.

    So the local player essentially sends their local input to the server with the Command, then the server send that input to each other client with the ClientRpc all, and that input is applied to the remote version of the original car on those remote clients. It is like the car is being driven by a player in both places, so all the extra stuff like brake lights, wheels and skid marks just work. Then the NetworkTransform keeps the positions close to being in sync.

    Hm. i also made a change to CarUserControl to prevent input from being processed, but didnt disable it.

    Code (CSharp):
    1. namespace UnityStandardAssets.Vehicles.Car
    2. {
    3.     [RequireComponent(typeof (CarController))]
    4.     public class CarUserControl : NetworkBehaviour
    5.     {
    6.         private CarController m_Car; // the car controller we want to use
    7.  
    8.         private void Awake()
    9.         {
    10.             // get the car controller
    11.             m_Car = GetComponent<CarController>();
    12.         }
    13.  
    14.         private void FixedUpdate()
    15.         {
    16.             if (!hasAuthority)
    17.                 return;
    18.  
    19.             // pass the input to the car!
    20.             float h = CrossPlatformInputManager.GetAxis("Horizontal");
    21.             float v = CrossPlatformInputManager.GetAxis("Vertical");
    22. #if !MOBILE_INPUT
    23.             float handbrake = CrossPlatformInputManager.GetAxis("Jump");
    24.             m_Car.Move(h, v, v, handbrake);
    25. #else
    26.             m_Car.Move(h, v, v, 0f);
    27. #endif
    28.         }
    29.     }
    30. }
    31.  
     
    ripetrescu and ChrisSch like this.
  6. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Ah I think I understand it a little better now! I had no idea you can make changes like the ++ inside an if statement. :D

    And is "hasAuthority" the "Local Player Authority" checkbox in Network Identity? I read to turn that on if we want things working right.

    This is my transform and identity settings. The rotation update was horribly delayed until I set it to 10 interpolation. That makes it at least 95% correct. I'm testing on the same machine by having two instances running. Can't sync if audio is running right like that tho. :p
    upload_2015-6-13_1-2-28.png

    Also can you tell me can I interpolate between the wheel updates?
     
  7. Justice0Juic3

    Justice0Juic3

    Joined:
    Apr 29, 2013
    Posts:
    188
    Unity doesn't seem to recognize the "moveCount", strange.
     
  8. adam_mehman

    adam_mehman

    Joined:
    Dec 11, 2014
    Posts:
    104
    You should declare the variable and the it will recognize it.
     
  9. Martins74

    Martins74

    Joined:
    Jul 21, 2016
    Posts:
    8
    I just can't get it to work.
    My with the default script the host can drive, but with this adaptation neither the host or the client can drive.
    I making a FPS when you can get in and out of cars but i cant solve how to resolve this problem.