Unity数据驱动的组件模式?

#创作灵感#

记录一下最近的练习项目

废话少说,我们数据驱动有很多办法,最简单的就是通过unity的scriptObject加上一层逻辑层来驱动,但是为了方便策划,我们会使用一些表工具,比如luban。这个自己的学习项目呢(没写完),我是通过luban配置数据变成json导入unity,然后通过一个configManager来处理导入的,后来发现每次都要为一个表写一个很麻烦,后面就考虑通过editor工具自动化配置(待完善)

using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using SimpleJSON;
using CDTU.Utils;
using CDTU.LogHelper;
using Hotfix.Config;

[DefaultExecutionOrder(-200)]
public sealed class ConfigManager : SingletonDD<ConfigManager>, IConfigManager
{    private TablesComponent _tables;
    public bool IsInitialized { get; private set; } = false;

    // 缓存所有表的JSON内容
    private Dictionary<string, JSONNode> _jsonCache = new Dictionary<string, JSONNode>();

    // 配置表名称列表 - 根据实际配置表扩展
    private static readonly List<string> ConfigTableNames = new List<string>
    {
        "tbcharacterinfo",
        "tbcharacterlevel",
        "tbweapon",
        //TODO- 在这里添加其他配置表名称
    };

    // 初始化任务,避免async void
    private Task _initializationTask;


    protected override void Awake()
    {
        base.Awake();
        _ = ConfigManager.Instance;
        // 启动初始化但不等待,避免async void
        _initializationTask = Initialize();
    }

    /// <summary>
    /// 等待初始化完成
    /// </summary>
    public async Task WaitForInitialization()
    {
        if (_initializationTask != null)
        {
            await _initializationTask;
        }
    }

    /// <summary>
    /// 初始化所有配置表
    /// </summary>
    public async Task Initialize()
    {
        if (IsInitialized) return;

        LogHelper.Log("开始初始化配置管理器...");

        // 加载所有配置表的JSON数据
        var loadTasks = ConfigTableNames.Select(LoadConfigJson);
        await Task.WhenAll(loadTasks);        // 构造 TablesComponent,传入JSON加载器
        _tables = new TablesComponent(tableName =>
        {
            _jsonCache.TryGetValue(tableName, out var node);
            return node;
        });

        IsInitialized = true;
        LogHelper.Log($"配置管理器初始化完成,共加载 {_jsonCache.Count} 个配置表");    }

    /// <summary>
    /// 加载单个配置表的JSON数据
    /// </summary>
    /// <param name="tableName">配置表名称</param>
    /// <returns>JSON节点</returns>
    private async Task<JSONNode> LoadConfigJson(string tableName)
    {
        if (_jsonCache.TryGetValue(tableName, out var cachedNode))
            return cachedNode;

        // 构建Addressables资源路径
        string assetPath = $"Assets/Bundles/Config/{tableName}.json";
        LogHelper.LogConfig($"开始加载配置表: {tableName}");

        // 异步加载TextAsset
        var handle = Addressables.LoadAssetAsync<TextAsset>(assetPath);
        await handle.Task;

        if (handle.Status == AsyncOperationStatus.Succeeded && handle.Result != null)
        {
            var jsonText = handle.Result.text;
            var jsonNode = JSON.Parse(jsonText);

            if (jsonNode != null)
            {
                _jsonCache[tableName] = jsonNode;
                LogHelper.LogConfig($"配置表加载成功: {tableName}");
            }
            else
            {
                LogHelper.LogError($"配置表JSON解析失败: {tableName}");
            }

            // 释放Addressables资源
            Addressables.Release(handle);
            return jsonNode;
        }

        LogHelper.LogError($"配置表加载失败: {assetPath}, Status: {handle.Status}");
        if (handle.IsValid())
        {
            Addressables.Release(handle);
        }        return null;
    }

    /// <summary>
    /// 获取TablesComponent - 提供直接访问
    /// </summary>
    /// <returns>TablesComponent实例</returns>
    public TablesComponent GetTables()
    {
        return IsInitialized ? _tables : null;
    }

