拉緹娜 2025-07-16 20:27 采纳率: 47.1%
浏览 9

Unity中关于System.Flags类型的JSON数据的解析

public class SkillData
{
    public int id;
    public string name;
    public enum Type { Attack, Buff, DeBuff, Special }
    public Type type;

    [System.Flags]
    public enum Tags
    {
        None = 0,
        Melee = 0x1,
        Ranged = 0x2,
        AoE = 0x4
    }
    public Tags tags;
    public bool read;
    public float cooldown;
    public int cost;
}
[System.Serializable]
public class SkillDatas
{
    public SkillData[] skills;
}

    void Start()
    {
        TextAsset jsonFile = Resources.Load<TextAsset>("SkillDatas");
        SkillDatas skillDatas = JsonUtility.FromJson<SkillDatas>(jsonFile.text);
        foreach (SkillData s in skillDatas.skills)
        {
            GameObject button = Instantiate(buttonPrefab, content);
            button.GetComponentInChildren<Text>().text = FormatSkillInfo(s);
            Debug.Log(s.tags);
        }
        LayoutRebuilder.ForceRebuildLayoutImmediate(content.GetComponent<RectTransform>());
    }
private string FormatSkillInfo(SkillData s)
{
    return $"{s.name}\n" +
       $"ID: {s.id}\t" +
       $"\tType: {s.type}\t" +
       $"\tTags: {s.tags.ToString()}\n" +
       $"Read: {(s.read ? "Yes" : "No")}\t" +
       $"\tCooldown: {s.cooldown}s\t" +
       $"\tCost: {s.cost}";
}

上面是一个存放在JSON中的数据类型以及解析代码,JSON具体内容为

{
  "skills": [
    {
      "id": 101,
      "name": "Power Slash",
      "type": "Attack",
      "tags": "Melee",
      "read": true,
      "cooldown": 3.0,
      "cost": 10
    },
    {
      "id": 102,
      "name": "Fireball",
      "type": "Attack",
      "tags": "Ranged, AoE",
      "read": true,
      "cooldown": 5.0,
      "cost": 20
    },
  //其他数据
}

在解析后分批把内容显示在button的text上,但是唯独tags显示全是None

img

  • 写回答

6条回答 默认 最新

  • 檀越@新空间 2025-07-16 20:28
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    在Unity中使用 JsonUtility 解析带有 [System.Flags] 枚举的JSON数据时,可能会遇到 枚举值无法正确解析 的问题。这是因为 JsonUtility 并不支持直接解析标志枚举(Flags Enum)的复合值(如 "Ranged, AoE"),它会将整个字符串当作一个整数来处理。


    问题分析

    你当前的代码中,Tags 是一个带有 [System.Flags] 的枚举:

    [System.Flags]
    public enum Tags
    {
        None = 0,
        Melee = 0x1,
        Ranged = 0x2,
        AoE = 0x4
    }
    

    但是,在JSON中你写的是:

    "tags": "Ranged, AoE"
    

    这表示你希望 tags 被解析为 Ranged | AoE,但 JsonUtility 无法识别这种格式,因此会将其视为 None


    解决方案

    解决方案一:手动解析 JSON 字符串

    由于 JsonUtility 不支持标志枚举的复合值,你需要在解析后手动将字符串转换为对应的枚举值。

    步骤如下:

    1. 修改 SkillData 类,去掉 [System.Flags] 属性
    2. 使用字符串存储 tags
    3. 在解析后手动转换成 Tags 枚举

    修改后的 SkillData 类:

    [System.Serializable]
    public class SkillData
    {
        public int id;
        public string name;
        public enum Type { Attack, Buff, DeBuff, Special }
        public Type type;
    
        // 去掉 [System.Flags] 属性
        public string tags; // 存储原始字符串
        public bool read;
        public float cooldown;
        public int cost;
    }
    

    修改 Start() 方法:

    void Start()
    {
        TextAsset jsonFile = Resources.Load<TextAsset>("SkillDatas");
        SkillDatas skillDatas = JsonUtility.FromJson<SkillDatas>(jsonFile.text);
        
        foreach (SkillData s in skillDatas.skills)
        {
            // 手动解析 tags 字符串
            s.tags = ParseTags(s.tags);
    
            GameObject button = Instantiate(buttonPrefab, content);
            button.GetComponentInChildren<Text>().text = FormatSkillInfo(s);
            Debug.Log(s.tags);
        }
    
        LayoutRebuilder.ForceRebuildLayoutImmediate(content.GetComponent<RectTransform>());
    }
    
    private string ParseTags(string tagString)
    {
        if (string.IsNullOrEmpty(tagString))
            return "None";
    
        string[] tags = tagString.Split(',');
        Tags result = Tags.None;
    
        foreach (string tag in tags)
        {
            string trimmedTag = tag.Trim();
            if (Enum.TryParse(trimmedTag, out Tags t))
            {
                result |= t;
            }
        }
    
        return result.ToString(); // 返回解析后的字符串
    }
    

    修改 FormatSkillInfo 方法:

    private string FormatSkillInfo(SkillData s)
    {
        return $"{s.name}\n" +
           $"ID: {s.id}\t" +
           $"\tType: {s.type}\t" +
           $"\tTags: {s.tags}\n" + // 现在是字符串
           $"Read: {(s.read ? "Yes" : "No")}\t" +
           $"\tCooldown: {s.cooldown}s\t" +
           $"\tCost: {s.cost}";
    }
    

    解决方案二:使用自定义 JSON 解析器

    如果你需要更复杂的解析逻辑,可以考虑使用 Newtonsoft.Json(Json.NET),它支持标志枚举的解析。

    安装 Newtonsoft.Json 包:

    1. 在 Unity 中通过 Package Manager 安装 Newtonsoft.Json
    2. 使用 JsonConvert.DeserializeObject<T> 替代 JsonUtility

    示例代码:

    using Newtonsoft.Json;
    
    void Start()
    {
        TextAsset jsonFile = Resources.Load<TextAsset>("SkillDatas");
        SkillDatas skillDatas = JsonConvert.DeserializeObject<SkillDatas>(jsonFile.text);
        
        foreach (SkillData s in skillDatas.skills)
        {
            GameObject button = Instantiate(buttonPrefab, content);
            button.GetComponentInChildren<Text>().text = FormatSkillInfo(s);
            Debug.Log(s.tags);
        }
    
        LayoutRebuilder.ForceRebuildLayoutImmediate(content.GetComponent<RectTransform>());
    }
    

    此时你可以保留 [System.Flags] 属性,并且 JsonConvert 会自动解析 "Ranged, AoE"Ranged | AoE


    ✅ 总结

    | 问题 | 原因 | 解决方案 | |------|------|----------| | tags 显示为 None | JsonUtility 不支持标志枚举的复合值 | 手动解析使用 Newtonsoft.Json | | JsonUtility 无法处理 Ranged, AoE 格式 | JsonUtility 不支持字符串到标志枚举的映射 | 修改字段类型为 string,并手动转换 |


    ✅ 推荐做法

    推荐使用解决方案一或二,取决于你的项目是否允许引入第三方库(如 Newtonsoft.Json)。如果项目规模较小,手动解析是更轻量的方式;如果项目复杂度高,建议使用 Newtonsoft.Json 提升灵活性和可维护性。


    如有需要,我可以提供完整的 SkillDataSkillDatas 类的完整代码示例。

    评论

报告相同问题?

问题事件

  • 创建了问题 7月16日