Network sync manual character bone movements

Options
I need to network sync the movement of a players arm bone.

In my game, I manually adjust a player's arm bone to point toward closest enemy:

void LateUpdate() { armLookDiff = targetEnemy.transform.position - armLookRotation.transform.position; armLookRotation = Quaternion.LookRotation(armLookDiff); characterArm.transform.rotation = armLookRotation; }

This all works great.

When I try to do an RPC as such:

void LateUpdate() { armLookDiff = targetEnemy.transform.position - armLookRotation.transform.position; armLookRotation = Quaternion.LookRotation(armLookDiff); m_PhotonView.RPC("armLookAtTarget", PhotonTargets.All); }
The RPC

[PunRPC] void armLookAtTarget() { characterArm.transform.rotation = armLookRotation; }


I am not seeing the arm point toward the enemy as viewed by remote player. I see it locally only.

I will also try to sync via OnPhotonSerializeView but does this code look reasonably correct?

Best Answer

Answers

  • FGStud
    FGStud
    edited March 2016
    Options
    Sorry I found a bunch of forum posts about this but not with any solution that makes sense or that works. I also looked at Marco Polo demo again as advised. Still no clarity.

    I switched to OnPhotonSerializeView but remote player arm still not sync'ing for both players.

    using UnityEngine; using System.Collections; public class NetworkStuff2016 : Photon.MonoBehaviour { public static Vector3 realPosition = Vector3.zero; Quaternion realRotation = Quaternion.identity; Animator anim; public Transform characterArm; Quaternion armLookRotationReal = Quaternion.identity; void Start () { characterArm = transform.Find("Hips/Spine/Spine1/Spine2/Shoulder/ShoulderL/UpperArm"); if(characterArm == null) Debug.Log ("characterArm not found"); if(characterArm != null) Debug.Log ("characterArm found"); anim = GetComponent<Animator>(); anim.SetFloat("Speed", 0.0f); } void Update () { if( photonView.isMine ) { } else { transform.position = Vector3.Lerp(transform.position, realPosition, 0.1f); transform.rotation = Quaternion.Lerp(transform.rotation, realRotation, 0.1f); characterArm.transform.rotation = Quaternion.Lerp(characterArm.transform.rotation, armLookRotationReal, 0.1f); } } public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { if(stream.isWriting) { stream.SendNext(transform.position); stream.SendNext(transform.rotation); stream.SendNext(characterArm.transform.rotation); stream.SendNext(anim.GetFloat("Speed")); } else { if( stream != null && anim != null) { realPosition = (Vector3)stream.ReceiveNext(); realRotation = (Quaternion)stream.ReceiveNext(); armLookRotationReal = (Quaternion)stream.ReceiveNext(); anim.SetFloat("Speed", (float)stream.ReceiveNext()); } } } }

    I found this older thread but its not clear how/why/where setting a float in mechanim helps.

    Failing to sync a localEurlerAngles value

    I have switched to OnPhotonSerializeView as recommended but apparently setting a bone angle as above doesn't work for me nor has it worked for others. I would love to know why this doesn't work.

    I see from the thread that an "Angle" is passed just as "Speed" is. I set my arm rotation in local player control as such.

    void LateUpdate() { armLookDiff = targetEnemy.transform.position - armLookRotation.transform.position; armLookRotation = Quaternion.LookRotation(armLookDiff); characterArm.transform.rotation = armLookRotation; }

    When/how/why do I need to set a mechanim state to make this work? I will try the mechanim state setting but not sure why I need to do that.

    Is there no other way to make this work?


  • FGStud
    Options
    I don't know why this got marked as answered but it is NOT answered.
  • vadim
    Options
    Can you be more precise. The problem is that PhotonRPC or OnPhotonSerializeView does not work for you? Or values delivered to other clients as expected but setting bone parameters fails? If latter is the case, this is probably not PUN related problem and you should focus on how you set these values (maybe they are overridden somewhere else).
  • FGStud
    Options
    Thanks for answering vadim. I took a break from this because it was so frustrating. I've now moved on to try to move a dragon head to point toward enemy instead of the arm (arm still doesn't work).

    If you read my post it is clear that I have tried both RPC and OnSerialized.

    When I use OnSerialized the values received from remote client are reasonable but setting the bone parameters fail. The head simply does not move ( just as the arm did not before).

    In the local player perspective the head rotates correctly. The remote player never sees the rotation.

    Here is a section of code from the player movement script attached to player prefab that I instantiate. This code works prefectly to rotate the head.

    void LateUpdate() { headLookDiff = targetEnemy.transform.position - dragonHead.transform.position; headLookRotation = Quaternion.LookRotation(headLookDiff); float QuatheadLookRotationEulerX = headLookRotation.eulerAngles.x; float QuatheadLookRotationEulerY = headLookRotation.eulerAngles.y; float QuatheadLookRotationEulerZ = headLookRotation.eulerAngles.z; Debug.Log ( "in movement script before anim set QuatheadLookRotationEulerX: " + QuatheadLookRotationEulerX + " QuatheadLookRotationEulerY: " + QuatheadLookRotationEulerY + " QuatheadLookRotationEulerZ: " + QuatheadLookRotationEulerZ ); dragonAnimator.SetFloat ("HeadAngleX", QuatheadLookRotationEulerX); dragonAnimator.SetFloat ("HeadAngleY", QuatheadLookRotationEulerY); dragonAnimator.SetFloat ("HeadAngleZ", QuatheadLookRotationEulerZ); dragonHead.transform.rotation = Quaternion.Euler(dragonAnimator.GetFloat("HeadAngleX"), dragonAnimator.GetFloat("HeadAngleY"), dragonAnimator.GetFloat("HeadAngleZ")); }

    ^^^This code works to rotate the head for both players as viewed locally.



    Now I serialize:

    using UnityEngine; using System.Collections; public class NetworkDragon2016 : Photon.MonoBehaviour { public static Vector3 realPosition = Vector3.zero; Quaternion realRotation = Quaternion.identity; Animator anim; private float HeadAngleX; private float HeadAngleY; private float HeadAngleZ; void Start () { // find head headDragon = transform.Find("Hips/Spine/Spine1/Spine2/Spine3/Spine4/Spine5/Spine6/Spine7/Neck/Neck1/Neck2/Neck3/Neck4/Neck5/Neck6/Head"); if(headDragon != null) Debug.Log ("Head found"); anim = GetComponent<Animator>(); anim.SetFloat("Speed", 0.0f); anim.SetFloat("HeadAngleX", 0); anim.SetFloat("HeadAngleY", 0); anim.SetFloat("HeadAngleZ", 0); anim.SetFloat("HeadAngleW", 0); } void Update () { if( photonView.isMine ) { //Debug.LogError ("photonView.isMine = true"); // Do nothing -- the character motor/input/etc... is moving us } else { transform.position = Vector3.Lerp(transform.position, realPosition, 0.1f); transform.rotation = Quaternion.Lerp(transform.rotation, realRotation, 0.1f); anim.SetFloat("HeadAngleX", Mathf.Lerp (anim.GetFloat ("HeadAngleX"), HeadAngleX, 0.1f)); anim.SetFloat("HeadAngleY", Mathf.Lerp (anim.GetFloat ("HeadAngleY"), HeadAngleY, 0.1f)); anim.SetFloat("HeadAngleZ", Mathf.Lerp (anim.GetFloat ("HeadAngleZ"), HeadAngleZ, 0.1f)); headDragon.transform.rotation = Quaternion.Euler(HeadAngleX, HeadAngleY, HeadAngleZ); Debug.Log ( "update from other HeadAngleX: " + HeadAngleX + " HeadAngleY: " + HeadAngleY + " HeadAngleZ: " + HeadAngleZ); } } public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { if(stream.isWriting && stream != null && anim != null) { // This is OUR player. We need to send our actual position to the network. stream.SendNext(transform.position); stream.SendNext(transform.rotation); stream.SendNext(anim.GetFloat("Speed")); stream.SendNext(anim.GetFloat("HeadAngleX")); stream.SendNext(anim.GetFloat("HeadAngleY")); stream.SendNext(anim.GetFloat("HeadAngleZ")); Debug.Log ( "what I send anim.GetFloat(HeadAngleX): " + anim.GetFloat("HeadAngleX") + " anim.GetFloat(HeadAngleY): " + anim.GetFloat("HeadAngleY") + " anim.GetFloat(HeadAngleZ): " + anim.GetFloat("HeadAngleZ")); } else { if( stream != null && anim != null) { realPosition = (Vector3)stream.ReceiveNext(); realRotation = (Quaternion)stream.ReceiveNext(); anim.SetFloat("Speed", (float)stream.ReceiveNext()); HeadAngleX = (float)stream.ReceiveNext(); HeadAngleY = (float)stream.ReceiveNext(); HeadAngleZ = (float)stream.ReceiveNext(); // anim.SetFloat("HeadAngleX", (float)stream.ReceiveNext()); // anim.SetFloat("HeadAngleY", (float)stream.ReceiveNext()); // anim.SetFloat("HeadAngleZ", (float)stream.ReceiveNext()); headDragon.transform.rotation = Quaternion.Euler(HeadAngleX, HeadAngleY, HeadAngleZ); Debug.Log ( "what I receive anim.GetFloat(HeadAngleX): " + anim.GetFloat("HeadAngleX") + " anim.GetFloat(HeadAngleY): " + anim.GetFloat("HeadAngleY") + " HeadAngleZ: " + HeadAngleZ); } } } }

    I think my problem is that I am not setting the remote players head rotation properly. The values from the stream look reasonable.

    I do this line after recieving the other players head rotation values but I don't think this is where I should set the head rotation value.

    headDragon.transform.rotation = Quaternion.Euler(HeadAngleX, HeadAngleY, HeadAngleZ);

    I am using anim states because the post below implies it has to be done that way.

    Failing to sync a localEurlerAngles value

    Where should I set the head rotation for remote player?

  • wesleywh
    Options
    How did you solve this? I'm getting problems with the bone rotations every once in a while getting set to zero.