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

Unity PUN 2网络多人游戏生成不同角色预制体后无法获取其他玩家角色信息的问题求助

Fixing Multiplayer Character Sync Issues with Photon in Unity

Let's break down exactly what's going wrong here and walk through the solution:

The Core Problem

Your current code assumes both player characters exist locally on every client, but that's not how Photon works. Each client only instantiates its own character (Actor 1 spawns blue, Actor 2 spawns green), so when you call GameObject.Find("green soldier(Clone)") on the blue player's client, that object doesn't exist locally—it's only present on the green player's device, and synced over the network to yours.

Additionally, you're setting BlueName and GreenName to the local player's nickname on every client, so remote player names never get synced.

Step-by-Step Solution

1. Use Photon Callbacks & Custom Properties

First, update your GameplayManager to inherit from MonoBehaviourPunCallbacks so you can listen for network events (like players joining or property updates). We'll also use Photon's custom player properties to sync nicknames across clients.

2. Rewrite Character Spawning & Sync

Remove the local Find() calls in Start()—we'll find remote players using their PhotonView owner instead of object names.

Here's the revised code:

using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using Photon.Realtime;
using System.Linq;

public class GameplayManager : MonoBehaviourPunCallbacks { 
    public PhotonView view; 
    public GameObject BlueSoldier; 
    public GameObject GreenSoldier; 
    public Vector2 BlueSpawnPos = new Vector2(4.07f, 0.02f); 
    public Vector2 GreenSpawnPos = new Vector2(3.97f, -0.02f); 

    private GameObject _localPlayer;
    private Text _victoryText;

    void Start() { 
        _victoryText = GameObject.Find("VictoryText").GetComponent<Text>();
        InstantiatePlayers();
        
        // Sync local player's nickname to all clients via custom properties
        ExitGames.Client.Photon.Hashtable playerProps = new ExitGames.Client.Photon.Hashtable();
        playerProps["Nickname"] = PhotonNetwork.LocalPlayer.NickName;
        PhotonNetwork.LocalPlayer.SetCustomProperties(playerProps);
    } 

    public void InstantiatePlayers() { 
        if (PhotonNetwork.LocalPlayer.ActorNumber == 1) { 
            _localPlayer = PhotonNetwork.Instantiate(BlueSoldier.name, BlueSpawnPos, Quaternion.identity); 
            Debug.Log($"Spawned blue player: {PhotonNetwork.LocalPlayer.NickName}");
        } 
        if (PhotonNetwork.LocalPlayer.ActorNumber == 2) { 
            _localPlayer = PhotonNetwork.Instantiate(GreenSoldier.name, GreenSpawnPos, Quaternion.identity); 
            Debug.Log($"Spawned green player: {PhotonNetwork.LocalPlayer.NickName}");
        } 
    }

    // Triggered when a new player joins the room
    public override void OnPlayerEnteredRoom(Player newPlayer) {
        UpdateRemotePlayerInfo();
    }

    // Triggered when a player's custom properties change (like their nickname)
    public override void OnPlayerPropertiesUpdate(Player targetPlayer, ExitGames.Client.Photon.Hashtable changedProps) {
        UpdateRemotePlayerInfo();
    }

    private void UpdateRemotePlayerInfo() {
        // Find and update blue player info
        Player bluePlayer = PhotonNetwork.PlayerList.FirstOrDefault(p => p.ActorNumber == 1);
        if (bluePlayer != null) {
            GameObject blueCharacter = FindPlayerCharacterByActorNumber(1);
            string blueName = bluePlayer.CustomProperties.ContainsKey("Nickname") 
                ? bluePlayer.CustomProperties["Nickname"].ToString() 
                : "Unknown Blue Player";
            
            if (blueCharacter != null) {
                // Store these references in your class variables if needed
                Debug.Log($"Found blue player: {blueName}");
            }
        }

        // Find and update green player info
        Player greenPlayer = PhotonNetwork.PlayerList.FirstOrDefault(p => p.ActorNumber == 2);
        if (greenPlayer != null) {
            GameObject greenCharacter = FindPlayerCharacterByActorNumber(2);
            string greenName = greenPlayer.CustomProperties.ContainsKey("Nickname") 
                ? greenPlayer.CustomProperties["Nickname"].ToString() 
                : "Unknown Green Player";
            
            if (greenCharacter != null) {
                Debug.Log($"Found green player: {greenName}");
            }
        }
    }

    // Reliably find a player's character using their ActorNumber (not object names)
    private GameObject FindPlayerCharacterByActorNumber(int actorNumber) {
        foreach (GameObject obj in GameObject.FindObjectsOfType<GameObject>()) {
            PhotonView pv = obj.GetComponent<PhotonView>();
            if (pv != null && pv.Owner != null && pv.Owner.ActorNumber == actorNumber) {
                return obj;
            }
        }
        return null;
    }
}

3. Critical Setup Checks

  • Add PhotonView to Character Prefabs: Make sure both your BlueSoldier and GreenSoldier prefabs have a PhotonView component attached. This tells Photon which objects to sync across the network.
  • Avoid Hardcoded Object Names: Using GameObject.Find() with clone names is fragile—our FindPlayerCharacterByActorNumber method uses the PhotonView.Owner property to match characters to their players, which is far more reliable.
  • Wait for Network Sync: Don't expect remote characters to exist immediately in Start()—Photon needs time to sync objects across clients, so we use callbacks like OnPlayerEnteredRoom to trigger updates once data is available.

Why This Works

  • Each client only spawns its own character, which is the correct Photon workflow.
  • Player nicknames are stored in synced custom properties, so all clients can access every player's name.
  • We use Photon's built-in callbacks to react to network events, ensuring we only try to access remote characters once they've been synced to the local client.

内容的提问来源于stack exchange,提问作者UnityMan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 15:03:15