Skip to content

数值组件

提示

本文档介绍数值组件的内容大部分来自于ET Book的数值组件部分。

简介

数值组件是 ET 框架中一个重要的功能组件,它提供了一套完整的数值管理方案。主要功能包括:

  • 数值的基础运算操作
  • 数值变化事件监听与分发

设计思路

注意

在复杂的游戏系统(如MMORPG、MOBA)中,技能系统需要一套灵活的数值结构支持。一个角色可能包含多种属性:移动速度、力量、怒气、能量、集中值、魔法值、血量等。这些属性之间相互影响,且会受到buff的影响(绝对值增加、百分比增加等)。

传统方案及其局限

csharp
class Numeric
{
    public int Hp;
    public int MaxHp;
    public int Speed;
    public int Energy;
    public int MaxEnergy;
    public int Mp;
    public int MaxMp;
}

这种设计存在以下问题:

  1. 不同职业可能使用不同属性系统(法师使用魔法值,盗贼使用能量值)
  2. 继承方案会导致类层次复杂
  3. 属性计算需要考虑多个影响因素

例如速度计算需要考虑:

csharp
class Numeric
{
    public int Speed;        // 速度最终值
    public int SpeedInit;    // 速度初始值
    public int SpeedAdd;     // 速度增加值
    public int SpeedPct;     // 速度增加百分比值
}

计算公式:

Speed = (SpeedInit + SpeedAdd) * (100 + SpeedPct) / 100

这种方案的主要问题:

  1. 类结构庞大
  2. 计算公式重复
  3. 属性配置不灵活

ET框架解决方案

ET框架采用Key-Value形式保存数值属性:

csharp
public enum NumericType
{
    Max = 10000,

    Speed = 1000,
    SpeedBase = Speed * 10 + 1,
    SpeedAdd = Speed * 10 + 2,
    SpeedPct = Speed * 10 + 3,
    SpeedFinalAdd = Speed * 10 + 4,
    SpeedFinalPct = Speed * 10 + 5,

    Hp = 1001,
    HpBase = Hp * 10 + 1,

    MaxHp = 1002,
    MaxHpBase = MaxHp * 10 + 1,
    MaxHpAdd = MaxHp * 10 + 2,
    MaxHpPct = MaxHp * 10 + 3,
    MaxHpFinalAdd = MaxHp * 10 + 4,
    MaxHpFinalPct = MaxHp * 10 + 5,
}

核心实现:

csharp
public class NumericComponent: Component
{
    public readonly Dictionary<int, int> NumericDic = new Dictionary<int, int>();

    public void Update(NumericType numericType)
    {
        if (numericType > NumericType.Max)
        {
            return;
        }
        int final = (int) numericType / 10;
        int bas = final * 10 + 1; 
        int add = final * 10 + 2;
        int pct = final * 10 + 3;
        int finalAdd = final * 10 + 4;
        int finalPct = final * 10 + 5;

        // final = (((base + add) * (100 + pct) / 100) + finalAdd) * (100 + finalPct) / 100;
        this.NumericDic[final] = ((this.GetByKey(bas) + this.GetByKey(add)) * (100 + this.GetByKey(pct)) / 100 + this.GetByKey(finalAdd)) * (100 + this.GetByKey(finalPct)) / 100;
        Game.EventSystem.Run(EventIdType.NumbericChange, this.Entity.Id, numericType, final);
    }
}

优势:

  1. 灵活的属性管理:不同职业可以拥有不同属性
  2. 统一的计算公式:所有属性使用相同的计算逻辑
  3. 事件系统支持:属性变化可以触发相应事件

实际应用示例

监视HP数值变化:

csharp
namespace MH
{
    [NumericWatcher(SceneType.Main, NumericType.Hp)]
    public class NumericWatcher_HpChange : INumericWatcher
    {
        public void Run(Unit unit, NumbericChange args)
        {
            if (unit == null || unit.IsDisposed)
                return;
            var numericComponent = unit.GetComponent<NumericComponent>();
            var currentHp = numericComponent[NumericType.Hp];
            var maxHp = numericComponent[NumericType.MaxHp];
            if (currentHp > maxHp)
                numericComponent.SetNoEvent(NumericType.Hp, maxHp);
            if (currentHp < 0)
                numericComponent.SetNoEvent(NumericType.Hp, 0);
            var hpBarComponent = unit.GetComponent<HpBarComponent>();
            hpBarComponent.SetHpSliderHandler(unit);
        }
    }
}

技术支持

获取帮助

  • 💬 加入QQ群讨论交流(ET框架群) : 474643097
  • ⭐ 在GitHub上关注项目获取最新更新

Released under the MIT License.