    /// <summary>
    /// 重新加载配置(简化版,主要用于编辑器测试)
    /// </summary>
    public async Task ReloadConfig()
    {
        IsInitialized = false;
        _jsonCache.Clear();
        _initializationTask = Initialize();
        await _initializationTask;
    }
}

这是Editor工具

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEditor;
using Hotfix.Config;

namespace ConfigManagerSystem
{
#if UNITY_EDITOR


    /// <summary>
    /// 配置注册器代码生成器
    /// 扫描Luban生成的TablesComponent,自动生成强类型的配置访问器
    /// </summary>
    public static class ConfigRegistryGenerator
    {
        private class ConfigMethodInfo
        {
            public string TableName { get; set; }
            public string TableType { get; set; }
            public string DataType { get; set; }
            public string DataTypeFullName { get; set; }
            public string KeyType { get; set; } = "string"; // 默认为string
        }
        private const string GENERATED_FILE_PATH = "Assets/Scripts/ConfigSystem/Generated/ConfigRegistry.cs";
        private const string NAMESPACE = "ConfigManagerSystem.Generated";

        [MenuItem("Tools/Config/生成配置注册器")]
        public static void GenerateConfigRegistry()
        {
            try
            {
                Debug.Log("开始生成配置注册器...");

                var configMethods = ExtractConfigMethods();
                Debug.Log($"提取到 {configMethods.Count} 个配置方法:");

                foreach (var method in configMethods)
                {
                    Debug.Log($"  - 表: {method.TableName}, 类型: {method.DataType}, 键类型: {method.KeyType}");
                }

                var generatedCode = GenerateRegistryCode(configMethods);

                // 确保目录存在
                var directory = Path.GetDirectoryName(GENERATED_FILE_PATH);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                File.WriteAllText(GENERATED_FILE_PATH, generatedCode);
                AssetDatabase.Refresh();

                Debug.Log($"配置注册器生成成功: {GENERATED_FILE_PATH}");
                Debug.Log($"共生成 {configMethods.Count} 个配置访问器");
                Debug.Log($"生成的代码长度: {generatedCode.Length} 字符");
            }
            catch (Exception e)
            {
                Debug.LogError($"生成配置注册器失败: {e.Message}");
                Debug.LogError($"堆栈跟踪: {e.StackTrace}");
            }
        }
        private static List<ConfigMethodInfo> ExtractConfigMethods()
        {
            var methods = new List<ConfigMethodInfo>();
            var tablesType = typeof(TablesComponent);

            Debug.Log($"正在扫描 {tablesType.FullName} 类型的属性...");
            foreach (var property in tablesType.GetProperties())
            {
                Debug.Log($"扫描属性: {property.Name}, 类型: {property.PropertyType.Name}");

                // 检查是否是配置表属性
                if (property.PropertyType.Name.StartsWith("TB"))
                {
                    Debug.Log($"发现配置表属性: {property.Name} (类型: {property.PropertyType.Name})");

                    // 查找所有GetOrDefault方法(支持string和int键)
                    var getMethods = property.PropertyType.GetMethods()
                        .Where(m => m.Name == "GetOrDefault" && m.GetParameters().Length == 1);

                    foreach (var getMethod in getMethods)
                    {
                        var paramType = getMethod.GetParameters()[0].ParameterType;
                        string keyTypeName;

                        // 确定键的类型
                        if (paramType == typeof(string))
                            keyTypeName = "string";
                        else if (paramType == typeof(int))
                            keyTypeName = "int";
                        else
                        {
                            Debug.Log($"  跳过不支持的键类型: {paramType.Name}");
                            continue; // 跳过不支持的键类型
                        }

                        Debug.Log($"  找到GetOrDefault方法: 键类型={keyTypeName}, 返回类型={getMethod.ReturnType.Name}");

                        methods.Add(new ConfigMethodInfo
                        {
                            TableName = property.Name,
                            TableType = property.PropertyType.Name,
                            DataType = getMethod.ReturnType.Name,
                            DataTypeFullName = getMethod.ReturnType.FullName,
                            KeyType = keyTypeName
                        });
                    }
                }
            }

            Debug.Log($"总共提取到 {methods.Count} 个配置方法");
            return methods;
        }
        private static string GenerateRegistryCode(List<ConfigMethodInfo> methods)
        {
            // 按键类型分组,避免方法重复
            var groupedMethods = methods.GroupBy(m => new { m.DataType, m.KeyType }).ToList();

            var getMethods = string.Join("\n\n        ", groupedMethods.Select(g =>
            {
                var method = g.First();
                var keyTypeSuffix = method.KeyType == "int" ? "ById" : "";
                return $@"/// <summary>
        /// 获取{method.DataType}配置
        /// </summary>
        public static {method.DataType} Get{method.DataType}{keyTypeSuffix}({method.KeyType} id)
        {{
            var tables = ConfigManager.Instance?.GetTables();
            return tables?.{method.TableName}?.GetOrDefault(id);
        }}";
            }));

            var getAllMethods = string.Join("\n\n        ", methods.GroupBy(m => m.DataType).Select(g =>
            {
                var method = g.First();
                return $@"/// <summary>
        /// 获取所有{method.DataType}配置
        /// </summary>
        public static List<{method.DataType}> GetAll{method.DataType}()
        {{
            var tables = ConfigManager.Instance?.GetTables();
            return tables?.{method.TableName}?.DataList ?? new List<{method.DataType}>();
        }}";
            })); var hasMethods = string.Join("\n\n        ", groupedMethods.Select(g =>
            {
                var method = g.First();
                var keyTypeSuffix = method.KeyType == "int" ? "ById" : "";
                return $@"/// <summary>
        /// 检查{method.DataType}配置是否存在
        /// </summary>
        public static bool Has{method.DataType}{keyTypeSuffix}({method.KeyType} id)
        {{
            return Get{method.DataType}{keyTypeSuffix}(id) != null;
        }}";
            })); var fastAccessMethods = string.Join("\n\n        ", methods.GroupBy(m => m.DataType).Select(g =>
            {
                var method = g.First();
                return $@"/// <summary>
        /// 获取{method.DataType}配置表(零分配访问)
        /// </summary>
        public static {method.TableType} Get{method.DataType}Table()
        {{
            return ConfigManager.Instance?.GetTables()?.{method.TableName};
        }}";
            }));            // 添加缓存相关的方法
            var cachedMethods = string.Join("\n\n        ", groupedMethods.Select(g =>
            {
                var method = g.First();
                var keyTypeSuffix = method.KeyType == "int" ? "ById" : "";
                var cacheKey = method.DataType.ToLower() + (method.KeyType == "int" ? "ById" : "");

                return $@"private static readonly Dictionary<{method.KeyType}, {method.DataType}> _{cacheKey}Cache = new Dictionary<{method.KeyType}, {method.DataType}>();
        
        /// <summary>
        /// 获取{method.DataType}配置(带缓存)
        /// </summary>
        public static {method.DataType} Get{method.DataType}Cached{keyTypeSuffix}({method.KeyType} id)
        {{
            if (_{cacheKey}Cache.TryGetValue(id, out var cached))
                return cached;
                
            var config = Get{method.DataType}{keyTypeSuffix}(id);
            if (config != null)
                _{cacheKey}Cache[id] = config;
                
            return config;
        }}
        
        /// <summary>
        /// 清除{method.DataType}缓存
        /// </summary>
        public static void Clear{method.DataType}Cache{keyTypeSuffix}()
        {{
            _{cacheKey}Cache.Clear();
        }}";
            }));

            return $@"//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by ConfigRegistryGenerator.
//     Changes to this file will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System.Collections.Generic;
using Hotfix.Config;

namespace {NAMESPACE}
{{
    /// <summary>
    /// 自动生成的配置访问器
    /// 提供强类型、高性能的配置访问方法
    /// 避免运行时反射,提升性能
    /// </summary>
    public static class ConfigRegistry
    {{
        #region 单个配置获取方法
        {getMethods}
        #endregion

        #region 所有配置获取方法
        {getAllMethods}
        #endregion

        #region 配置存在性检查方法
        {hasMethods}
        #endregion

        #region 快速表访问方法(零分配)
        {fastAccessMethods}
        #endregion

        #region 缓存访问方法
        {cachedMethods}
        #endregion

        #region 工具方法
        /// <summary>
        /// 检查配置管理器是否已初始化
        /// </summary>
        public static bool IsConfigManagerReady => ConfigManager.Instance?.IsInitialized == true;

        /// <summary>
        /// 等待配置管理器初始化完成
        /// </summary>
        public static async System.Threading.Tasks.Task WaitForInitialization()
        {{
            if (ConfigManager.Instance != null)
            {{
                await ConfigManager.Instance.WaitForInitialization();
            }}
        }}        
        /// <summary>
        /// 清除所有缓存
        /// </summary>
        public static void ClearAllCaches()
        {{
            {string.Join("\n            ", groupedMethods.Select(g =>
            {
                var method = g.First();
                var keyTypeSuffix = method.KeyType == "int" ? "ById" : "";
                return $"Clear{method.DataType}Cache{keyTypeSuffix}();";
            }))}
        }}        
        /// <summary>
        /// 获取配置统计信息
        /// </summary>
        public static string GetConfigStats()
        {{
            var tables = ConfigManager.Instance?.GetTables();
            if (tables == null) return ""配置未初始化"";
            
            return $@""配置统计:
{string.Join("\n", methods.GroupBy(m => m.DataType).Select(g =>
{
    var method = g.First();
    return $"- {method.DataType}: {{tables.{method.TableName}?.DataList?.Count ?? 0}} 项";
}))}"";
        }}
        #endregion
    }}
}}";
        }

    }
#endif
}

