You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
    }
}

问题分析与解决方案

核心问题

  1. spawnedPlayerPrefab的跨设备指向错误:当第二台设备加入时,第一台设备的spawnedPlayerPrefab仍指向本地Player1,RPC执行时只会检查Player1的ViewID,不会处理Player2;而第二台设备的RPC调用可能因网络同步延迟,导致ViewID判断逻辑未触发。
  2. 硬编码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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 11:30:55