Search Unity

Resolved The host don't see animations of clients

Discussion in 'Netcode for GameObjects' started by Natank25, Jun 15, 2022.

  1. Natank25

    Natank25

    Joined:
    Feb 10, 2022
    Posts:
    26
    So, as the title is saying, the host don't see animations of clients. First, because players saw their own animations on every players, I tried making to make it so the animator in the scripts is only the one of the player and not of every players. I managed to fixe this problem but now host don't see the animations of the cilents.

    Anyone can help me with this issue ?
     
    Last edited: Jun 16, 2022
  2. CosmoM

    CosmoM

    Joined:
    Oct 31, 2015
    Posts:
    204
    Do you use a NetworkAnimator or Rpcs? Can you post your code?
     
  3. Natank25

    Natank25

    Joined:
    Feb 10, 2022
    Posts:
    26
    I used NetworkAnimator but not Rpcs because i don't know how to place it in my code.

    This only the code for the animation :
    Code (CSharp):
    1.  
    2. [SerializeField]
    3. private Animator animator;
    4.  
    5. void Start()
    6.     {
    7.         if (IsLocalPlayer)
    8.         {
    9.             animator = GetComponentInChildren<Animator>();
    10.         }
    11.  
    12.  
    13.     }
    14.  
    15. void Update(){
    16.    if (animator != null)
    17.         {
    18.             if (input.y > 0 && input.x == 0)
    19.             {
    20.                 animator.SetBool("backwards", false);
    21.                 animator.SetBool("left", false);
    22.                 animator.SetBool("right", false);
    23.                 animator.SetBool("idle", false);
    24.                 animator.SetBool("forwards", true);
    25.             }
    26.             else if (input.y < 0 && input.x == 0)
    27.             {
    28.                 animator.SetBool("forwards", false);
    29.                 animator.SetBool("left", false);
    30.                 animator.SetBool("right", false);
    31.                 animator.SetBool("idle", false);
    32.                 animator.SetBool("backwards", true);
    33.             }
    34.             else if (input.y == 0 && input.x > 0)
    35.             {
    36.                 animator.SetBool("forwards", false);
    37.                 animator.SetBool("backwards", false);
    38.                 animator.SetBool("left", false);
    39.                 animator.SetBool("idle", false);
    40.                 animator.SetBool("right", true);
    41.             }
    42.             else if (input.y == 0 && input.x < 0)
    43.             {
    44.                 animator.SetBool("forwards", false);
    45.                 animator.SetBool("backwards", false);
    46.                 animator.SetBool("right", false);
    47.                 animator.SetBool("idle", false);
    48.                 animator.SetBool("left", true);
    49.             }
    50.  
    51.             else
    52.             {
    53.                 animator.SetBool("forwards", false);
    54.                 animator.SetBool("backwards", false);
    55.                 animator.SetBool("left", false);
    56.                 animator.SetBool("right", false);
    57.  
    58.                 animator.SetBool("idle", true);
    59.            }
    60.     }
    61. }
     
  4. CosmoM

    CosmoM

    Joined:
    Oct 31, 2015
    Posts:
    204
    If you use a (standard) NetworkAnimator, then the server is authoritative. Meaning, you need to let the server set the animator parameters instead of the local player to have it replicated to all other clients. That will mean a delay however, since you will need the input read by the local player, sent to the server via ServerRpc, and then the server set the animator which then gets synced to all other clients. To ensure the local player does not see a delay, you can instead remove the NetworkAnimator, set the animator variables on the local player (as you do currently), then call a ServerRpc which sets the same values on the server (unless it's also the localPlayer), and which then calls a ClientRpc which sets them on all other clients (unless IsServer or IsLocalPlayer). That way, the local player experiences no animation delays, and all others experience the same delay they would have gotten anyway with a NetworkAnimator component.
     
  5. Natank25

    Natank25

    Joined:
    Feb 10, 2022
    Posts:
    26
    Can you give me an exemple please because I didn't understand everything ?
     
  6. CosmoM

    CosmoM

    Joined:
    Oct 31, 2015
    Posts:
    204
    What follows is untested code, debug as necessary. Don't forget to remove the NetworkAnimator.

    Above your public movement class (or in a different script) put:

    Code (CSharp):
    1. public enum Move {
    2.   idle,
    3.   forwards,
    4.   left,
    5.   right,
    6.   backwards
    7. }
    Then change your movement code to:

    Code (CSharp):
    1. [SerializeField]
    2. private Animator animator;
    3.  
    4. //Cache the animator state hashes to save CPU time
    5. private int animIdle;
    6. private int animForwards;
    7. private int animLeft;
    8. private int animRight;
    9. private int animBackwards;
    10.  
    11. void Awake() {
    12.   animator=GetComponentInChildren<Animator>();
    13.   animIdle=animator.StringToHash("idle");
    14.   animForwards=animator.StringToHash("forwards");
    15.   animLeft=animator.StringToHash("left");
    16.   animRight=animator.StringToHash("right");
    17.   animBackwards=animator.StringToHash("backwards");
    18. }
    19.  
    20. void Update() {
    21.   if (!IsLocalPlayer) return;
    22.   Move nextMove=Move.idle;
    23.   if (input.y > 0 && input.x == 0) {
    24.     nextMove=Move.forwards;
    25.   }
    26.   else if (input.y < 0 && input.x == 0) {
    27.     nextMove=Move.backwards;
    28.   }
    29.   else if (input.y == 0 && input.x > 0) {
    30.     nextMove=Move.right;
    31.   }
    32.   else if (input.y == 0 && input.x < 0) {
    33.     nextMove=Move.left;
    34.   }
    35.   SetAnimatorState(nextMove);
    36.   SetAnimatorStateServerRpc(nextMove);
    37. }
    38.  
    39. private void SetAnimatorState(Move nextMove) {
    40.   animator.SetBool(animIdle,false);
    41.   animator.SetBool(animForwards,false);
    42.   animator.SetBool(animLeft,false);
    43.   animator.SetBool(animRight,false);
    44.   animator.SetBool(animBackwards,false);
    45.   if (nextMove==Move.idle) animator.SetBool(animIdle,true);
    46.   else if (nextMove==Move.forwards) animator.SetBool(animForwards,true);
    47.   else if (nextMove==Move.left) animator.SetBool(animLeft,true);
    48.   else if (nextMove==Move.right) animator.SetBool(animRight,true);
    49.   else animator.SetBool(animBackwards,true);
    50. }
    51.  
    52. [ServerRpc]
    53. private void SetAnimatorStateServerRpc(Move nextMove) {
    54.   if (!IsLocalPlayer) SetAnimatorState(nextMove);
    55.   SetAnimatorStateClientRpc(Move nextMove);
    56. }
    57.  
    58. [ClientRpc]
    59. private void SetAnimatorStateClientRpc(Move nextMove) {
    60.   if (!IsLocalPlayer && !IsServer) SetAnimatorState(nextMove);
    61. }
    It looks by the way like your animator would benefit from a blend tree. Then you would only need to pass the input.x and input.y and not five booleans. But that's not multiplayer related.
     
  7. Natank25

    Natank25

    Joined:
    Feb 10, 2022
    Posts:
    26
    It works, thank you. But now I'm interested on using a blend (because I don't now how to use them, I'll search for it). But thank you anyaway !