Files
Cielonos/docs/架构改进建议.md
2026-04-18 13:57:19 -04:00

16 KiB
Raw Blame History

Cielonos 项目架构改进建议

一、整体架构评估

当前架构优势

  1. 模块化设计: Submodule/Subcontroller架构将逻辑和表现分离提供了良好的可扩展性
  2. 组件化思想: 大量使用字典存储子模块,便于动态增删功能
  3. 事件驱动: 使用UniRx实现响应式事件系统解耦了系统间的依赖
  4. 系统完整性: 战斗、Buff、状态、动画等核心系统已经具备完整的基础架构

当前架构不足

  1. 职责边界模糊: 部分类承担了过多职责
  2. 代码组织混乱: 部分脚本放置位置不合理
  3. 抽象程度不足: 部分核心逻辑缺少接口抽象
  4. 文档注释缺失: 代码缺少必要的注释和说明
  5. 配置化程度低: 硬编码问题较多

二、具体改进建议

1. 核心架构层

1.1 建立核心接口层

问题: 当前系统之间直接依赖具体实现,缺乏抽象层

建议:

Core/Interfaces/
├── ICharacter.cs              # 角色接口
├── IAttackable.cs             # 可攻击对象接口
├── IBuffable.cs               # 可附魔Buff对象接口
├── IItem.cs                   # 物品接口
├── IWeapon.cs                 # 武器接口
├── IDamageable.cs             # 可受伤害对象接口
└── ITeamMember.cs             # 阵营成员接口

示例代码:

public interface ICharacter
{
    Fraction Team { get; }
    bool IsDead { get; }
    float Health { get; }
    float MaxHealth { get; }
    
    void TakeDamage(DamageInfo damageInfo);
    void ApplyBuff(IBuff buff);
    void Heal(float amount);
}

public interface IDamageSource
{
    DamageInfo CreateDamage();
    AttackType DamageType { get; }
    float DamageValue { get; }
}

1.2 引入服务定位器模式

问题: Manager类直接持有引用系统间耦合度高

建议:

public static class GameServices
{
    private static readonly Dictionary<Type, object> services = new Dictionary<Type, object>();
    
    public static void Register<T>(T service) where T : class
    {
        services[typeof(T)] = service;
    }
    
    public static T Get<T>() where T : class
    {
        if (services.TryGetValue(typeof(T), out var service))
        {
            return service as T;
        }
        
        Debug.LogError($"Service {typeof(T)} not found!");
        return null;
    }
    
    public static void Clear()
    {
        services.Clear();
    }
}

// 使用示例
public class BattleManager : MonoBehaviour
{
    public void Initialize()
    {
        GameServices.Register<IBattleService>(this);
        GameServices.Register<ICharacterService>(new CharacterService());
        GameServices.Register<IBuffService>(new BuffService());
    }
}

// 在其他类中使用
var battleService = GameServices.Get<IBattleService>();

1.3 建立消息总线系统

问题: 当前事件系统分散在各个类中,难以追踪和调试

建议:

public enum GameEvent
{
    // 角色事件
    CharacterDied,
    CharacterSpawned,
    CharacterRevived,
    
    // 战斗事件
    DamageDealt,
    DamageTaken,
    AttackBlocked,
    AttackDodged,
    CriticalHit,
    
    // 物品事件
    ItemAcquired,
    ItemUsed,
    ItemDiscarded,
    WeaponSwitched,
    
    // Buff事件
    BuffApplied,
    BuffRemoved,
    BuffExpired,
    
    // 游戏状态事件
    WaveStarted,
    WaveCleared,
    BossAppeared,
    BossDefeated,
    
    // 系统事件
    GamePaused,
    GameResumed,
    CheckpointReached
}

public class GameEventBus
{
    private static readonly Dictionary<GameEvent, Action<GameEventArgs>> 
        eventHandlers = new Dictionary<GameEvent, Action<GameEventArgs>>();
    
    public static void Subscribe(GameEvent eventType, Action<GameEventArgs> handler)
    {
        if (!eventHandlers.ContainsKey(eventType))
        {
            eventHandlers[eventType] = handler;
        }
        else
        {
            eventHandlers[eventType] += handler;
        }
    }
    
