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

Unity3D中基于ScriptableObject实现可编辑的复杂奖励数据结构

实现支持Unity编辑器可视化编辑的Roguelike奖励系统ScriptableObject

因为Unity编辑器不支持直接序列化Dictionary并提供可视化编辑界面,我们可以用可序列化的嵌套类+列表来模拟Lua嵌套表的结构,同时在运行时构建字典缓存保证查询效率。具体实现步骤如下:

1. 定义基础枚举与数据类

先明确核心分类的枚举,以及单个奖励的结构:

// 职业枚举
public enum CharacterClass
{
    Melee,
    Healer,
    Ranger,
    Mage
}

// 稀有度枚举
public enum RewardRarity
{
    Common,
    Uncommon,
    Rare,
    Legendary
}

// 单个奖励的具体数据,标记为可序列化让编辑器识别
[Serializable]
public class RewardEntry
{
    public string rewardName;
    public int statBoost;
    public Sprite rewardIcon;
    // 可根据需求添加更多属性(如物品ID、技能解锁标记等)
}

2. 构建嵌套的可序列化组类

用两层嵌套的可序列化类,对应「职业→稀有度→奖励列表」的层级:

// 单个稀有度对应的奖励组
[Serializable]
public class RarityRewardGroup
{
    public RewardRarity rarity;
    public List<RewardEntry> rewards = new List<RewardEntry>();
}

// 单个职业对应的稀有度奖励组集合
[Serializable]
public class ClassRewardGroup
{
    public CharacterClass characterClass;
    public List<RarityRewardGroup> rarityGroups = new List<RarityRewardGroup>();
}

3. 实现核心ScriptableObject

用List<ClassRewardGroup>替代外层字典,同时在内部构建字典缓存用于运行时快速查询:

[CreateAssetMenu(fileName = "RewardDatabase", menuName = "Roguelike/Reward Database")]
public class RewardDatabase : ScriptableObject
{
    // 编辑器可见的列表,支持直接增删改
    [SerializeField] private List<ClassRewardGroup> classRewardGroups = new List<ClassRewardGroup>();
    
    // 运行时缓存用的字典,保证查询效率
    private Dictionary<CharacterClass, Dictionary<RewardRarity, List<RewardEntry>>> _rewardCache;

    private void OnEnable()
    {
        BuildRewardCache();
    }

    private void OnValidate()
    {
        // 编辑器修改数据时自动更新缓存
        BuildRewardCache();
    }

    // 构建运行时查询用的字典缓存
    private void BuildRewardCache()
    {
        _rewardCache = new Dictionary<CharacterClass, Dictionary<RewardRarity, List<RewardEntry>>>();
        
        foreach (var classGroup in classRewardGroups)
        {
            var rarityDict = new Dictionary<RewardRarity, List<RewardEntry>>();
            foreach (var rarityGroup in classGroup.rarityGroups)
            {
                // 处理重复稀有度的情况(可选,根据需求覆盖或报错)
                if (rarityDict.ContainsKey(rarityGroup.rarity))
                {
                    Debug.LogWarning($"重复的稀有度 {rarityGroup.rarity} 存在于职业 {classGroup.characterClass} 中,已覆盖原有数据");
                }
                rarityDict[rarityGroup.rarity] = new List<RewardEntry>(rarityGroup.rewards);
            }
            _rewardCache[classGroup.characterClass] = rarityDict;
        }
    }

    // 对外提供的查询方法
    public List<RewardEntry> GetRewards(CharacterClass characterClass, RewardRarity rarity)
    {
        if (_rewardCache.TryGetValue(characterClass, out var rarityDict) && rarityDict.TryGetValue(rarity, out var rewards))
        {
            return rewards;
        }
        Debug.LogWarning($"未找到职业 {characterClass}、稀有度 {rarity} 对应的奖励");
        return new List<RewardEntry>();
    }
}

4. 编辑器增强(可选)

添加自定义Editor类,自动校验重复的职业/稀有度,避免配置错误:

#if UNITY_EDITOR
using UnityEditor;
using System.Linq;

[CustomEditor(typeof(RewardDatabase))]
public class RewardDatabaseEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        
        var db = target as RewardDatabase;
        if (db == null) return;
        
        // 检查重复职业
        var duplicateClasses = db.classRewardGroups.GroupBy(g => g.characterClass)
            .Where(g => g.Count() > 1)
            .Select(g => g.Key);
        
        if (duplicateClasses.Any())
        {
            EditorGUILayout.HelpBox($"发现重复职业:{string.Join(", ", duplicateClasses)}", MessageType.Warning);
        }
        
        // 检查每个职业下的重复稀有度
        foreach (var classGroup in db.classRewardGroups)
        {
            var duplicateRarities = classGroup.rarityGroups.GroupBy(g => g.rarity)
                .Where(g => g.Count() > 1)
                .Select(g => g.Key);
            
            if (duplicateRarities.Any())
            {
                EditorGUILayout.HelpBox($"职业 {classGroup.characterClass} 下存在重复稀有度:{string.Join(", ", duplicateRarities)}", MessageType.Warning);
            }
        }
    }
}
#endif

使用方式

  1. 在Unity编辑器右键菜单选择Roguelike/Reward Database,创建奖励数据库资产
  2. 在Inspector面板中直接添加/删除ClassRewardGroup,选择对应职业
  3. 每个职业组下添加RarityRewardGroup,选择稀有度并填充奖励条目
  4. 代码中通过GetRewards()方法按职业和稀有度查询奖励

内容的提问来源于stack exchange,提问作者mAts

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 08:45:17