通过这两个工具(当然还是有问题的比如还是要在这个配置表名称里面加自己json表名称)

这就是数据驱动以及载入了。。。。。

接下来是组件模式,人物的组件模式我准备分为两种,一种人物本身的组件模式,这个不用说都很简单,只需要给characterdata一个共享数据的地方

using System.Collections.Generic;
using UnityEngine;
using ConfigManagerSystem.Generated;
using CDTU.LogHelper;
using System;

namespace Characters.Data
{
    /// <summary>
    /// 修正值类型枚举
    /// </summary>
    public enum ModifierType
    {
        MaxHealth,
        Attack,
        MoveSpeed,
        AttackSpeed,
        Power,
        Unknown
    }

    /// <summary>
    /// 角色配置数据类 - 统一管理角色的所有配置数值
    /// </summary>
    [Serializable]
    public class CharacterConfigData : ICharacterConfigProvider
    {
        // 基础信息
        public readonly string CharacterId;

        // 缓存的最终数值(避免重复计算)
        private float _cachedMaxHealth;
        private float _cachedAttack;
        private float _cachedMoveSpeed;
        private float _cachedPower;
        private float _cachedAttackSpeed;
        private bool _cachedDestroyOnDeath;
        private bool _statsDirty = true;

        // 公开访问属性
        public float MaxHealth
        {
            get
            {
                RefreshStatsIfDirty();
                return _cachedMaxHealth;
            }
        }

