Search Unity

Spawned projectile's rotation on client wrong for one frame

Discussion in 'Multiplayer' started by IAMBATMAN, Sep 23, 2016.

  1. IAMBATMAN

    IAMBATMAN

    Joined:
    Aug 14, 2015
    Posts:
    272
    Hello, I have a bow that you can shoot by clicking the left mouse button. On the host it shoots an arrow straight out and it looks pretty nice, but on the client the arrow points to the left with a rotation is 0 0 0 for 1 frame, before it gets straight. Which makes it look bad.

    here's the code I use
    Code (CSharp):
    1.     void Update ()
    2.     {
    3.         if(Input.GetMouseButtonDown(0) && canShoot)
    4.         {
    5.             animator.SetBool("Shoot", true);
    6.             canShoot = false;
    7.             Invoke("StartShoot",1.12f);
    8.             Invoke("StopShootAnim", 1.333f);
    9.         }
    10.     }
    11.     void StartShoot()
    12.     {
    13.         CmdShoot(bowString.position,bowString.eulerAngles);
    14.     }
    15.     [Command]
    16.     public void CmdShoot(Vector3 position, Vector3 rotation)
    17.     {
    18.         GameObject newArrow = Instantiate(arrow, position, Quaternion.Euler(rotation)) as GameObject;
    19.         newArrow.GetComponent<Rigidbody>().velocity = newArrow.transform.forward * 50;
    20.         NetworkServer.Spawn(newArrow);
    21.     }
    Do you know why it does this?
     
  2. cjf93

    cjf93

    Joined:
    Apr 28, 2014
    Posts:
    14
    You are setting the rotation on instantiate to the bowString.eulerAngles, maybe you want the rotation of the Arrow not the bowstring?

    I tried this and its working fine

    Code (CSharp):
    1.     public GameObject prefab;
    2.     void Start () {      
    3.         Vector3 mypos = this.transform.position;
    4.         mypos.y += 10.0f;
    5.         GameObject newArrow = Instantiate(prefab, mypos, Quaternion.Euler(this.transform.eulerAngles)) as GameObject;
    6.         newArrow.GetComponent<Rigidbody>().velocity = newArrow.transform.forward * 50;
    7.     }
    8.    
    Also my prefab and the object that I instantiate have different rotations
     
  3. IAMBATMAN

    IAMBATMAN

    Joined:
    Aug 14, 2015
    Posts:
    272
    Hmmm... No I want it to be bowString.eulerAngles, and It all works in the end. There's just one frame where the rotation is wrong which gives it a stutter effect, I'll upload gifs soon. As well as my tweaked code.
     
  4. IAMBATMAN

    IAMBATMAN

    Joined:
    Aug 14, 2015
    Posts:
    272
    This is my shooting code

    Code (CSharp):
    1. public GameObject arrow;
    2.     public Transform bowString;
    3.     public GameObject currentArrow;
    4.     public Animator animator;
    5.     public bool canShoot = true;
    6.     public Transform bowStringActual;
    7.     public GameObject kinematicArrow;
    8.  
    9.     // Use this for initialization
    10.     void Start ()
    11.     {
    12.         if (!isLocalPlayer)
    13.         {
    14.             this.enabled = false;
    15.         }
    16.         else
    17.         {
    18.             StartReload();
    19.         }
    20.     }
    21.  
    22.     // Update is called once per frame
    23.     void Update ()
    24.     {
    25.         if(Input.GetMouseButtonDown(0) && canShoot)
    26.         {
    27.             animator.SetBool("Shoot", true);
    28.             canShoot = false;
    29.             Invoke("StartShoot",1.12f);
    30.             Invoke("StopShootAnim", 1.333f);
    31.         }
    32.     }
    33.     void StartShoot()
    34.     {
    35.         CmdShoot(bowString.position,bowString.rotation);
    36.     }
    37.  
    38.     [Command]
    39.     public void CmdShoot(Vector3 position, Quaternion rotation)
    40.     {
    41.         Destroy(currentArrow);
    42.         GameObject newArrow = Instantiate(arrow, position, rotation) as GameObject;
    43.         newArrow.GetComponent<Rigidbody>().velocity = newArrow.transform.forward * 50;
    44.         NetworkServer.Spawn(newArrow);
    45.         Invoke("StartReload", 1f);
    46.     }
    47.     void StartReload()
    48.     {
    49.         CmdReload(bowString.position,bowString.eulerAngles);
    50.     }
    51.     [Command]
    52.     void CmdReload(Vector3 position, Vector3 rotation)
    53.     {
    54.         GameObject newArrow2 = Instantiate(kinematicArrow, position, Quaternion.Euler(rotation)) as GameObject;
    55.         newArrow2.GetComponent<Arrow>().parent = transform;
    56.         currentArrow = newArrow2;
    57.         NetworkServer.Spawn(newArrow2);
    58.     }
    59.     void StopShootAnim()
    60.     {
    61.         canShoot = true;
    62.         animator.SetBool("Shoot", false);
    63.     }
     
  5. IAMBATMAN

    IAMBATMAN

    Joined:
    Aug 14, 2015
    Posts:
    272
    This is the result, know how I can fix the arrow jitter on the client?

    Host shooting



    Client Shooting


     
  6. IAMBATMAN

    IAMBATMAN

    Joined:
    Aug 14, 2015
    Posts:
    272
    No one?
     
  7. IAMBATMAN

    IAMBATMAN

    Joined:
    Aug 14, 2015
    Posts:
    272
    I fixed it :)

    I put this script on my arrow (real arrow are the ones firing, and !realarrow are the ones that are in the string)

    Code (CSharp):
    1. [SyncVar(hook = "OnParentChange")]
    2.     public Transform parent;
    3.     public bool isRealArrow = false;
    4.  
    5.     void OnParentChange(Transform parent_)
    6.     {
    7.         parent = parent_;
    8.         if (!isRealArrow)
    9.         {
    10.             print("lol");
    11.             transform.parent = parent_.GetComponent<PlayerShoot>().bowStringActual;
    12.             transform.localEulerAngles = new Vector3(3.4254f, 89.8375f, 251.1488f);
    13.             transform.localPosition = new Vector3(2.670019f, -0.1708062f, 0.0190545f);
    14.         }
    15.     }
    16.     void Start()
    17.     {
    18.         if(parent != null && transform.parent == null)
    19.         {
    20.             if (!isRealArrow)
    21.             {
    22.                 transform.parent = parent.GetComponent<PlayerShoot>().bowStringActual;
    23.                 transform.localEulerAngles = new Vector3(3.4254f, 89.8375f, 251.1488f);
    24.                 transform.localPosition = new Vector3(2.670019f, -0.1708062f, 0.0190545f);
    25.             }
    26.             else
    27.             {
    28.                 transform.position = parent.GetComponent<PlayerShoot>().bowString.transform.position;
    29.                 transform.rotation = parent.GetComponent<PlayerShoot>().bowString.transform.rotation;
    30.  
    31.             }
    32.         }
    33.     }
     
  8. again

    again

    Joined:
    Mar 3, 2013
    Posts:
    21
    Hi Batman ;-)
    Could you please explain to me the basic idea how you solved this problem?Im facing exactly the same problem like you, but cant figure it out.

    I have simple script on my player which spawns bullets by [command] like this:
    Code (CSharp):
    1.  [Command]
    2.     void CmdFire()
    3.     {
    4.        var bullet = (GameObject)Instantiate(
    5.             bulletPrefab,
    6.             transform.position - transform.forward,
    7.             transform.forward);
    8.  
    9.        bullet.GetComponent<Rigidbody>().velocity = transform.forward*100;
    10.      
    11.        NetworkServer.Spawn(bullet);
    12.      
    13.        Destroy(bullet, 2.0f);
    14.     }
    And I tried to narrow your code to be used in my simple case like that:
    Code (CSharp):
    1.  
    2. [SyncVar(hook = "OnParentChange")]
    3.     public Transform parent;
    4.     void OnParentChange(Transform parent_)
    5.     {
    6.         parent = parent_;
    7.  
    8.     }
    9.     void Start()
    10.     {
    11.         if(parent != null && transform.parent == null)
    12.         {
    13.                 transform.position = parent.transform.position;
    14.                 transform.rotation = parent.transform.rotation;
    15.             }
    16.         }
    17.     }
    And adding it to my bullet prefab but without any sucess.
    Please could you push me in the right direction?

    Thanks in advance
     
  9. Jos-Yule

    Jos-Yule

    Joined:
    Sep 17, 2012
    Posts:
    292
    Spawn() does update the location of the spawned item, but not its rotation. You can't syncvar a transform, but you can a Quaternion, so if you do something like

    Code (CSharp):
    1. [SyncVar]
    2. Quaternion rotation;
    3.  
    4. void OnStartClient()
    5. {
    6.     this.transform.rotation = rotation;
    7. }
    8.  
    9. void Update()
    10. {
    11.     rotation = this.transform.rotation;
    12. }
    Note that updating the rotation syncvar every frame isn't a good idea! :) Also, SyncVars are set before the client is "spawned", so you can be sure that in the OnStartClient, rotation will be set to whatever it was on the host.