Search Unity

Strange network behavior, explanations more than welcome!

Discussion in 'Multiplayer' started by yaraco, Jun 17, 2017.

  1. yaraco

    yaraco

    Joined:
    Aug 21, 2013
    Posts:
    5
    Hello everyone! Trying to create my first game with Unity and the HLAPI and I encounter a strange behaviour I cannot explain. Would love to find a smart ass who can explain it to me.

    I have a PlayerController linked to my player gameObject. This PlayerController is a NetworkBehaviour.
    The game object has a network identity, a network transform, but no network animator. I handle animations by hand. The send rate of the network transform is for the moment set to 0, I don't want any positions correction.
    I can give a target this PlayerController and it handle the movement toward this position on the instance of the game who requested it and on all other instances.

    Let's have a try with this configuration : 1 host (but also playing) and 2 clients.

    When I call "GiveTarget" on a host, I have absolutly no problem. The movement and the animation are smooth on hosts and both clients.

    The problem comes when I call "GiveTarget" on a client. The movement and the animation are also perfeclty smooth on both clients.
    But a strange behaviour seems to happen on the host. The movement is right, but the animation seems to stop and go back to "idle" usually pretty quickly.
    When inserting debug logging, I notice that my stop calculation launch on the server a curious result : the distance between my position and the target at the current frame is greater than the one on the previous frame. Which has for result to call "StopWarlock()".
    In this function, I call the animation "Idle", seems to match with my animation stopping.
    But I also set my desired velocity to zero, so it should totally stop my movement.
    When my player on the host finally reach is targeted destination, the "StopWarlock" is called another time and the movement is stopped for good at this moment.

    My questions are :
    - Why my function "StopWarlock()" is called a first time when it should apparently not. Nothing is interfering with the movement and the distance between the target and my position should not increase between two frames. (and its not a small calculation approximation, values for example : Stop called : sqrMag : 35.50561 - lastSqrMag : 34.02433)
    - Why my function seems half called? It stops the animation, but not the movement.

    You can find attached the code of my PlayerController. Hope a good samaritan can help me process this mind F***!

    Thank you by advance!

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Networking;
    6.  
    7.  
    8.  
    9. public class PlayerController : NetworkBehaviour {
    10.  
    11.  
    12.     // Desired velocity of the player
    13.     private Vector3 desiredVelocity;
    14.  
    15.     // Target we are trying to reach
    16.     private Vector3 target;
    17.  
    18.     // Speed
    19.     private float speed = 7f;
    20.  
    21.     // Square distance between the target and the player calculated on the last frame
    22.     private float lastSqrMag;
    23.  
    24.     void OnStartLocalPlayer() {
    25.         // dummy target due to weird calculations at the initialisation. another thing I don't understand
    26.         target = new Vector3(1, 0, 1);
    27.        
    28.         lastSqrMag = Mathf.Infinity;
    29.        
    30.         desiredVelocity = Vector3.zero;
    31.     }
    32.  
    33.     void Update() {
    34.         StopWarlockOnTarget();
    35.     }
    36.  
    37.     void FixedUpdate() {
    38.         gameObject.GetComponent<Rigidbody>().velocity = desiredVelocity;
    39.     }
    40.  
    41.     /// <summary>
    42.     /// Give a target to the player
    43.     /// </summary>
    44.     /// <param name="target"></param>
    45.     public void GiveTarget(Vector3 target) {
    46.  
    47.         if (isServer) {
    48.             // Server order : executed on the server (locally) and on the clients
    49.             RpcDispatchMoveToTarget(target);
    50.         } else {
    51.             // Client order : executed locally
    52.             MoveToTarget(target);
    53.             // And ask the server to execute it on other clients
    54.             CmdMoveToTarget(target);
    55.         }
    56.     }
    57.  
    58.     /// <summary>
    59.     /// Executed on  server with client target
    60.     /// </summary>
    61.     /// <param name="target"></param>
    62.     [Command]
    63.     private void CmdMoveToTarget(Vector3 target) {
    64.         Debug.Log("Move asked by client");
    65.         RpcDispatchMoveToTarget(target);
    66.         Debug.Log("End Move asked by client");
    67.     }
    68.  
    69.     /// <summary>
    70.     /// Executed on clients with data target given by the server
    71.     /// </summary>
    72.     /// <param name="target"></param>
    73.     [ClientRpc]
    74.     private void RpcDispatchMoveToTarget(Vector3 target) {
    75.         // Order executed on server and on all the other clients (excluded the original caller)
    76.         Debug.Log("Move asked by serveur");
    77.         if (isServer || (!isServer && !isLocalPlayer)) {
    78.             MoveToTarget(target);
    79.         }
    80.         Debug.Log("End Move asked by serveur");
    81.     }
    82.  
    83.     private void MoveToTarget(Vector3 target) {
    84.        
    85.         this.target = target;
    86.         gameObject.GetComponent<Animator>().Play("Run");
    87.  
    88.         Vector3 direction = target - gameObject.transform.position;
    89.        
    90.         Vector3 lookAt = new Vector3(target.x, gameObject.transform.position.y, target.z);
    91.         gameObject.transform.LookAt(lookAt);
    92.  
    93.         desiredVelocity = direction.normalized * speed;
    94.  
    95.         // reset lastSqrMag
    96.         lastSqrMag = Mathf.Infinity;
    97.         Debug.Log("Move to target - lastSqrMag : " + lastSqrMag);
    98.         gameObject.GetComponent<Rigidbody>().velocity = desiredVelocity;
    99.  
    100.         float sqrMag = (target - gameObject.transform.position).sqrMagnitude;
    101.         Debug.Log("Start sqrMag : " + sqrMag + " - lastSqrMag : " + lastSqrMag + " - " + Time.time);
    102.     }
    103.  
    104.     private void StopWarlockOnTarget() {
    105.  
    106.         float sqrMag = (target - gameObject.transform.position).sqrMagnitude;
    107.        
    108.         if (!isLocalPlayer) {
    109.             Debug.Log("Calcul sqrMag : " + sqrMag + " - lastSqrMag : " + lastSqrMag + " - " + Time.time);
    110.         }
    111.        
    112.         if (sqrMag > lastSqrMag) {
    113.             Debug.Log("Stop sqrMag : " + sqrMag + " - lastSqrMag : " + lastSqrMag + " - " + Time.time);
    114.             // rigidbody has reached target and is now moving past it
    115.             StopWarlock();
    116.         }
    117.  
    118.         // make sure you update the lastSqrMag
    119.         lastSqrMag = sqrMag;
    120.     }
    121.  
    122.     public void StopWarlock() {
    123.         // stop the rigidbody by setting the velocity to zero
    124.         desiredVelocity = Vector3.zero;
    125.         gameObject.GetComponent<Animator>().Play("Idle");
    126.     }
    127.    
    128. }
    129.  
    130.