        public float Attack
        {
            get
            {
                RefreshStatsIfDirty();
                return _cachedAttack;
            }
        }

        public float MoveSpeed
        {
            get
            {
                RefreshStatsIfDirty();
                return _cachedMoveSpeed;
            }
        }

        public float Power
        {
            get
            {
                RefreshStatsIfDirty();
                return _cachedPower;
            }
        }

        public float AttackSpeed
        {
            get
            {
                RefreshStatsIfDirty();
                return _cachedAttackSpeed;
            }
        }

        public bool DestroyOnDeath
        {
            get
            {
                RefreshStatsIfDirty();
                return _cachedDestroyOnDeath;
            }
        }

        // 修正值系统(装备、BUFF等)
        private readonly Dictionary<string, float> _modifiers = new();

        // 事件系统
        public Action<CharacterConfigData> OnStatsChanged;

        /// <summary>
        /// 构造函数
        /// </summary>
        public CharacterConfigData(string characterId)
        {
            CharacterId = characterId;
            _statsDirty = true;
        }

        // /// <summary>
        // /// 添加修正值(装备、BUFF等)
        // /// </summary>
        // public void AddModifier(string key, float value)
        // {
        //     _modifiers[key] = value;
        //     _statsDirty = true;
        // }

        /// <summary>
        /// 添加类型化修正值(推荐使用)
        /// </summary>
        public void AddModifier(ModifierType type, string key, float value)
        {
            // 使用类型前缀确保准确分类
            var typedKey = $"{type}_{key}";
            _modifiers[typedKey] = value;
            _statsDirty = true;
        }

