Unity中使用Photon PUN时玩家自定义属性返回null如何解决?
核心问题(导致属性返回null/值错误)
- SetCustomProperties方法参数未正确使用:你传入了string类型的icon参数,但实际给
customProperties["icon"]赋值时写死了字符串"icon",而不是传入的参数值,导致不管你传什么动物名,最终存的都是固定的"icon"字符串。 - 属性读取时机错误:Photon的自定义属性同步是异步操作,调用
SetCustomProperties后立即读取PhotonNetwork.LocalPlayer.CustomProperties,很大概率属性还没完成同步,就会返回null。 - 未确认房间连接状态就操作属性:你在Start方法里直接调用分配逻辑,此时如果客户端还没完成加入房间的流程,Photon的玩家属性接口还不可用,也会导致设置/读取失败。
- 去重逻辑未同步:你现在的打乱、删除icon操作都是在本地客户端执行的,不同客户端之间的icon列表状态完全不同步,无法保证多玩家分配的字符串不重复,要实现全局唯一需要由房主统一分配再同步给所有玩家。
代码冗余/不合理点
SetCustomProperties里的判空逻辑完全没用:你每次调用方法都新建了一个空的customProperties哈希表,判断空表是否包含"icon"键永远为true,这段逻辑可以直接删掉。- 类里定义的
playerProperties哈希表、shuffledIcons列表、b变量、Start方法里的hash变量都是定义后未使用的冗余代码,可以删除。 - 公有SpriteRenderer字段你直接用
new SpriteRenderer()初始化是错误的,Unity的MonoBehaviour组件不能直接new创建,应该删掉初始化代码,在Inspector面板里拖拽对应场景中的组件赋值。 - 取打乱后icon的时候写死了
icons[1],应该取第一个icons[0]更合理,删除的时候也对应删第一个元素。 - 最后遍历玩家设置Sprite的部分可以用字典优化,不用写一堆if else。
修复后的核心代码示例
using System.Collections; using System.Collections.Generic; using UnityEngine; using Photon.Pun; using Photon.Realtime; public class PropertyAssigner : MonoBehaviourPunCallbacks { // 删掉原来的new初始化,从Inspector赋值 public SpriteRenderer Donkey; public SpriteRenderer Elephant; public SpriteRenderer Porcupine; public SpriteRenderer Beaver; public SpriteRenderer Eagle; public SpriteRenderer Bird; public SpriteRenderer Dinosaur; public SpriteRenderer Rhino; public Sprite DonkeySp; public Sprite ElephantSp; public Sprite PorcupineSp; public Sprite BeaverSp; public Sprite EagleSp; public Sprite BirdSp; public Sprite DinosaurSp; public Sprite RhinoSp; List<string> icons = new List<string>(); // 用字典存图标映射,简化后续判断 private Dictionary<string, SpriteRenderer> iconToRenderer; private Dictionary<string, Sprite> iconToSprite; void Awake() { // 初始化映射字典 iconToRenderer = new Dictionary<string, SpriteRenderer>() { {"Donkey", Donkey}, {"Elephant", Elephant}, {"Porcupine", Porcupine}, {"Beaver", Beaver}, {"Eagle", Eagle}, {"Bird", Bird}, {"Dinosaur", Dinosaur}, {"Rhino", Rhino} }; iconToSprite = new Dictionary<string, Sprite>() { {"Donkey", DonkeySp}, {"Elephant", ElephantSp}, {"Porcupine", PorcupineSp}, {"Beaver", BeaverSp}, {"Eagle", EagleSp}, {"Bird", BirdSp}, {"Dinosaur", DinosaurSp}, {"Rhino", RhinoSp} }; icons.Add("Donkey"); icons.Add("Elephant"); icons.Add("Porcupine"); icons.Add("Beaver"); icons.Add("Eagle"); icons.Add("Bird"); icons.Add("Dinosaur"); icons.Add("Rhino"); } // 加入房间成功后再执行分配逻辑,代替原来的Start调用 public override void OnJoinedRoom() { // 只有房主统一分配,保证全局不重复 if (PhotonNetwork.IsMasterClient) { ShuffleIcons(); // 给所有玩家分配唯一图标 for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++) { string assignedIcon = icons[i]; ExitGames.Client.Photon.Hashtable customProperties = new ExitGames.Client.Photon.Hashtable(); customProperties["icon"] = assignedIcon; PhotonNetwork.PlayerList[i].SetCustomProperties(customProperties); } } } // 玩家属性更新后触发,在这里读取属性就不会拿到null了 public override void OnPlayerPropertiesUpdate(Player targetPlayer, ExitGames.Client.Photon.Hashtable changedProps) { if (changedProps.ContainsKey("icon")) { string icon = changedProps["icon"].ToString(); if (iconToRenderer.TryGetValue(icon, out var renderer) && iconToSprite.TryGetValue(icon, out var sprite)) { renderer.sprite = sprite; Debug.Log($"{icon} Sprite 已设置"); } // 测试读取 Debug.Log($"玩家 {targetPlayer.NickName} 分配的图标是:{icon}"); } } void ShuffleIcons() { for (int i = 0; i < icons.Count; i++) { string temp = icons[i]; int randomIndex = Random.Range(i, icons.Count); icons[i] = icons[randomIndex]; icons[randomIndex] = temp; } } }
内容的提问来源于stack exchange,提问作者Alador
相关产品推荐
相关产品推荐

