基于Photon PUN 2实现多人游戏本地启用死亡玩家Up Camera
问题:Photon PUN2中仅让本地死亡玩家切换到 spectator camera
在基于Photon PUN 2开发的多人游戏中,目标是实现玩家死亡时启用名为“Up Camera”的 spectator camera,但当前存在问题:玩家死亡时该相机会对所有玩家全局启用,未死亡玩家也会强制切换到该相机。伤害数据由包含射击者ID与被击中玩家ID的projectile传递,当前使用的damageMenager脚本如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using Photon.Pun; public class damageMenager : MonoBehaviour { public int hp; public GameObject player; public Image hpBar; public PlayerSpawner playerSpawner; public void Update() { if(this.gameObject == player) { hpBar.fillAmount = hp / 100f ; } } private void Awake() { playerSpawner = FindObjectOfType<PlayerSpawner>(); } public void takeDamage(int damage, GameObject otherPlayer, int shooterId) { if (otherPlayer.GetPhotonView() != null) { if (otherPlayer.GetPhotonView().ViewID != shooterId) { if (hp <= 0) { foreach (Transform tm in otherPlayer.transform) { if (tm.GetComponent<wheelController>() != null) { tm.GetComponent<wheelController>().enabled = false; } } otherPlayer.transform.Find("Camera").gameObject.SetActive(false); otherPlayer.transform.Find("CM FreeLook1").gameObject.SetActive(false); otherPlayer.transform.Find("Canvas").gameObject.SetActive(false); otherPlayer.GetComponent<tuttiPU>().enabled = false; otherPlayer.GetComponent<mina>().enabled = false; otherPlayer.GetComponent<Inpiedi>().enabled = false; otherPlayer.GetComponent<cannoniDavanti>().enabled = false; otherPlayer.GetComponent<localPlayerManager>().enabled = false; otherPlayer.GetComponent<damageMenager>().enabled = false; otherPlayer.transform.Find("Up Camera").gameObject.SetActive(true); } else { hp -= damage; } } } } }
解决方案
核心问题在于当前代码在所有客户端执行了相机切换逻辑,而相机切换是本地客户端专属操作,不该全局同步执行。只需通过Photon的IsMine属性判断操作对象是否为本地玩家,即可实现仅在死亡玩家的本地设备启用 spectator camera。
修改后的代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using Photon.Pun; public class damageMenager : MonoBehaviour { [SyncVar(hook = nameof(OnHpChanged))] // 同步生命值,确保客户端状态一致 public int hp = 100; public GameObject player; public Image hpBar; public PlayerSpawner playerSpawner; public void Update() { if(this.gameObject == player) { hpBar.fillAmount = hp / 100f ; } } private void Awake() { playerSpawner = FindObjectOfType<PlayerSpawner>(); } // SyncVar钩子:生命值变化时自动更新UI(优化体验) private void OnHpChanged(int oldHp, int newHp) { if(this.gameObject == player) { hpBar.fillAmount = newHp / 100f; } } public void takeDamage(int damage, GameObject otherPlayer, int shooterId) { var photonView = otherPlayer.GetPhotonView(); if (photonView == null) return; if (photonView.ViewID == shooterId) return; if (hp <= 0) { // 所有客户端通用的死亡逻辑(禁用非本地控制组件) foreach (Transform tm in otherPlayer.transform) { var wheelCtrl = tm.GetComponent<wheelController>(); if (wheelCtrl != null) { wheelCtrl.enabled = false; } } otherPlayer.GetComponent<tuttiPU>().enabled = false; otherPlayer.GetComponent<mina>().enabled = false; otherPlayer.GetComponent<Inpiedi>().enabled = false; otherPlayer.GetComponent<cannoniDavanti>().enabled = false; otherPlayer.GetComponent<damageMenager>().enabled = false; // 仅在本地玩家的客户端执行相机/UI切换 if (photonView.IsMine) { otherPlayer.transform.Find("Camera").gameObject.SetActive(false); otherPlayer.transform.Find("CM FreeLook1").gameObject.SetActive(false); otherPlayer.transform.Find("Canvas").gameObject.SetActive(false); otherPlayer.GetComponent<localPlayerManager>().enabled = false; otherPlayer.transform.Find("Up Camera").gameObject.SetActive(true); } } else { // 仅服务器端修改生命值,防止客户端恶意篡改 if (PhotonNetwork.IsMasterClient) { hp -= damage; } } } }
关键改动说明
- 同步生命值:给
hp添加[SyncVar]属性,确保所有客户端的生命值状态一致,避免逻辑冲突。 - 本地玩家判断:将相机切换、UI隐藏、本地控制组件禁用等操作放在
photonView.IsMine判断内,仅让死亡玩家的本地设备执行这些操作。 - 服务器端控血:生命值修改由MasterClient(服务器)执行,杜绝客户端篡改数据的可能。
内容的提问来源于stack exchange,提问作者Fabbr0
相关产品推荐
相关产品推荐