        /// <summary>
        /// 移除修正值
        /// </summary>
        public void RemoveModifier(string key)
        {
            if (_modifiers.Remove(key))
            {
                _statsDirty = true;
            }
        }

        /// <summary>
        /// 移除类型化修正值
        /// </summary>
        public void RemoveModifier(ModifierType type, string key)
        {
            var typedKey = $"{type}_{key}";
            RemoveModifier(typedKey);
        }

        /// <summary>
        /// 清除所有修正值
        /// </summary>
        public void ClearModifiers()
        {
            _modifiers.Clear();
            _statsDirty = true;
        }

        /// <summary>
        /// 强制刷新数值
        /// </summary>
        public void ForceRefresh()
        {
            _statsDirty = true;
            RefreshStatsIfDirty();
        }

        /// <summary>
        /// 按需刷新数值
        /// </summary>
        private void RefreshStatsIfDirty()
        {
            if (_statsDirty)
            {
                RefreshAllStats();
            }
        }

        /// <summary>
        /// 重新计算所有数值
        /// </summary>
        private void RefreshAllStats()
        {
            // 获取基础配置
            var baseConfig = ConfigRegistry.GetCharacterInfo(CharacterId);
            if (baseConfig == null)
            {
                LogHelper.LogError($"找不到角色配置: {CharacterId}");
                return;
            }

            // 暂时使用基础配置数值,不考虑等级影响
            _cachedMaxHealth = baseConfig.MaxHealth;
            _cachedAttack = baseConfig.Atk;
            _cachedMoveSpeed = baseConfig.MoveSpeed;
            _cachedPower = baseConfig.Power;
            // 暂时使用固定攻击速度
            _cachedAttackSpeed = 1.0f;
            _cachedDestroyOnDeath = baseConfig.DestroyOnDeath;

            // 应用修正值
            ApplyModifiers();

            _statsDirty = false;

            // 触发变化事件
            OnStatsChanged?.Invoke(this);
        }

        /// <summary>
        /// 应用所有修正值
        /// </summary>
        private void ApplyModifiers()
        {
            foreach (var modifier in _modifiers)
            {
                var key = modifier.Key;
                var value = modifier.Value;
                var modifierType = ClassifyModifier(key);

                switch (modifierType)
                {
                    case ModifierType.MaxHealth:
                        _cachedMaxHealth += value;
                        break;
                    case ModifierType.Attack:
                        _cachedAttack += value;
                        break;
                    case ModifierType.MoveSpeed:
                        _cachedMoveSpeed += value;
                        break;
                    case ModifierType.AttackSpeed:
                        _cachedAttackSpeed += value;
                        break;
                    case ModifierType.Power:
                        _cachedPower += value;
                        break;
                    case ModifierType.Unknown:
                        LogHelper.LogWarning($"未识别的修正值类型: {key},值: {value}");
                        break;
                }
            }
            // 确保数值不为负
            _cachedMaxHealth = Mathf.Max(1, _cachedMaxHealth);
            _cachedAttack = Mathf.Max(0, _cachedAttack);
            _cachedMoveSpeed = Mathf.Max(0.1f, _cachedMoveSpeed);//todo-也许需要调整
            _cachedPower = Mathf.Max(0, _cachedPower);
            _cachedAttackSpeed = Mathf.Max(0.1f, _cachedAttackSpeed);
        }

