synchronized transform is always 0,0,0 in Photon unity

I'm making a simple zombie co-op game with Unity and Photon and have problem with sync enemy transform.

First, I need to explain my idea of chasing enemy AI. Enemies are using NavMeshAgent to finding path, but I thought finding path on every player's computer is too much.

So I thought that it would be great if the zombie's target player is current player(The player who actually playing this game, not a master), then enables NavMeshAgent to finding path, otherwise, just update transform received from network(synchronized).

I think my idea is fine, so I made it. This is the code.

1. NetworkEnemy Script: This script sync animation and transform data via network. Using RPC to synchronize animation and use OnPhotonSerializeView to synchronize transform data.

public class NetworkEnemy : Photon.MonoBehaviour {
Chasing chasing;        // The Chasing Script. I will explain later.
GameObject target;
NetworkPlayer targetNetworkPlayer;
Vector3 syncPos = Vector3.zero;
Quaternion syncRot = Quaternion.identity;
...

void Start() {
// target is Player and has NetworkPlayer component which derieves Photon.MonoBehavior. Of course, Player has PhotonView component.
target = chasing.Target;
targetNetworkPlayer = target.GetComponent<NetworkPlayer>();
}

void Update() {
// Interpolate player loc/rot only target isn't local player.
// Because if the target is local player, NavMeshAgent will control it.
// IsLocalPlayer returns photonView.isMine
if(!targetNetworkPlayer.IsLocalPlayer) {
transform.position = Vector3.Lerp(transform.position, syncPos, 0.1f);
transform.rotation = Quaternion.Lerp(transform.rotation, syncRot, 0.1f);
}

... // Check is dead or something like that here...
}

...

public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
if(stream.isWriting) {
stream.SendNext(transform.position);
stream.SendNext(transform.rotation);
}
else {
syncPos = (Vector3) stream.ReceiveNext();
syncRot = (Quaternion) stream.ReceiveNext();
}
}

...
}

2. Chasing Script: It controls(enable/disable) NavMeshAgent. If the target player is local player, turn this on. Else, turn this off. Also it checks player in the attack range and do attack.

public class Chasing : Photon.MonoBehaviour {
NavMeshAgent agent;
GameObject target;
NetworkPlayer targetNetworkPlayer;

...

void Awake () {
...
agent = GetComponent<NavMeshAgent>();

SetTarget(GetClosestPlayer());    // GetClosestPlayer returns closet Player GameObject
}

public void SetTarget(GameObject player) {
target = player;
targetNetworkPlayer = player.GetComponent<NetworkPlayer>();

// If target is local player(photonView.isMine), activate NavMeshAgent
if(targetNetworkPlayer.IsLocalPlayer) {
agent.enabled = true;
}
else {
agent.enabled = false;
}
}

...
}


I tested this code online but it wasn't working as I expected.

So I tested about 5~6 times and finally figured out what happens actually(I updated some of them. Please read carefully). Before that, I'm just gonna call "Master" player is A, and other is B.

1. In Player A(Master) sight
1. If the target is A, it works
2. If the target is B, it has (0,0,0) position
2. In Player B sight
1. If the target is A, it works
2. If the target is B, it works

In NetworkEnemy script, you were saw these codes:

public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
if(stream.isWriting) {
stream.SendNext(transform.position);
stream.SendNext(transform.rotation);
}
else {
syncPos = (Vector3) stream.ReceiveNext();
syncRot = (Quaternion) stream.ReceiveNext();
}
}


I'm synchronizing it's transform but why another player got 0,0,0 only it wasn't master?

Is my idea is wrong? Then should I activate NavMeshAgent always to every zombies from every players? If that so, how to solve the issue that each player's game calculates different path?

Those scripts are observed by PhotonView component. There is no more scripts that updates zombie's transform, they're all.

If I approach wrong way, then it will be very appreciate it how to make Co-op enemy path finding system efficiently.

Any advice will very appreciate it.

2 Answers

I solved this problem by using RPC. Remove whole OnPhotonSerializeView code and add new RPC Function like this:

[PunRPC]
void UpdateZombieTransform(Vector3 pos, Quaternion rot) {
syncPos = pos;
syncRot = rot;
}


And in Update function, paste this code:

if(!targetNetworkPlayer.IsLocalPlayer) {
transform.position = Vector3.Lerp(transform.position, syncPos, 0.1f);
transform.rotation = Quaternion.Lerp(transform.rotation, syncRot, 0.1f);
}
else {
photonView.RPC("UpdateZombieTransform", PhotonTargets.Others, transform.position, transform.rotation);
}


I don't know why it works and why OnPhotonSerializeView is not :( I solved this problem, but can anyone tell me why this is works?

Anyway if you faced same problem as me, I hope this solution work for you. Thanks.

One thing: let do the master client the work: spawn enemies, add target and calculate the path.

And only synchronized the position/rotation on other clients.

Maybe OnPhotonSerializeView doesn't work properly because your script doesn't inherit from IPunObservable.

And using RPC for syncing position and rotation isn't a good idea.

• "And using RPC for syncing position and rotation isn't a good idea." Why not? – Alexandre Vaillancourt Jan 24 '18 at 11:54