第四章:采集系统

一、本章核心目标

本章节的核心在于横向扩展在第三章建立的采集系统基础,通过引入新的资源、工具和交互方式,极大地丰富了游戏的核心玩法循环,并显著提升了玩家的沉浸感与系统的可维护性。

  • 显性目标 (玩家体验)

    • 丰富采集对象:引入了全新的可采集资源类型,如岩石灌木,使世界更具互动性。

    • 扩展工具系统:新增了核心工具**“石镐”**,用于采集特定资源(如矿石),建立了工具与资源的强关联性。

    • 提升视觉反馈:为棕榈树增加了被砍伐时的撞击粒子特效 (VFX) 和被摧毁后的溶解 (Dissolve) 消失特效,增强了玩家行为的视觉反馈和沉浸感。

    • 优化库存管理:实现了物品堆叠 (Item Stacking) 功能,解决了之前采集资源会占用大量独立库存槽的问题,是核心的QoL(生活质量)提升。

    • 增加徒手采集:实现了无需工具、通过按键交互 (E键) 的徒手采集方式,用于采集灌木等地面物品。

  • 隐性/战略目标 (技术与项目)

    • 验证框架可扩展性:通过添加石镐、岩石和灌木,检验了第三章建立的基于数据驱动和蓝图继承的采集框架是否足够灵活和可扩展。

    • 深化数据驱动设计:全面使用 Data Asset 来定义新的可采集资源、掉落物、工具属性等,进一步将游戏逻辑与数据分离,便于后期迭代和内容添加。

    • 建立视觉特效管线:初步建立了从材质修改(溶解)、粒子系统应用(撞击/破坏)到蓝图控制的完整VFX实现流程,为未来更复杂的特效打下基础。

    • 完善核心组件功能:对库存组件 (ItemsContainer) 进行了关键性重构,使其支持堆叠逻辑,这是任何生存建造游戏都不可或缺的核心功能。

    • 构建多模态交互:引入了基于按键的“交互系统”,与基于工具的“挥砍系统”并行,为未来更多样的互动(如开门、对话)提供了系统原型。


二、系统与功能实现

本章实现了多个关键系统,并与前期系统(如物品、库存、工具)进行了深度交互。

  • 功能列表与描述

    • 溶解特效系统:

      • 通过修改 M_Palm_Master 主材质,添加了一个由标量参数 Dissolve 控制的透明度遮罩溶解效果。

      • BP_PalmDestructible_Master 蓝图中,使用时间轴 (Timeline) 在树木倒地10秒后驱动该 Dissolve 参数,实现平滑的溶解动画。

    • 新工具(石镐)系统:

      • 通过复制和修改石斧的 Data Asset 和蓝图,快速创建了石镐(DA_StonePickaxe, BP_StonePickaxe)。

      • 该系统复用了父类 Tool_Master 的全部挥砍和伤害逻辑,仅需在子类中定义新的模型、工具类型(枚举)和属性。

    • 岩石采集系统:

      • 使用 Quixel Bridge 导入高精度岩石模型。

      • 创建了 BP_Rock_Master 作为所有可采集岩石的父类,并派生出具体的岩石蓝图(如 BP_Beach_Rock_01)。

      • 利用 Chaos物理引擎Fracture 模式创建了几何集合体 (Geometry Collection),用于实现岩石的破碎效果。

      • 创建了 BP_Destructible_Rock 蓝图,在被摧毁时生成破碎体,并额外生成一个 BP_Destruction_Force Actor来施加径向力,使破碎效果更真实。

    • 徒手采集(交互)系统:

      • 创建了 BP_GroundItem_Master 作为徒手采集物品(如灌木)的基类。

      • 新增了输入按键 E,并在玩家角色蓝图中实现了 F_Interact 函数,该函数执行向前射线检测,寻找实现了 BPI_Interactable 接口的Actor。

      • 如果检测到的是可徒手采集的物品,则执行 F_HarvestGroundItem 函数,播放采集动画并给予玩家资源。

    • 物品堆叠系统:

      • 重构了 BPC_ItemsContainer 中的 AddItem 函数。

      • 核心逻辑:

        1. 检查物品 Data Asset 中的布尔值,判断是否可堆叠。

        2. 若可堆叠,遍历库存寻找同ID且未满堆叠的物品。

        3. 找到则补充数量,并计算溢出量。

        4. 若有溢出或未找到可堆叠的物品,则寻找空栏位创建新堆叠。

        5. 若物品不可堆叠,则执行原逻辑(寻找空栏位)。

    • 控制器支持系统:

      • 为手柄实现了完整的UI导航,通过重写 GetDesiredFocusTarget 来设置初始焦点。

      • 实现了基于单击的“选择-放置”式物品移动(模拟拖拽) 和基于双击的快捷转移功能(如在库存和快捷栏之间转移)。