        /// <summary>
        /// 分类修正值类型
        /// </summary>
        private ModifierType ClassifyModifier(string key)
        {
            // 检查类型化前缀
            if (key.StartsWith("MaxHealth_") || key.StartsWith("Health_"))
                return ModifierType.MaxHealth;
            if (key.StartsWith("Attack_"))
                return ModifierType.Attack;
            if (key.StartsWith("MoveSpeed_"))
                return ModifierType.MoveSpeed;
            if (key.StartsWith("AttackSpeed_"))
                return ModifierType.AttackSpeed;
            if (key.StartsWith("Power_"))
                return ModifierType.Power;

            // 向后兼容的字符串匹配(按优先级顺序)
            var lowerKey = key.ToLowerInvariant();

            if (lowerKey.Contains("maxhealth") || lowerKey.Contains("health"))
                return ModifierType.MaxHealth;
            if (lowerKey.Contains("attackspeed"))
                return ModifierType.AttackSpeed;
            if (lowerKey.Contains("movespeed"))
                return ModifierType.MoveSpeed;
            if (lowerKey.Contains("attack"))
                return ModifierType.Attack;
            if (lowerKey.Contains("power"))
                return ModifierType.Power;

            return ModifierType.Unknown;
        }

        public float GetStats(ModifierType type)
        {
            RefreshStatsIfDirty();
            return type switch
            {
                ModifierType.MaxHealth => _cachedMaxHealth,
                ModifierType.Attack => _cachedAttack,
                ModifierType.MoveSpeed => _cachedMoveSpeed,
                // ModifierType.AttackSpeed => _cachedAttackSpeed,
                ModifierType.Power => _cachedPower,
                _ => 0f // 未知类型返回0
            };
        }

        /// <summary>
        /// 获取配置摘要信息
        /// </summary>
        public string GetConfigSummary()
        {
            RefreshStatsIfDirty();
            return $"角色: {CharacterId}\n" +
                   $"生命值: {_cachedMaxHealth:F1}, 攻击力: {_cachedAttack:F1}\n" +
                   $"移动速度: {_cachedMoveSpeed:F1}\n" +
                   $"能量: {_cachedPower:F1}, 死亡销毁: {_cachedDestroyOnDeath}";
        }

        /// <summary>
        /// 获取修正值详情(调试用)
        /// </summary>
        public string GetModifiersDetail()
        {
            if (_modifiers.Count == 0)
                return "无修正值";

            var details = new System.Text.StringBuilder();
            details.AppendLine("当前修正值 (按类型分组):");

            // 按类型分组显示
            var typeGroups = new Dictionary<ModifierType, List<KeyValuePair<string, float>>>();

            foreach (var modifier in _modifiers)
            {
                var modifierType = ClassifyModifier(modifier.Key);
                if (!typeGroups.ContainsKey(modifierType))
                    typeGroups[modifierType] = new List<KeyValuePair<string, float>>();

                typeGroups[modifierType].Add(modifier);
            }

            foreach (var group in typeGroups)
            {
                details.AppendLine($"  {group.Key}:");
                foreach (var modifier in group.Value)
                {
                    details.AppendLine($"    {modifier.Key}: {modifier.Value:F1}");
                }
            }

            return details.ToString().TrimEnd();
        }

        /// <summary>
        /// 获取基础值详情(调试用)
        /// </summary>
        public string GetBaseValuesDetail()
        {
            var baseConfig = ConfigRegistry.GetCharacterInfo(CharacterId);
            if (baseConfig == null)
                return "基础配置未找到";

            // 暂时注释掉等级系统相关代码
            // float healthMultiplier = 1.0f + (_currentLevel - 1) * 0.1f;
            // float attackBonus = (_currentLevel - 1) * 2f;
            // float speedBonus = (_currentLevel - 1) * 0.1f;

            return $"基础配置:\n" +
                   $"  基础血量: {baseConfig.MaxHealth}\n" +
                   $"  基础攻击: {baseConfig.Atk}\n" +
                   $"  基础速度: {baseConfig.MoveSpeed}\n" +
                   $"  基础能量: {baseConfig.Power}";
            //     $"  基础攻速: 1.0";
        }
    }
}

