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.
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(); } } ... }
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.
- In Player A(Master) sight
- If the target is A, it works
- If the target is B, it has (0,0,0) position
- In Player B sight
- If the target is A, it works
- 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.