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

Unity创建排行榜触发ArgumentNullException,求解决方法

Unity排行榜加载时ArgumentNullException错误排查与解决

错误核心原因

报错ArgumentNullException: Value cannot be null. Parameter name: source的直接原因是**loadedUserData.ListPlayer为null**,导致Linq排序操作没有可操作的数据源。

具体问题点与修复方案

1. 序列化/反序列化工具不匹配

你保存数据用的是Newtonsoft的JsonSerializer,但加载时用的是Unity自带的JsonUtility,两者序列化格式不兼容,导致反序列化后ListPlayer字段为null。

修复:统一使用Newtonsoft.Json进行序列化和反序列化:

  • 确保Unity已导入Newtonsoft.Json包(Package Manager中搜索Newtonsoft Json安装)
  • 同步修改保存和加载逻辑,用JsonConvert替代原有实现

2. ListPlayer未初始化

ListPlayerModel中的ListPlayer字段没有默认初始化,即使序列化正常,空对象也会导致后续操作报错。

修复:给ListPlayerModel添加构造函数初始化列表:

public class UserModel : IDataModel
{
    public int Score;
    public string Day;
    public string Name;
}

[Serializable]
public class ListPlayerModel : IDataModel
{
    public List<UserModel> ListPlayer;

    public ListPlayerModel()
    {
        ListPlayer = new List<UserModel>();
    }
}

3. 保存逻辑优化

将原SaveDataToFile改为更简洁的Newtonsoft实现:

public void SaveDataToFile()
{
    string json = JsonConvert.SerializeObject(this.Model);
    string filePath = Application.persistentDataPath + "/dataUser.json";
    File.WriteAllText(filePath, json);
    Debug.Log("Save success");
}

4. 加载逻辑彻底修复

原加载逻辑存在3个严重问题:嵌套循环重复实例化、错误访问字符串索引(std.Name[i]取的是字符而非完整名称)、未处理文件不存在的情况。修复后的代码:

public void LoadDataToFile()
{
    string filePath = Application.persistentDataPath + "/dataUser.json";
    ListPlayerModel loadedUserData;

    // 处理文件不存在的情况
    if (!File.Exists(filePath))
    {
        loadedUserData = new ListPlayerModel();
        File.WriteAllText(filePath, JsonConvert.SerializeObject(loadedUserData));
        Debug.Log("No data file found, created empty one");
        return;
    }

    // 用Newtonsoft反序列化,匹配保存逻辑
    string outputJson = File.ReadAllText(filePath);
    loadedUserData = JsonConvert.DeserializeObject<ListPlayerModel>(outputJson);

    // 双重保险:确保列表不为null
    if (loadedUserData.ListPlayer == null)
    {
        loadedUserData.ListPlayer = new List<UserModel>();
    }

    // 按分数降序排序,取前3名
    var topPlayers = loadedUserData.ListPlayer.OrderByDescending(p => p.Score).Take(3).ToList();

    // 实例化每个排行榜项
    for (int i = 0; i < topPlayers.Count; i++)
    {
        var currentPlayer = topPlayers[i];
        // 实例化预制体并设置父物体(根据你的UI容器调整)
        GameObject newRankItem = UnityEngine.Object.Instantiate(ListPlayer, transform);
        
        // 调整位置(示例为垂直排列,每个项间隔100像素,可按需修改)
        RectTransform itemRect = newRankItem.GetComponent<RectTransform>();
        itemRect.anchoredPosition = new Vector2(0, -i * 100);

        // 找到预制体内的文本组件并赋值
        Text nameText = newRankItem.transform.Find("ListPlayerName").GetComponent<Text>();
        Text scoreText = newRankItem.transform.Find("ListPlayerScore").GetComponent<Text>();
        Text dayText = newRankItem.transform.Find("ListPlayerDay").GetComponent<Text>();

        nameText.text = currentPlayer.Name;
        scoreText.text = currentPlayer.Score.ToString();
        dayText.text = currentPlayer.Day;
    }
}

5. 额外注意事项

  • 确保排行榜预制体ListPlayer内存在名为ListPlayerName、ListPlayerScore、ListPlayerDay的Text组件
  • 排序用OrderByDescending才能取最高分,原代码的OrderBy是升序,会获取最低分
  • 实例化时务必设置父物体,避免UI元素位置错乱
  • 检查UserView中的SaveUserData方法,确保this.Model.ListPlayer已初始化(通过ListPlayerModel的构造函数已解决)

内容的提问来源于stack exchange,提问作者Ngọc Phát

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 02:50:26