三、关键设计思想

本章的设计思想高度统一,以可扩展性可维护性为核心。

设计思想/原则 具体应用实例 优势分析
蓝图继承 (Inheritance) - BP_StonePickaxe 继承自 BP_Tool_Master
- BP_Rock_Master 继承自 BP_LargeItem_Master
- 所有可摧毁Actor的蓝图(如棕榈树、岩石、灌木的破碎体)均继承自 BP_Destructible_Harvestable
代码复用:子类自动获得父类的核心功能,无需重写。
结构清晰:形成了清晰的层级关系,易于理解和管理。
易于扩展:添加新品种的树、矿、工具,只需创建新的子蓝图并配置其特有属性即可。
数据驱动 (Data-Driven) - 工具属性:石镐的ID、名称、图标、类别等存储在 DA_StonePickaxe 中。
- 资源掉落:岩石和灌木的掉落物(石头、铁矿、浆果)、数量、所需工具类型等均定义在各自的 Harvesting Resource Data Asset 中。
- 物品属性:新增的石头、铁矿、浆果等物品是否可堆叠、堆叠上限、重量等属性都在其 Item Info Data Asset 中定义。
解耦:将游戏数据(如掉落率、物品属性)与游戏逻辑(蓝图代码)分离。
快速迭代:策划或设计师可以直接修改 Data Asset 来调整游戏平衡和内容,无需修改代码。
配置化:让游戏内容变得高度可配置,便于未来大规模添加内容。
接口 (Interface) - BPI_Interactable:定义了一个通用的交互接口,任何希望通过E键触发的物体(如灌木)都可以实现它。
- BPI_GroundItem:为徒手采集物品创建了独立的接口,用于获取/更新生命值和资源信息。
- BPI_SurvivalCharacter/Controller:用于UI和游戏世界之间的通信,如UI通知控制器移动物品,或通知角色执行快捷转移。
松耦合:调用者(如玩家角色)无需知道目标的具体类型,只需知道它是否实现了某个接口即可调用其功能。
系统解耦BPI_Interactable 使得交互系统可以独立于采集系统,未来可以轻松扩展到开门、拾取任务物品等。
开闭原则 (Open/Closed) - 工具系统:添加石镐时,我们扩展BP_Tool_Master(通过创建子类),但没有修改其内部的通用挥砍逻辑。
- 采集物系统:添加岩石和灌木,都是通过创建新的采集物蓝图和对应的 Data Asset扩展系统,而无需修改玩家角色的核心采集判定代码。
稳定性:核心代码库保持稳定,不易因添加新功能而引入Bug。
可维护性:新增功能被隔离在新的类中,易于定位和修改。

四、核心技术点与难点

