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

Unity中使用Photon PUN时玩家自定义属性返回null如何解决?

核心问题(导致属性返回null/值错误)

  1. SetCustomProperties方法参数未正确使用:你传入了string类型的icon参数,但实际给customProperties["icon"]赋值时写死了字符串"icon",而不是传入的参数值,导致不管你传什么动物名,最终存的都是固定的"icon"字符串。
  2. 属性读取时机错误:Photon的自定义属性同步是异步操作,调用SetCustomProperties后立即读取PhotonNetwork.LocalPlayer.CustomProperties,很大概率属性还没完成同步,就会返回null。
  3. 未确认房间连接状态就操作属性:你在Start方法里直接调用分配逻辑,此时如果客户端还没完成加入房间的流程,Photon的玩家属性接口还不可用,也会导致设置/读取失败。
  4. 去重逻辑未同步:你现在的打乱、删除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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 16:57:03