    public static void Unsubscribe(GameEvent eventType, Action<GameEventArgs> handler)
    {
        if (eventHandlers.ContainsKey(eventType))
        {
            eventHandlers[eventType] -= handler;
        }
    }
    
    public static void Publish(GameEvent eventType, GameEventArgs args = null)
    {
        if (eventHandlers.TryGetValue(eventType, out var handler))
        {
            handler?.Invoke(args);
        }
    }
}

public class GameEventArgs
{
    public object Sender { get; set; }
    public Dictionary<string, object> Data { get; set; } = new Dictionary<string, object>();
}

2. 角色系统改进

2.1 拆分CharacterBase

问题: CharacterBase类过于庞大承担了太多职责

建议: 将其拆分为多个专门类

// 核心角色数据
public class CharacterData : ScriptableObject
{
    public string characterId;
    public string characterName;
    public Fraction defaultFaction;
    public AttributeData baseAttributes;
    public VFXData vfxData;
    public AudioContainer audioData;
    public List<SerializableType> availableBuffs;
}

// 角色配置器
public class CharacterBuilder
{
    private CharacterData data;
    private List<ICharacterComponent> components = new List<ICharacterComponent>();
    
    public CharacterBuilder SetData(CharacterData data) { ... }
    public CharacterBuilder AddComponent<T>() where T : ICharacterComponent { ... }
    public ICharacter Build() { ... }
}

// 组件接口
public interface ICharacterComponent
{
    void Initialize(ICharacter character);
    void Update(float deltaTime);
    void Cleanup();
}

2.2 改进属性系统

问题: 当前属性使用字符串字典缺少类型安全和IDE支持

建议:

// 属性ID枚举
public enum AttributeId
{
    // 基础属性
    MaxHealth,
    CurrentHealth,
    MaxEnergy,
    CurrentEnergy,
    MovementSpeed,
    AttackSpeed,
    
    // 战斗属性
    PhysicalAttack,
    PhysicalDefense,
    EnergyAttack,
    EnergyDefense,
    CriticalRate,
    CriticalDamage,
    
    // 抗性
    FireResistance,
    IceResistance,
    LightningResistance,
    
    // 特殊属性
    LifeSteal,
    CooldownReduction,
}

// 属性修饰器
public interface IAttributeModifier
{
    int Priority { get; }
    AttributeId TargetAttribute { get; }
    float Modify(float originalValue);
}

// 属性计算器
public class AttributeCalculator
{
    private List<IAttributeModifier> modifiers = new List<IAttributeModifier>();
    
    public float Calculate(AttributeId attributeId, float baseValue)
    {
        var applicableModifiers = modifiers
            .Where(m => m.TargetAttribute == attributeId)
            .OrderBy(m => m.Priority);
        
        float result = baseValue;
        foreach (var modifier in applicableModifiers)
        {
            result = modifier.Modify(result);
        }
        return result;
    }
}

3. 战斗系统改进

3.1 建立战斗配置系统

问题: 战斗参数硬编码,难以平衡调整

建议:

[CreateAssetMenu(fileName = "BattleConfig", menuName = "Cielonos/Config/BattleConfig")]
public class BattleConfig : ScriptableObject
{
    [Header("Damage Calculation")]
    public float baseCriticalMultiplier = 1.5f;
    public float maxCriticalMultiplier = 3.0f;
    public float levelDamageBonus = 0.1f;
    
    [Header("Breakthrough Thresholds")]
    public float weakBreakthroughThreshold = 0.5f;
    public float mediumBreakthroughThreshold = 0.75f;
    public float heavyBreakthroughThreshold = 1.0f;
    
    [Header("Hit Detection")]
    public float hitstopDuration = 0.05f;
    public float screenShakeIntensity = 0.1f;
    
    [Header("Damage Numbers")]
    public float damageNumberScale = 1.0f;
    public float criticalScale = 1.5f;
    public float damageNumberLifetime = 1.0f;
}

public class BattleConfigProvider
{
    public static BattleConfig Config => 
        Resources.Load<BattleConfig>("Config/BattleConfig");
}

3.2 改进攻击判定系统

