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

Photon.Pun FPS游戏玩家重复生成Bug修复求助

问题描述

开发基于Photon.Pun的FPS游戏时,遇到以下问题:当房间内已有玩家时,新玩家加入后会出现其他玩家重复生成的情况。打印生成日志显示SpawnPlayer仅执行一次,推测问题出在实例化相关逻辑中。以下是RoomManager脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using TMPro;
using Unity.VisualScripting;
using Photon.Realtime;

public class RoomManager : MonoBehaviourPunCallbacks
{

    public static RoomManager instance;

    public GameObject player;
    public GameObject playersWeapon;
    [Space]
    public Transform spawnPoint;

    public GameObject Connectingcam;

    public TextMeshPro placeholderText;
    

    public string nickname;

    private pauseScript pauseScreenScript;



    [Space]
    public GameObject nameUI;
    public GameObject connectUI;

    void Awake()
    {
        instance = this;
    }
    public void ChangeNickname(string n)
    {
        nickname = n;
    }

    public void JoinRoomButtonPressed()
    {
        nameUI.SetActive(false);
        connectUI.SetActive(true);
        if(nickname == "")
        {
            nickname = "이름없는사용자" + Random.Range(0, 99999).ToString();
        }
        Debug.Log("Connecting to Server");
        PhotonNetwork.ConnectUsingSettings();
    }

    // Start is called before the first frame update
    void Start()
    {

    }

    public override void OnConnectedToMaster()
    {
        base.OnConnectedToMaster();
        Debug.Log("Connected to Server");
        PhotonNetwork.JoinLobby();
    }

    public override void OnJoinedLobby()
    {
        base.OnJoinedLobby();
        PhotonNetwork.JoinOrCreateRoom("test", null, null);
    }

    public override void OnJoinedRoom()
    {
        Connectingcam.SetActive(false);
        
        base.OnJoinedRoom();
        Debug.Log("Joined Room");
        SpawnPlayer();
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public override void OnDisconnected(DisconnectCause cause)
    {
        base.OnDisconnected(cause);
        Debug.Log("Disconnected from Server");

    }

    public override void OnPlayerEnteredRoom(Player newPlayer)
    {
        base.OnPlayerEnteredRoom(newPlayer);
    }

    public void SpawnPlayer(){
        if(PhotonNetwork.IsConnected && PhotonNetwork.LocalPlayer.IsLocal)
        {
            Debug.Log("Spawning Player");
            GameObject _player = PhotonNetwork.Instantiate(player.name, spawnPoint.position, Quaternion.identity);
            _player.GetComponent<PlayerSetup>().IsLocalPlayer();
            _player.GetComponent<HP>().IsLocalPlayer = true;
            _player.GetComponent<voidDeath>().IsLocalPlayer = true;
            _player.GetComponentInChildren<Weapon>().IsLocalPlayer = true;
            _player.GetComponent<PhotonView>().RPC("SetNickname", RpcTarget.AllBuffered, nickname);
            PhotonNetwork.LocalPlayer.NickName = nickname;
            Debug.Log("Spawned Player");
        }

        
    }

    public void killPlayer()
    {

    }  
}
修复方案

1. 修正玩家预制体的实例化路径

PhotonNetwork.Instantiate要求预制体必须放在Resources文件夹下,且传入的是Resources内的相对路径,而非直接使用player.name。路径错误会导致Photon无法正确同步实例,引发异常生成。

修改SpawnPlayer中的实例化代码:

// 假设玩家预制体放在Resources/Players目录下,路径改为对应相对路径
GameObject _player = PhotonNetwork.Instantiate("Players/Player", spawnPoint.position, Quaternion.identity);

2. 优化本地玩家初始化逻辑

避免手动赋值IsLocalPlayer时出现范围错误,通过PhotonView.IsMine精准判断本地玩家:

public void SpawnPlayer(){
    if(PhotonNetwork.IsConnected && PhotonNetwork.LocalPlayer.IsLocal)
    {
        Debug.Log("Spawning Player");
        GameObject _player = PhotonNetwork.Instantiate("Players/Player", spawnPoint.position, Quaternion.identity);
        PhotonView playerView = _player.GetComponent<PhotonView>();
        
        // 仅对本地玩家执行初始化操作
        if(playerView.IsMine)
        {
            _player.GetComponent<PlayerSetup>().IsLocalPlayer();
            _player.GetComponent<HP>().IsLocalPlayer = true;
            _player.GetComponent<voidDeath>().IsLocalPlayer = true;
            _player.GetComponentInChildren<Weapon>().IsLocalPlayer = true;
            playerView.RPC("SetNickname", RpcTarget.AllBuffered, nickname);
            PhotonNetwork.LocalPlayer.NickName = nickname;
        }
        Debug.Log("Spawned Player");
    }
}

3. 确保RoomManager单例不重复创建

在Awake中添加单例校验和DontDestroyOnLoad,防止场景切换时生成多个RoomManager实例,避免重复调用SpawnPlayer:

void Awake()
{
    // 销毁重复的单例实例
    if(instance != null && instance != this)
    {
        Destroy(gameObject);
        return;
    }
    instance = this;
    DontDestroyOnLoad(gameObject);
}

4. 检查玩家预制体的Photon配置

  • 玩家预制体必须挂载PhotonView组件,并在Observed Components中添加需要同步的组件(如Transform、Animator),确保Photon能正确同步玩家状态,避免重复生成的假象。
  • 确保预制体的PhotonView的View ID设置为AutoSync,由Photon自动分配唯一ID。

5. 排查额外的SpawnPlayer触发逻辑

检查项目中是否有其他脚本调用了RoomManager.instance.SpawnPlayer(),比如场景加载事件、UI误触发等,确保只有OnJoinedRoom时才执行玩家生成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 01:08:11