技术点/难点 描述与解决方案
动态材质实例与溶解特效 描述: 需要在运行时通过蓝图控制材质的参数,以实现平滑的溶解动画。
解决方案: 1. 在主材质中,将Opacity Mask的输入端替换为一个线性插值(Lerp)节点,并用一个名为Dissolve的标量参数来控制插值Alpha。 2. 在可摧毁物体的蓝图中,于BeginPlay事件后,为静态网格体组件创建动态材质实例 (Create Dynamic Material Instance)。 3. 使用时间轴 (Timeline) 节点输出一个随时间变化的浮点值(从1到-1),在Update引脚上持续调用Set Scalar Parameter Value来更新动态材质实例的Dissolve参数,从而实现动画效果。
Chaos 物理破碎系统 描述: 实现岩石、灌木等物体被摧毁时,能自然地碎裂成多块。
解决方案: 1. 进入UE的Fracture Mode。 2. 为目标静态网格体创建几何集合体 (Geometry Collection) 资源。 3. 使用Uniform Fracture工具将其预先切割成多个碎片。 4. 在可摧毁蓝图中,使用Geometry Collection组件代替静态网格体组件,并设置合适的伤害阈值 (Damage Threshold),使其在受到伤害时能够碎裂。
破碎效果优化 描述: 默认的Chaos破碎效果可能只是简单地散开,缺乏冲击力。
解决方案: 创建一个继承自Field System Actor的蓝图 BP_Destruction_Force。 在其内部,添加一个径向衰减 (Radial Falloff) 和一个外部张力 (External Strain) 物理场。 当原物体被摧毁时,在同一位置生成这个BP_Destruction_Force Actor,它会瞬间对周围的碎片施加一个向外的推力,模拟爆炸冲击波的效果,使破碎表现更佳。
复杂的物品堆叠逻辑 描述: 实现一个能正确处理所有边界情况(如填满部分堆叠、溢出到新格子、多堆叠溢出等)的健壮的物品堆叠系统。
解决方案: 设计了一个多层检查和循环的AddItem函数。算法核心在于:1. 检查与循环: 优先循环寻找已存在的、未满的同类物品堆叠。 2. 数量计算: 精确计算当前堆叠能吸收多少数量,以及剩余的溢出数量。 3. 递归/循环调用: 如果存在溢出,则将溢出部分作为“新物品”再次尝试添加到库存中,这个过程会持续到所有物品都被放入或库存已满。这个逻辑通过For Each Loop with Break和后续的检查循环实现。
控制器UI交互的非原生实现 描述: UMG本身没有直接的“双击”事件或“控制器拖拽”状态。
解决方案: 1. 双击模拟: 在 W_InventorySlotOnPressed 事件中,使用一个浮点数变量clicks作为计数器,并配合一个0.2秒的可重触发延迟 (Retriggerable Delay)。每次点击clicks++,如果延迟结束时clicks仍为1,则判定为单击;如果在延迟期间再次点击,clicks变为2,则判定为双击。 2. 拖拽模拟: 单击物品时,在玩家控制器 (Player Controller) 中记录下该物品的来源容器和索引,并设置一个bIsItemSelected布尔值为true。 当再次单击另一栏位时,若bIsItemSelectedtrue,则调用已有的OnSlotDrop逻辑,使用之前存储的来源信息和当前点击的目标信息来完成移动,然后将布尔值重置。

五、自我批判与重构

  • 遇到的“坑”或关键问题:

    • 破碎几何体的材质问题: Chaos破碎后的几何体,如果没有在材质中勾选Used with Geometry Collections,会出现渲染错误(如棋盘格)。 这是一个容易忽略但影响视觉效果的关键设置。

    • 控制器焦点管理: 如果不主动通过GetDesiredFocusTarget设置初始焦点,手柄在打开UI时将处于“失焦”状态,无法进行任何操作。

    • 物品堆叠的边界情况: 堆叠逻辑的复杂性很容易导致Bug,例如,对剩余数量的计算错误可能导致物品被“吞掉”或“复制”。开发过程中必须对所有可能的堆叠情景(满堆叠、部分堆叠、无堆叠、溢出)进行充分测试。

  • 对前期设计的反思与修正:

    • 石斧工具类型修正: 在创建石镐时,反思发现之前的石斧BP_StoneHatchet没有正确设置其ToolType枚举为Hatchet,本章对此进行了修正。 这是一个对前期疏忽的良好修正,体现了在迭代中完善系统的过程。

    • 主干蓝图的“净化”: 在创建棕榈树的子蓝图前,清空了父类Destructible_Tree_Master中的静态网格体引用。 这是一个非常好的实践,确保了父类(模板)的通用性,避免子类意外继承不必要的资产引用,从而优化内存。

  • 如果重来一次,如何优化

    • 统一采集接口: 当前为大型采集物(树、矿)和地面采集物(灌木)创建了两个功能几乎完全相同的接口 (BPI_LargeItem vs BPI_GroundItem)。 如果重来,可以设计一个更为通用的BPI_Harvestable接口,内部包含一个GetRequiredToolType函数。徒手采集可以被视为需要一个特殊的“Hand”工具类型,这样就可以用一套逻辑处理所有采集行为,减少接口冗余。

    • 使用Enhanced Input实现双击: 当前在UI中模拟双击的逻辑是有效的,但属于“手摇轮子”。 Unreal Engine的Enhanced Input系统原生支持多击(Double Tap, Triple Tap)触发器。如果重来,会研究如何将这些系统级输入触发器更优雅地与UMG的事件系统结合,可能会让实现更简洁、更官方。

    • 将物品转移逻辑集中化: 目前物品转移的逻辑分散在多个地方(Player Controller处理拖拽,TransferItemHotkey函数处理双击快捷转移)。可以考虑创建一个专门的InventoryTransferManager或类似的单例/子系统,集中处理所有类型的物品转移请求,无论其来自鼠标拖拽、控制器单击还是双击。这将使得逻辑更集中,易于调试和扩展。