问题: AttackArea承担了过多职责

建议:

// 攻击配置
[CreateAssetMenu(fileName = "AttackConfig", menuName = "Cielonos/Attack/AttackConfig")]
public class AttackConfig : ScriptableObject
{
    public LayerMask targetLayers;
    public float hitboxActiveDuration;
    public Vector3 hitboxSize;
    public Vector3 hitboxOffset;
    public bool useRaycast;
    public float raycastDistance;
}

// 命中结果
public struct HitResult
{
    public ICharacter Target;
    public Vector3 HitPoint;
    public Vector3 HitNormal;
    public bool IsCritical;
    public float FinalDamage;
    public DamageType DamageType;
}

// 命中事件
public class HitEventArgs : GameEventArgs
{
    public HitResult HitResult { get; set; }
    public ICharacter Attacker { get; set; }
}

4. 物品系统改进

4.1 建立物品数据库

问题: 物品管理分散在各处

建议:

[CreateAssetMenu(fileName = "ItemDatabase", menuName = "Cielonos/Items/Database")]
public class ItemDatabase : ScriptableObject
{
    [SerializeField] private List<WeaponData> weapons = new List<WeaponData>();
    [SerializeField] private List<ArmorData> armors = new List<ArmorData>();
    [SerializeField] private List<ConsumableData> consumables = new List<ConsumableData>>();
    
    public WeaponData GetWeapon(string id) => weapons.FirstOrDefault(w => w.Id == id);
    public T GetItem<T>(string id) where T : ItemData
    {
        var field = typeof(ItemDatabase).GetField(typeof(T).Name.ToLower() + "s", 
            BindingFlags.NonPublic | BindingFlags.Instance);
        var list = field?.GetValue(this) as IEnumerable<ItemData>;
        return list?.FirstOrDefault(i => i.Id == id) as T;
    }
}

// 物品生成器
public static class ItemFactory
{
    public static IItem Create(ItemData data, int level = 1)
    {
        return data switch
        {
            WeaponData weaponData => CreateWeapon(weaponData, level),
            ArmorData armorData => CreateArmor(armorData, level),
            ConsumableData consumableData => CreateConsumable(consumableData),
            _ => throw new ArgumentException($"Unknown item type: {data.GetType()}")
        };
    }
    
    private static Weapon CreateWeapon(WeaponData data, int level)
    {
        var weapon = new Weapon();
        weapon.Initialize(data, level);
        return weapon;
    }
}

5. AI系统改进

5.1 建立AI配置系统

问题: AI行为硬编码缺乏配置化

建议:

[CreateAssetMenu(fileName = "AIConfig", menuName = "Cielonos/AI/AIConfig")]
public class AIConfig : ScriptableObject
{
    [Header("Detection")]
    public float detectionRange = 10f;
    public float attackRange = 2f;
    public float loseInterestRange = 20f;
    
    [Header("Movement")]
    public float preferredDistance = 5f;
    public float strafeSpeed = 2f;
    
    [Header("Decision Making")]
    public float decisionInterval = 0.5f;
    public float healthThresholdForRetreat = 0.3f;
    public float energyThresholdForSpecial = 0.7f;
    
    [Header("Behavior Weights")]
    public float attackWeight = 1.0f;
    public float defendWeight = 0.5f;
    public float retreatWeight = 0.3f;
    public float supportWeight = 0.4f;
}

[Serializable]
public class BehaviorState
{
    public string stateName;
    public BehaviorTree tree;
    public List<Transition> transitions = new List<Transition>();
    public float enterDelay;
}

[Serializable]
public class Transition
{
    public string targetState;
    public List<Condition> conditions = new List<Condition>();
}

[Serializable]
public abstract class Condition
{
    public abstract bool Evaluate(IAIController controller);
}

6. 数据持久化改进

6.1 建立游戏存档系统

问题: 缺乏统一的存档管理

建议:

[System.Serializable]
public class GameSaveData
{
    public string saveId;
    public DateTime saveTime;
    public int playerLevel;
    public Vector3 playerPosition;
    public List<ItemSaveData> inventory;
    public List<string> unlockedAbilities;
    public int currentZoneIndex;
    public int currentScore;
    public List<AchievementSaveData> achievements;
}

