最近在研究物品组件架构如何设计。也就是说,通过组件组合来实现游戏物品。

主要思路

其实就是 ECS 那套.

组件化的物品使用数据来进行完全的物品定义,而让系统或执行者来根据组件数据进行多样化的行为。

所以在这种架构里,物品是纯粹的数据定义,而系统才是执行行为的主体。

此外,标签系统也是一种物品系统(不过其数据只是一个存储标签的键值字典<string, bool>

没有网络同步的简单版本

先从没有网络同步的版本来思考。

物品实体模型

这个模型由三部分组成,分别是存储物品数据的ComponentData,存储组件列表的ComponentList物品基类和使用组件来进行操作的ItemProcessors物品执行器。

以解耦传统的Item类来示范,如一个可以发光并且有耐久机制的打火机可以拆成Lighter有光源组件Lightable、耐久组件Durability、用于标识物品信息的标识符组件Identity

在系统需要实现物品行为的时候,由ItemProcessors来根据物品执行。

比如说玩家手持矿稿点击地面的时候MiningSystem或者MapSystem就会来读取玩家手中物品信息Item然后搜索组件来执行行为。

就像 ECS 一样把物品拆解了。

在数据驱动的加持下,这样极大增加了物品实现的灵活性和可扩展性(可以轻松实现新的物品),不过代价是调试困难以及代码复杂度提高。

组件的管理

组件依赖

在组合时,会遇到组件相互依赖的问题(例如:攻击组件Attackable需要装备Equipable组件才能生效)。

一个简单有效的方式是:

  • 组件检查: 在添加 AttackComponent 时,代码检查是否存在 EquipableComponent

而更加灵活的方式是:

  • 黑板模式 (Blackboard): 物品实体上维护一个公共的数据字典,所有组件都可以读写这个字典来共享状态。 备注:一个示例就是用黑板模式来构建伤害计算公式,不管底下的组件怎么互相影响,最终都以黑板计算结果为主。

附录

classDiagram
     2. 动态实例层 (Runtime & Network)
    class ItemInstance {
        <<struct>>
        +int TypeID
        +float CurrentDurability
        +INetworkSerializable Serialize()
    }
    note for ItemInstance "背包中的数据包,通过RPC传输"

     4. 控制中心 (NGO NetworkBehaviour)
    class ServerItemHandler {
        <<NetworkBehaviour>>
        -Inventory PlayerInventory
        +RequestUseItemServerRpc(slotIndex, targetPos)
    }

    %% 关系描述
    ServerItemHandler ..> ItemInstance : 持有/验证
    ItemInstance ..> ItemDefinition : 根据TypeID查询
    ServerItemHandler --> VoxelProcessor : 调用
    ServerItemHandler --> CombatProcessor : 调用
    VoxelProcessor --> VoxelMap : 修改地图数据
    CombatProcessor --> EffectProcessor : 触发状态效果