Unity中通过Photon为PUN实例化GameObject设置标签问题求助
问题:Photon PUN中Player2标签无法通过RPC正确设置
我尝试通过RPC调用,依据PhotonView的ViewID为两个PUN实例化的GameObject分别设置“Player1”和“Player2”标签。目前Player1的标签可成功设置,但Player2的标签始终无法正确赋予。该网络代码运行在两台Oculus Quest设备上:启动第一台Quest时,Player1标签可正常分配;启动第二台Quest时,Player2 GameObject会生成,且其PhotonView的ViewID确实为“2001”,但标签未被设置为“Player2”。
原代码
using System; using UnityEngine; using Photon.Pun; using Photon.Realtime; using UnityEngine.XR.Interaction.Toolkit; public class NetworkPlayerSpawner : MonoBehaviourPunCallbacks { public GameObject XROriginPrefab; [HideInInspector] public GameObject spawnedPlayerPrefab; private PhotonView pv; private void Start() { pv = GetComponent<PhotonView>(); } private void Update() { // Debug.Log(PhotonNetwork.CurrentRoom.PlayerCount); } public override void OnJoinedRoom() { base.OnJoinedRoom(); var playerCount = PhotonNetwork.CurrentRoom.PlayerCount; Debug.Log("The player count is: " + playerCount); var teleportAreas = GameObject.FindGameObjectsWithTag("Floor"); //playerCount = 2; if (playerCount == 1) { XROriginPrefab = Instantiate(XROriginPrefab, new Vector3(0, 2.36199999f, 3.78999996f), new Quaternion(0, 0, 0, 1)); spawnedPlayerPrefab = PhotonNetwork.Instantiate("Network Player", transform.position, transform.rotation); //spawnedPlayerPrefab.tag = "Player1"; foreach (GameObject go in teleportAreas) { go.AddComponent<TeleportationArea>(); } } else { XROriginPrefab = Instantiate(XROriginPrefab, new Vector3(-10.3859997f,1.60699999f,10.6400003f), new Quaternion(0,0,0,1)); spawnedPlayerPrefab = PhotonNetwork.Instantiate("Network Player", transform.position, transform.rotation); //spawnedPlayerPrefab.tag = "Player2"; //If teleport breaks again, I uncommented this line, so it should be commented out again. Should allow for teleport in User 2's room. foreach (GameObject go in teleportAreas) { go.AddComponent<TeleportationArea>(); } } rpcCallTagAssign(); } public override void OnPlayerEnteredRoom(Player newPlayer) { base.OnPlayerEnteredRoom(newPlayer); Debug.Log("Remote Player Joined!"); rpcCallTagAssign(); } public override void OnLeftRoom() { base.OnLeftRoom(); PhotonNetwork.Destroy(spawnedPlayerPrefab); } [PunRPC] private void tagAssign() { if (spawnedPlayerPrefab.GetComponent<PhotonView>().ViewID==1001) { spawnedPlayerPrefab.tag = "Player1"; } if (spawnedPlayerPrefab.GetComponent<PhotonView>().ViewID==2001) { spawnedPlayerPrefab.tag = "Player2"; } } private void rpcCallTagAssign() { pv.RPC("tagAssign", RpcTarget.AllViaServer); } }
问题分析与解决方案
核心问题
spawnedPlayerPrefab的跨设备指向错误:当第二台设备加入时,第一台设备的spawnedPlayerPrefab仍指向本地Player1,RPC执行时只会检查Player1的ViewID,不会处理Player2;而第二台设备的RPC调用可能因网络同步延迟,导致ViewID判断逻辑未触发。- 硬编码ViewID不可靠:Photon的ViewID分配规则不固定,硬写
1001/2001会导致扩展性极差,后续新增玩家会彻底失效。
修复方案
改用Photon内置的ActorNumber(房间内每个玩家的唯一标识)区分玩家,同时确保所有设备能正确遍历并设置对应玩家的标签:
修复后代码
using System; using UnityEngine; using Photon.Pun; using Photon.Realtime; using UnityEngine.XR.Interaction.Toolkit; public class NetworkPlayerSpawner : MonoBehaviourPunCallbacks { public GameObject XROriginPrefab; [HideInInspector] public GameObject spawnedPlayerPrefab; private PhotonView pv; private void Start() { pv = GetComponent<PhotonView>(); } public override void OnJoinedRoom() { base.OnJoinedRoom(); var playerCount = PhotonNetwork.CurrentRoom.PlayerCount; Debug.Log("The player count is: " + playerCount); var teleportAreas = GameObject.FindGameObjectsWithTag("Floor"); // 简化生成位置判断 Vector3 spawnPos = playerCount == 1 ? new Vector3(0, 2.36199999f, 3.78999996f) : new Vector3(-10.3859997f,1.60699999f,10.6400003f); XROriginPrefab = Instantiate(XROriginPrefab, spawnPos, Quaternion.identity); spawnedPlayerPrefab = PhotonNetwork.Instantiate("Network Player", transform.position, transform.rotation); // 避免重复添加TeleportationArea组件 foreach (GameObject go in teleportAreas) { if (!go.TryGetComponent(out TeleportationArea _)) { go.AddComponent<TeleportationArea>(); } } // 延迟调用确保网络对象同步完成 Invoke(nameof(rpcCallTagAssign), 0.5f); } public override void OnPlayerEnteredRoom(Player newPlayer) { base.OnPlayerEnteredRoom(newPlayer); Debug.Log("Remote Player Joined!"); Invoke(nameof(rpcCallTagAssign), 0.5f); } public override void OnLeftRoom() { base.OnLeftRoom(); PhotonNetwork.Destroy(spawnedPlayerPrefab); } [PunRPC] private void tagAssign() { // 遍历所有网络玩家对象(建议给预制体设置初始标签如"NetworkPlayer",查找更精准) var allNetworkPlayers = GameObject.FindGameObjectsWithTag("Untagged"); foreach (var playerObj in allNetworkPlayers) { var photonView = playerObj.GetComponent<PhotonView>(); if (photonView == null || !photonView.IsMine) continue; // 用ActorNumber区分玩家,1为第一个加入,2为第二个 playerObj.tag = photonView.Owner.ActorNumber == 1 ? "Player1" : "Player2"; } } private void rpcCallTagAssign() { pv.RPC("tagAssign", RpcTarget.AllViaServer); } }
额外优化建议
- 给“Network Player”预制体设置专属初始标签(如
NetworkPlayer),替换代码中Untagged的查找逻辑,避免误匹配其他对象 - 延迟调用RPC是为了确保网络对象在所有设备上完成实例化,避免空引用或未同步问题
- 用
Quaternion.identity替代手动创建四元组,代码更简洁
内容的提问来源于stack exchange,提问作者Gamerprime
相关产品推荐
相关产品推荐