当然还是未完善,,大家都在这里处理数据修改数据,保证了人物数据的统一,当然玩家控制的人物是只通过这里修改,敌人的数据我会想着通过半ECS通过一个system统一处理组件,优化性能。这里就只讲解一下玩家控制人物处理的逻辑,开始一个协调者Character组件先初始化数据并载入数据,通过init方法和接口IComponent来初始化各个组件,这样一个人物就初始化好了。

using UnityEngine;
using CDTU.LogHelper;
using Characters.Utils;
using Characters.Data;
using System.Threading.Tasks;
using Characters.Managers;

public class Character : MonoBehaviour
{
    [SerializeField] protected string characterId;
    // [SerializeField] protected int characterLevel = 1;

    // 组件管理器
    protected ComponentManager _componentManager;
    
    // 核心组件
    private CharacterHealthComponent _healthComponent;
    private CharacterPowerComponent _powerComponent;

    // 统一配置数据
    private CharacterConfigData _characterConfig;

    // 属性访问
    public string CharacterId => characterId;
    // public int CharacterLevel => characterLevel;
    public CharacterConfigData CharacterConfig => _characterConfig;
    
    // 便捷的数值访问
    public float MaxHealth => _characterConfig?.MaxHealth ?? 0f;
    public float Attack => _characterConfig?.Attack ?? 0f;
    public float MoveSpeed => _characterConfig?.MoveSpeed ?? 0f;
    public float Power => _characterConfig?.Power ?? 0f;

    // 升级事件
    public System.Action<int> OnCharacterLevelUp;
    /// <summary>
    /// 检查角色是否已初始化完成
    /// </summary>
    public bool IsInitialized => _isInitialized;
    // 初始化状态
    private Task _initializationTask;
    private bool _isInitialized = false;

    protected virtual void Awake()
    {
        if (string.IsNullOrEmpty(characterId))
        {
            LogHelper.LogError("角色ID未设置!");
            return;
        }

        // 启动异步初始化
        _initializationTask = InitializeAsync();
    }

    private async Task InitializeAsync()
    {
        // 1. 等待配置管理器初始化
        await ConfigManager.Instance.WaitForInitialization();

        // 2. 获取统一配置数据
        // _characterConfig = CharacterConfigManager.GetConfig(characterId, characterLevel);
        _characterConfig = CharacterConfigManager.GetConfig(characterId);
        if (_characterConfig == null)
        {
            // LogHelper.LogError($"无法创建角色配置,ID: {characterId}, Level: {characterLevel}");
            LogHelper.LogError($"无法创建角色配置,ID: {characterId}");
            return;
        }

        // 3. 订阅配置变化事件
        _characterConfig.OnStatsChanged += OnConfigStatsChanged;

        // 4. 初始化组件管理器
        _componentManager = new ComponentManager(this.gameObject, this);
        if (!_componentManager.Initialize())
        {
            LogHelper.LogError("组件管理器初始化失败!");
            return;
        }        // 5. 获取核心组件并传递配置
        _healthComponent = _componentManager.GetOrAddComponent<CharacterHealthComponent>();
        _powerComponent = _componentManager.GetOrAddComponent<CharacterPowerComponent>();

        // 6. 订阅组件事件
        if (_healthComponent != null)
        {
            _healthComponent.OnHealthChanged += OnCharacterHealthChanged;
            _healthComponent.OnDied += OnCharacterDied;
        }

        if (_powerComponent != null)
        {
            _powerComponent.OnPowerChanged += OnPowerChanged;
        }

        // 7. 标记初始化完成
        _isInitialized = true;

        LogHelper.Log($"角色 {characterId}");
        // LogHelper.Log($"角色 {characterId} (Level {characterLevel}) 初始化完成");
    }

    /// <summary>
    /// 配置数值变化时的回调
    /// </summary>
    private void OnConfigStatsChanged(CharacterConfigData config)
    {
        LogHelper.Log($"角色 {characterId} 配置更新: {config.GetConfigSummary()}");
        
        // 通知组件配置已更新
        NotifyComponentsConfigUpdated();
    }    /// <summary>
    /// 通知所有组件配置已更新
    /// </summary>
    private void NotifyComponentsConfigUpdated()
    {
        // 配置数据系统会自动通知所有组件,这里主要用于其他特殊处理
        LogHelper.Log($"角色 {characterId} 配置已更新,所有组件将自动同步");
    }