public interface ISaveSystem
{
    void Save(GameSaveData data);
    GameSaveData Load(string saveId);
    List<string> GetAllSaves();
    void DeleteSave(string saveId);
}

public class EasySaveAdapter : ISaveSystem
{
    public void Save(GameSaveData data)
    {
        ES3.Save("save_" + data.saveId, data);
    }
    
    public GameSaveData Load(string saveId)
    {
        return ES3.Load<GameSaveData>("save_" + saveId);
    }
    
    public List<string> GetAllSaves()
    {
        // 实现保存文件列表获取
    }
    
    public void DeleteSave(string saveId)
    {
        ES3.DeleteKey("save_" + saveId);
    }
}

7. UI系统改进

7.1 建立UI框架

问题: UI组件耦合度高难以复用

建议:

public abstract class UIScreen : MonoBehaviour
{
    protected bool isVisible;
    
    public virtual void Show() 
    { 
        gameObject.SetActive(true);
        OnShow();
        isVisible = true;
    }
    
    public virtual void Hide() 
    { 
        OnHide();
        gameObject.SetActive(false);
        isVisible = false;
    }
    
    protected abstract void OnShow();
    protected abstract void OnHide();
}

public class UIManager
{
    private Stack<UIScreen> screenStack = new Stack<UIScreen>();
    
    public void ShowScreen<T>() where T : UIScreen
    {
        var screen = GetScreen<T>();
        if (screen != null)
        {
            screen.Show();
            screenStack.Push(screen);
        }
    }
    
    public void CloseCurrentScreen()
    {
        if (screenStack.Count > 0)
        {
            var screen = screenStack.Pop();
            screen.Hide();
        }
    }
}

8. 代码规范与工具

8.1 增加代码注释

建议: 在关键类和方法添加XML文档注释

/// <summary>
/// 伤害信息结构体,包含所有与伤害计算相关的参数
/// </summary>
public struct DamageInfo
{
    /// <summary>
    /// 伤害来源
    /// </summary>
    public IDamageSource Source;
    
    /// <summary>
    /// 伤害值基数
    /// </summary>
    public float BaseDamage;
    
    /// <summary>
    /// 伤害类型
    /// </summary>
    public DamageType Type;
}

8.2 建立自定义编辑器工具

建议: 为复杂系统创建编辑器窗口

#if UNITY_EDITOR
public class CharacterEditorWindow : EditorWindow
{
    [MenuItem("Cielonos/Character Editor")]
    public static void OpenWindow()
    {
        GetWindow<CharacterEditorWindow>("Character Editor");
    }
    
    private void OnGUI()
    {
        // 创建角色编辑器UI
    }
}

public class BuffEditorWindow : EditorWindow
{
    [MenuItem("Cielonos/Buff Editor")]
    public static void OpenWindow()
    {
        GetWindow<BuffEditorWindow>("Buff Editor");
    }
}
#endif

三、改进优先级

P0 - 必须改进(阻塞性问题)

  1. 建立核心接口层
  2. 改进属性系统类型安全
  3. 建立消息总线

P1 - 重要改进(核心功能)

  1. 拆分CharacterBase
  2. 建立战斗配置系统
  3. 建立物品数据库
  4. 建立AI配置系统

P2 - 优化改进(提升开发效率)

  1. 建立存档系统
  2. 建立UI框架
  3. 增加代码注释
  4. 创建编辑器工具

P3 - 长期改进(架构优化)

  1. 服务定位器模式
  2. 组件化重构
  3. 配置化完善

四、总结

当前项目在架构上已经奠定了良好的基础核心系统基本完备。要构建完善的Roguelike ARPG框架重点需要

  1. 抽象接口层: 建立清晰的接口边界,提高系统可测试性和可替换性
  2. 配置驱动: 将硬编码转为配置化,提高设计迭代效率
  3. 数据管理: 建立统一的数据管理系统包括物品、敌人、AI等
  4. 代码规范: 增加注释和文档,提高代码可维护性
  5. 工具支持: 开发自定义编辑器工具,提高开发效率

文档生成日期: 2026-04-17
生成者: Game Designer Agent