第二十二章:附加内容
1. 本章核心目标
本章的核心在于为游戏项目增加四个独立的系统,旨在深化游戏的可玩性和提升项目的完整性与可维护性。
-
显性目标 (玩家体验):
-
可配置服务器: 允许服务器管理员(通常也是玩家)通过外部文件自定义服务器名称、地图、玩家上限及游戏倍率,提升了多人游戏的个性化和管理便捷性。
-
游泳系统: 玩家角色现在可以在水体中游泳,增加了世界的探索维度和真实感。
-
地表脚步系统: 玩家在不同材质(如草地、沙地、木板)上移动时,会产生对应的脚步声和粒子特效,增强了环境的沉浸感和反馈。
-
种植系统: 玩家可以放置种植盆,播种、施肥并等待作物分阶段生长,最终收获,丰富了生存和资源管理的玩法。
-
-
隐性目标 (技术与战略):
-
解耦配置与逻辑: 将服务器配置从蓝图的硬编码中分离出来,便于非开发人员调整,是产品化和长期运营的重要一步。
-
扩展物理与动画系统: 引入物理材质和动画通知(Anim Notify)的联动,探索更精细的物理-动画交互实现。
-
设计模式复用与数据驱动: 复用并扩展了类似“熔炉”的“处理站”设计模式,并引入数据表(Data Table)来管理作物生长阶段的网格体,强化了数据驱动设计的思想。
-
补全核心生存玩法循环: 种植系统为游戏后期的资源循环提供了新的维度,使生存体验更加完整。
-
目标关系图:
显性目标 (玩家层面) | 隐性/战略目标 (开发/项目层面) |
---|---|
1. 可配置服务器 | 解耦配置与逻辑,提升项目可维护性与运营便利性。 |
2. 游泳系统 | 增强角色控制器,解决引擎特定模式的局限性。 |
3. 地表脚步系统 | 扩展物理与动画系统的综合应用,提升环境交互的实现深度。 |
4. 种植系统 | 复用设计模式,实践数据驱动设计,补全核心玩法循环。 |
2. 系统与功能实现
本章实现了以下四个核心系统,并与前期系统进行了深度交互。
系统/功能 | 描述 | 与前期系统的交互/依赖 |
---|---|---|
专用服务器配置文件系统 | 通过启用 JSON Blueprint Utilities 插件,在 GameInstance 中实现了在创建会话前读取外部 server-config.json 文件的功能。 系统能解析服务器名、地图、最大连接数及各项倍率(如采集、经验),并为监听服务器提供了备用方案,即从UI获取倍率设置。 |
- 修改了 GameInstance 中的 Create Advanced Session 流程。 - 依赖于 GameMode 来区分专用服务器和监听服务器。 - 影响了 角色经验获取 ( Add Experience ) 和资源采集 (Add Resources ) 的最终数值计算。 |
游泳系统 | 在 BP_OceanSwimming 蓝图中使用盒体碰撞器触发角色进入/离开游泳状态。 角色通过接口调用进入游泳状态后,会切换动画状态机至游泳姿态,并将其移动模式设置为Flying (飞行)以规避原生Swimming 模式的Bug。 移动输入逻辑被修改,以允许玩家通过视角朝向控制上浮和下潜。 |
- 依赖于 动画蓝图中的状态机来切换动画。 - 修改了 角色蓝图中的移动输入逻辑。 - 扩展了 角色控制器的状态管理(通过新增 isSwimming 布尔值)。 |
地表脚步系统 | 定义了一系列物理材质(沙、草、水、木、石、金属),并将它们分配给场景中的不同对象(如地貌、建筑部件)。 在行走/奔跑动画中添加Footstep 动画通知,在动画蓝图中捕获此通知,并向下发射射线检测,根据检测到的物理表面类型,播放对应的声音和Niagara粒子特效。 |
- 深度依赖 UE的物理材质(Physical Material)系统。 - 依赖于 动画蓝图的动画通知(Anim Notify)机制。 - 扩展了 游戏中几乎所有可供行走的静态网格体和地貌的资产设置。 |
作物种植系统 | 通过复制和修改“熔炉”蓝图实现。 这是一个基于定时器和状态机(使用isSeeded , isGrowing , isFruiting 等布尔值)的系统。 它根据配方检查库存中的种子和肥料,在不同生长阶段通过异步加载并切换不同的植物网格体。 当作物成熟后,系统会周期性地将产物添加到库存中。 |
- 复用并修改了“熔炉”系统(一个处理站)的逻辑框架。 - 与 物品系统(Data Asset)、库存系统、配方系统紧密耦合。 - 引入了 数据表(Data Table)来管理与物品ID关联的生长阶段网格体,实践了数据驱动。 |
3. 关键设计思想
本章的实现体现了多种重要的设计原则和模式,提升了代码的灵活性和可扩展性。
设计思想 | 描述与应用实例 |
---|---|
设计原则 | |
配置优于硬编码 | 应用: 服务器配置系统。 将服务器名、倍率等易变数据从蓝图逻辑中移至外部JSON文件,使非程序员也能轻松修改服务器设置,提高了灵活性和可维护性。 |
数据驱动设计 | 应用: 脚步系统和种植系统。使用物理材质定义地表属性,使用数据表定义作物各阶段的视觉表现(网格体)。这使得添加新的地表类型或新作物时,只需修改数据资产,而无需更改核心蓝图逻辑。 |
单一职责原则 | 应用: 各系统职责分离。例如,脚步声和特效的触发逻辑被封装在动画蓝图中,因为它直接响应动画事件(AnimNotify ),职责清晰。 |
设计模式 | |
状态模式 (State Pattern) | 应用: 作物种植系统。通过 isSeeded 、isGrowing 和 isFruiting 等一系列布尔变量,清晰地定义了作物从“空地”到“播种”、“生长”、“结果”再到“枯萎”的完整生命周期状态,并根据不同状态执行不同逻辑(如切换模型、产出物品)。 |
观察者模式 (Observer Pattern) | 应用: 脚步系统。动画系统作为“被观察者”,通过 AnimNotify (“通知”),在特定时间点(脚落地时)通知动画蓝图这个“观察者”去执行特定逻辑(播放声效和特效)。 |
策略模式 (Strategy Pattern) | 应用: 脚步系统。Select 节点根据输入的物理表面类型(EPhysicalSurface ),选择并执行不同的“策略”(播放哪种声音、生成哪种特效)。这是策略模式的一种简化实现,将算法的选择与执行分离开。 |
4. 核心技术点与难点
本章的开发过程涉及多个具体的技术挑战,并通过特定方法得以解决。
核心技术点/难点 | 描述 | 解决方案与实现 |
---|---|---|
启用C++插件与项目重新编译 | 服务器配置功能需要 JSON Blueprint Utilities 插件,而启用这类含C++代码的插件,要求从IDE (Visual Studio) 中手动重新编译整个游戏项目。 |
1. 在UE编辑器中启用插件并重启。 2. 关闭UE编辑器,在Visual Studio中打开项目的 .sln 文件。 3. 在解决方案资源管理器中,右键点击项目并选择“生成”(Build)来完成编译。 |
规避引擎内置游泳模式的Bug | 开发过程中发现,引擎默认的 Swimming 移动模式存在问题(被描述为 “buggy”)。 |
使用 Flying (飞行) 移动模式作为替代方案。 同时,重写了部分移动输入逻辑,将玩家的视角俯仰(Pitch)与角色的Z轴移动关联起来,从而实现了通过抬头和低头来控制上浮和下潜。 |
动态异步加载资源 | 在种植系统中,当作物进入下一个生长阶段时,需要切换其静态网格体。如果同步加载,可能会导致游戏瞬间卡顿,影响体验。 | 使用 Async Load Asset (异步加载资产) 节点来加载下一阶段的植物网格体。 加载完成后,通过其 Completed 回调引脚来执行设置网格体的逻辑,从而避免了对游戏主线程的阻塞。 |
物理材质与动画通知的联动 | 脚步系统的核心是精确地在脚接触不同地面时触发相应的效果。 | 1. 材质定义: 利用UE的物理材质系统为不同表面(地貌层、建筑模型)打上“标签”。 2. 事件触发: 在动画序列的精确帧(脚落地时)添加 AnimNotify 作为事件触发点。 3. 信息获取: 在动画蓝图中响应通知,并从角色脚下进行向下射线检测,从命中结果中获取表面的物理材质信息。 |
5. 自我批判与重构
本章的实现虽然功能完整,但也暴露出一些设计和实现上的问题,为未来的优化提供了方向。
-
遇到的“坑”与关键问题:
-
繁琐的手动操作: 脚步系统要求为每一个行走/奔跑相关动画手动添加多个动画通知,这是一项重复性高且容易出错的工作。
-
资产准备流程复杂: 种植系统的植物模型需要通过 Quixel Bridge 插件获取,并涉及到引擎重启、项目重新编译和手动合并Actor等多个步骤,流程繁琐且对不熟悉的用户不友好。
-
设计迭代中的局限: 种植系统的逻辑最初在函数内实现,后因需要使用
Async Load
节点(该节点不能在函数中使用)而被迫迁移到事件图表中,这反映了初期设计的局限性。 -
对引擎Bug的妥协: 游泳系统直接放弃了原生的
Swimming
模式,转而使用Flying
模式作为权宜之计,这并非一个根本性的解决方案。
-
-
反思与重构建议:
问题点 | 如果重来一次的优化方案 |
---|---|
脚步动画通知繁琐 | 放弃使用 AnimNotify 。改为在角色蓝图的 Tick 事件中,实时检测脚部骨骼插槽(Socket)与地面的距离。当距离小于某个阈值时,触发一次脚步效果检测。这种方法与具体动画解耦,无论更换或新增何种移动动画,脚步系统都能自动生效。 |
种植系统状态管理 | 当前使用多个布尔值(isSeeded , isGrowing 等)来管理状态,当状态增多时容易出错。 优化方案: 使用**枚举(Enum)**类型(如 E_GrowthState )来定义作物的状态(Empty , Seeded , Growing , Fruiting , Dead )。这样状态管理更清晰、更安全,且易于扩展。 |
游泳系统的实现 | 深入研究原生 Swimming 移动模式的问题根源并尝试修复它,或者构建一个更完整的自定义移动组件(Custom Movement Component),而不是简单地复用 Flying 模式,以获得更精确和可控的游泳物理表现。 |
数据耦合问题 | 当前生长所需时间、肥料消耗等逻辑数值部分硬编码在蓝图中。 优化方案: 将这些参数也移到数据资产(如 Recipe 或 Crop Plot 的数据表)中,实现完全的数据驱动。这将使得平衡性调整和添加新作物变得极为高效,无需再修改蓝图。 |