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

PhotonNetwork.Instantiate异常:玩家对象无法实例化问题排查

问题排查与修复方案

核心问题分析

玩家无法实例化的根源在于两个脚本的异步逻辑处理错误,以及Photon网络流程的顺序违规,具体问题如下:

一、Photon_Manager脚本的关键错误

  1. 场景加载时机错误:调用PhotonNetwork.CreateRoom()或PhotonNetwork.JoinRoom()后立刻执行场景加载,这两个操作是异步的,此时玩家并未真正加入房间,直接加载场景会导致后续网络状态异常。
  2. 协程使用无效:所有StartCoroutine(waitSeconds())的调用都没有等待协程完成,代码直接继续执行,等待逻辑完全失效。
  3. UI切换时机错误:LogIn()中调用PhotonNetwork.ConnectUsingSettings()后立刻切换到创建/加入房间UI,但此时网络连接尚未完成,后续房间操作可能失败。

二、Instantiate_Player脚本的关键错误

  1. 实例化逻辑未等待协程:Start()中启动等待协程后直接执行玩家实例化判断,协程的等待没有生效,此时PhotonNetwork.IsConnectedAndReady可能仍为false,导致实例化代码不执行。
  2. 未确保预制体加载路径正确:PhotonNetwork.Instantiate()要求预制体必须放在Resources文件夹下,否则无法找到预制体。

修复后的代码

1. 修改后的Photon_Manager脚本

using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using Photon.Realtime;

public class Photon_Manager : MonoBehaviourPunCallbacks
{
    [SerializeField] TMP_InputField nameField;
    [SerializeField] TMP_InputField roomNameField;
    [SerializeField] TMP_InputField joinRoomField;

    [SerializeField] GameObject createJoinCanvas;
    [SerializeField] GameObject logInCanvas;
    [SerializeField] GameObject createCanvas;
    [SerializeField] GameObject joinCanvas;

    [SerializeField] string sceneToLoad;

    [SerializeField] public bool createRoomStatus = false;
    [SerializeField] public bool joinRoomStatus = false;
    [SerializeField] public bool logInStatus = false;   

    public override void OnConnectedToMaster()
    {
        Debug.Log("Connected to master server");
        PhotonNetwork.JoinLobby();
        // 连接成功后再显示创建/加入房间UI
        logInCanvas.SetActive(false);
        createJoinCanvas.SetActive(true);
        logInStatus = true;
        Debug.Log("LogIn Done");
    }

    public override void OnCreatedRoom()
    {
        Debug.Log("Created room: " + PhotonNetwork.CurrentRoom.Name);
    }

    // 加入房间成功后加载游戏场景
    public override void OnJoinedRoom()
    {
        Debug.Log(PhotonNetwork.LocalPlayer.NickName + " joined " + PhotonNetwork.CurrentRoom.Name);
        StartCoroutine(WaitAndLoadScene(sceneToLoad));
        // 根据操作类型更新UI与状态
        if(createRoomStatus)
        {
            createCanvas.SetActive(false);
        }
        else if(joinRoomStatus)
        {
            joinCanvas.SetActive(false);
        }
    }

    void Start()
    {
        Debug.Log("Photon Manager started");
    }

    public void LogIn()
    {
        string temp = nameField.text;
        if(!string.IsNullOrEmpty(temp))
        {
            PhotonNetwork.LocalPlayer.NickName = temp;
            PhotonNetwork.ConnectUsingSettings();
            logInCanvas.SetActive(false);
        }
        else
        {
            Debug.LogError("Nickname cannot be empty!");
        }
    }

    public void CreateRoom()
    {
        string roomName = roomNameField.text;
        if(!string.IsNullOrEmpty(roomName))
        {
            createRoomStatus = true;
            joinRoomStatus = false;
            PhotonNetwork.CreateRoom(roomName);
        }
        else
        {
            Debug.LogError("Room name cannot be empty!");
        }
    }

    public void JoinRoom()
    {
        string tempRoomName = joinRoomField.text;
        if(!string.IsNullOrEmpty(tempRoomName))
        {
            joinRoomStatus = true;
            createRoomStatus = false;
            PhotonNetwork.JoinRoom(tempRoomName);
        }
        else
        {
            Debug.LogError("Room name cannot be empty!");
        }
    }

    // 带等待的场景加载协程
    private IEnumerator WaitAndLoadScene(string sceneName)
    {
        yield return new WaitForSeconds(2.5f);
        PhotonNetwork.LoadLevel(sceneName);
    }
}

2. 修改后的Instantiate_Player脚本

using UnityEngine;
using Photon.Pun;
using System.Collections;

public class Instantiate_Player : MonoBehaviour
{
    [SerializeField] GameObject playerPrefab;

    [SerializeField] float xMin;
    [SerializeField] float zMin;
    [SerializeField] float xMax;
    [SerializeField] float zMax;

    void Start()
    {
        // 将实例化逻辑放入协程,确保等待后执行
        StartCoroutine(WaitAndSpawnPlayer());
    }

    private IEnumerator WaitAndSpawnPlayer()
    {
        yield return new WaitForSeconds(1.5f);
        
        // 循环检查网络状态,直到就绪
        while(!PhotonNetwork.IsConnectedAndReady)
        {
            yield return null;
        }

        // 确保预制体存在且在Resources文件夹中
        if(playerPrefab != null)
        {
            Vector3 playerPos = new Vector3(Random.Range(xMin, xMax), 0.0f, Random.Range(zMin, zMax));
            // 使用默认groupID 0
            GameObject obj = PhotonNetwork.Instantiate(playerPrefab.name, playerPos, Quaternion.identity);
            obj.SetActive(true);
            Debug.Log("Player instantiated successfully");
        }
        else
        {
            Debug.LogError("Player prefab is not assigned!");
        }
    }
}

额外注意事项

  • 玩家预制体必须放置在Resources文件夹下,PhotonNetwork.Instantiate()只能加载该目录下的资源。
  • 预制体上的PhotonView组件需正确配置:View ID设置为AutoSync,并将需要同步的组件(如移动脚本)添加到观察列表中。
  • 检查PhotonServerSettings的App ID、Region等参数,确保与Photon Dashboard配置一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 04:54:12