    // /// <summary>
    // /// 角色升级
    // /// </summary>
    // public virtual void LevelUp()
    // {
    //     // characterLevel++;
    //     // _characterConfig?.LevelUp();
        
    //     LogHelper.Log($"角色 {characterId} 升级到 {characterLevel} 级");
    //     OnCharacterLevelUp?.Invoke(characterLevel);
    // }

    // /// <summary>
    // /// 设置角色等级
    // /// </summary>
    // public virtual void SetLevel(int newLevel)
    // {
    //     if (characterLevel == newLevel) return;
        
    //     characterLevel = newLevel;
    //     _characterConfig?.SetLevel(newLevel);
        
    //     OnCharacterLevelUp?.Invoke(characterLevel);
    // }


    protected virtual async void Start()
    {
        // 等待初始化完成
        if (_initializationTask != null)
        {
            await _initializationTask;
        }

        // 确保初始化成功后才开始组件
        if (_isInitialized && _componentManager != null)
        {
            _componentManager.StartAll();
        }
    }

    protected virtual void Update()
    {
        // 只有在初始化完成后才更新组件
        if (_isInitialized && _componentManager != null)
        {
            _componentManager.UpdateAll(Time.deltaTime);
        }
    }

    /// <summary>
    /// 等待角色初始化完成
    /// </summary>
    public async Task WaitForInitialization()
    {
        if (_initializationTask != null)
        {
            await _initializationTask;
        }
    }
    #region 事件处理
    protected virtual void OnCharacterHealthChanged(object sender, CharacterHealthComponent.HealthChangedEventArgs e)
    {
        LogHelper.Log($"角色受到 {e.ChangeAmount} 点伤害!当前生命值: {e.CurrentHealth}/{_componentManager.GetComponent<CharacterHealthComponent>().GetMaxHealth()}");
    }

    protected virtual void OnCharacterDied()
    {
        LogHelper.Log($"{CharacterId}已死亡!");
    }

    protected virtual void OnPowerChanged(object sender, CharacterPowerComponent.OnPowerChangedEventArgs e)
    {
        LogHelper.Log($"角色能量值变化: {e.Power}/{_powerComponent.GetMaxPower()}");
    }
    #endregion

    #region 公共方法供调用
    public void ApplyDamage(float damage)
    {
        _componentManager.GetComponent<CharacterHealthComponent>().TakeDamage(damage);
    }

    public void ApplyHealing(float amount)
    {
        _componentManager.GetComponent<CharacterHealthComponent>().Heal(amount);
    }
    #endregion

    protected virtual void OnDestroy()
    {
        // 取消配置事件订阅
        if (_characterConfig != null)
        {
            _characterConfig.OnStatsChanged -= OnConfigStatsChanged;
        }

        // 取消事件订阅
        if (_healthComponent != null)
        {
            _healthComponent.OnHealthChanged -= OnCharacterHealthChanged;
            _healthComponent.OnDied -= OnCharacterDied;
        }

        if (_powerComponent != null)
        {
            _powerComponent.OnPowerChanged -= OnPowerChanged;
        }

        // 清理所有组件
        _componentManager?.CleanupAll();
    }
}

using Characters.Data;

public interface IComponent
{
    /// <summary>
    /// 组件的拥有者
    /// </summary>
    /// <param name="config"></param>
    void OnInit(CharacterConfigData config);
    /// <summary>
    /// 所有组件初始化后调用,用于依赖其他组件的设置
    /// </summary>
    void OnStart();

    /// <summary>
    /// 组件被禁用或移除时调用
    /// </summary>
    void OnDisable();

    /// <summary>
    /// 设置组件的拥有者
    /// 该方法通常在组件被添加到角色时调用
    /// </summary>
    /// <param name="owner">组件的拥有者</param>
    void SetOwner(Character owner);
}

// 可更新组件
public interface IUpdatableComponent : IComponent
{
    void OnTick(float deltaTime);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值