按钮无法激活ObjectPool中Start()创建的子弹问题求助
问题描述
- 按钮按下事件绑定了
Shoot函数,初始化阶段创建子弹后,按下按钮无法激活子弹; - 若将初始化逻辑移至
Shoot方法内,子弹可显示但每次按下都会重复生成新子弹; - 已使用Photon并加入
PhotonNetwork相关代码,仍存在对象激活失败的问题。
相关代码
PlayerShooter.cs
using UnityEngine; public class PlayerShooter : ObjectPool { [SerializeField] private GameObject _bullet; private void Start() { Initialize(_bullet); } public void Shoot() { // Initialize(_bullet); if (TryGetObject(out GameObject bullet)) { bullet.SetActive(true); } } }
ObjectPool.cs
using System.Collections.Generic; using UnityEngine; using System.Linq; public class ObjectPool : MonoBehaviour { [SerializeField] private int _amount; private List<GameObject> _pool = new(); protected void Initialize(GameObject prefab) { for (int i = 0; i < _amount; i++) { GameObject spawned = PhotonNetwork.Instantiate(prefab.name, transform.position, Quaternion.identity); spawned.SetActive(false); _pool.Add(spawned); } } protected bool TryGetObject(out GameObject result) { result = _pool.FirstOrDefault(gameObject => gameObject.activeSelf == false); return result != null; } }
问题排查与解决方案
1. 修复Photon网络对象权限问题
Photon实例化的对象仅由创建它的客户端拥有控制权,直接调用SetActive会因权限限制失效。需通过Photon的RPC实现跨客户端同步激活:
- 给子弹预制体添加
PhotonView组件; - 在子弹脚本中添加RPC方法:
using Photon.Pun; public class Bullet : MonoBehaviourPunCallbacks { [PunRPC] public void ActivateBullet() { gameObject.SetActive(true); } } - 修改
Shoot方法,通过RPC激活子弹:public void Shoot() { if (TryGetObject(out GameObject bullet)) { bullet.GetComponent<PhotonView>().RPC("ActivateBullet", RpcTarget.All); } }
2. 修正对象池初始化与同步
初始化逻辑仅在本地执行时,其他客户端的对象池列表未同步,导致跨端找不到可用对象:
- 确保初始化在Photon连接成功后执行,修改
PlayerShooter的Start方法:private void Start() { if (PhotonNetwork.IsConnectedAndReady) { Initialize(_bullet); } else { PhotonNetwork.NetworkingClient.StateChanged += OnPhotonStateChanged; } } private void OnPhotonStateChanged(ClientState state) { if (state == ClientState.Joined) { Initialize(_bullet); PhotonNetwork.NetworkingClient.StateChanged -= OnPhotonStateChanged; } }
3. 优化TryGetObject方法
原方法使用FirstOrDefault可能因网络同步延迟导致状态判断错误,改为遍历检查对象有效性:
protected bool TryGetObject(out GameObject result) { result = null; foreach (var obj in _pool) { if (obj != null && !obj.activeSelf) { result = obj; break; } } return result != null; }
4. 避免重复初始化
确保Initialize方法仅执行一次,添加标记位:
private bool _isInitialized = false; protected void Initialize(GameObject prefab) { if (_isInitialized) return; for (int i = 0; i < _amount; i++) { GameObject spawned = PhotonNetwork.Instantiate(prefab.name, transform.position, Quaternion.identity); spawned.SetActive(false); _pool.Add(spawned); } _isInitialized = true; }
内容的提问来源于stack exchange,提问作者user21403547
相关产品推荐
相关产品推荐

