第二十章:网络会话与前端UI
一、 本章核心目标
本章节的目标是构建完整的游戏前端体验框架,为玩家提供清晰、功能完备的入口,并为后续的多人游戏功能打下坚实的UI与系统基础。
-
显性目标 (Player-Facing Goals):
-
主菜单搭建: 实现玩家启动游戏后看到的第一个交互界面,包括单人游戏、多人游戏、设置和退出等核心入口。
-
设置菜单实现: 提供一个全面的设置中心,允许玩家自定义图像、音频和输入控制,以优化个人游戏体验。
-
游戏模式入口: 提供明确的单人模式和多人模式入口,允许玩家直接开始单人游戏或进入多人服务器浏览器。
-
游戏内菜单: 实现游戏中可随时调用的“逃生菜单”(ESC菜单),提供返回游戏、设置、返回主菜单和退出游戏等功能。
-
初始角色创建流程: 为首次进入游戏的玩家设计一个“出生点选择窗口”,允许玩家输入角色名并选择初始出生区域。
-
-
隐性/战略目标 (Technical/Project Goals):
-
UI框架与模块化: 建立一套可复用、模块化的UI组件体系。例如,将各类设置(如图形、音频、输入)拆分为独立的Widget,便于管理和扩展。
-
系统解耦: 通过为菜单系统创建独立的
GameMode
和PlayerController
,将前端UI逻辑与核心游戏逻辑进行有效隔离,降低耦合度。 -
引擎系统集成: 深入集成并应用虚幻引擎的核心系统,如使用
Game User Settings
持久化图像设置,以及利用Enhanced Input System
实现运行时的按键重映射功能。 -
多人会话前端: 搭建支持Steam多人会话(Session)的前端界面,包括创建游戏(Host)和查找游戏(Find)的UI,为后续的网络功能提供用户操作入口。
-
-
目标关系图:
graph TD A[<b>本章总目标: 构建完整前端体验</b>] --> B{显性目标: 玩家功能}; A --> C{隐性目标: 技术与架构}; subgraph B B1[主菜单 & 游戏入口] B2[功能全面的设置菜单] B3[游戏内ESC菜单] B4[新玩家出生流程UI] end subgraph C C1[建立模块化UI框架] C2[解耦菜单与游戏逻辑] C3[集成引擎核心系统] C4[实现多人会话UI基础] end B1 --> C4; B2 --> C1; B2 --> C3;
二、 系统与功能实现
本章节实现了一系列相互关联的前端UI系统,具体如下表所示:
系统/功能 (System/Feature) | 详细描述 (Description) | 与前期系统的交互/依赖 (Interaction/Dependency) |
---|---|---|
主菜单系统 (W_PlayDomain ) |
作为游戏的主入口界面,包含“单人”、“多人”、“设置”、“退出”按钮。其背景采用了动态视差效果,根据鼠标位置移动,提升视觉表现力。 | 依赖: 无直接前期系统依赖,是新构建的独立前端流程。 交互: 通过按钮事件触发关卡加载 ( Open Level ) 或创建其他UI Widgets。 |
设置系统 (W_OptionsMenu ) |
一个多标签的设置中心,通过Widget Switcher 切换不同设置页面。 |
依赖: - 图形设置: 依赖引擎的 Game User Settings 对象来存取配置。- 输入设置: 深度依赖前期构建的 Enhanced Input System 的InputMappingContext 。 |
单人游戏模式 | 简化版的单人模式入口。点击按钮后,直接通过Open Level 节点加载预设的“Island”地图。 |
交互: 加载游戏世界后,将激活前序章节中实现的角色数据存读档系统。 |
多人会话系统 (UI) | 包含W_MultiplayerMenu 、W_HostGame 、W_FindSession 和W_ServerSlot 四个核心Widgets,分别用于多人游戏入口、创建会话、查找会话(服务器浏览器)及显示单个服务器条目。 |
交互: - 创建会话: 调用 Create Advanced Session 节点,并将服务器名、地图名等信息作为Extra Settings 打包。- 查找会话: 调用 Find Advanced Sessions 节点,并动态生成W_ServerSlot 列表。 |
新玩家出生系统 (UI) | W_SpawnInMenu ,在玩家首次进入游戏世界时弹出,提供角色命名和出生点选择功能。 |
交互: - 角色命名: 与 PlayerState 交互,更新玩家名。- 选择出生点: 与 PlayerCharacter 蓝图中的生成逻辑交互,决定最终出生位置。 |
游戏内ESC菜单 (W_EscapeMenu ) |
在游戏场景中通过ESC 键调用,提供返回、设置、退回主菜单等功能。是独立于主菜单的、在游戏内HUD层显示的模态窗口。 |
依赖: 依赖游戏内Survival_PlayerController 来监听ESC 输入事件并管理自身的显示/隐藏。 |
三、 关键设计思想
本章的设计遵循了现代UI开发的通用原则,以确保系统的可维护性和扩展性。
-
设计模式 (Design Patterns):
-
组合模式 (Composition): 大量使用Widget组合来构建复杂UI。例如,
W_OptionsMenu
由W_GraphicsSettings
、W_AudioSettings
等子Widget组合而成,而W_FindSession
则动态组合多个W_ServerSlot
来构成服务器列表。这种模式使得每个UI部分都可以独立开发和修改。 -
观察者模式 (Observer / Event-Driven): 系统的核心交互是事件驱动的。UI控件(如按钮、滑块)的各种事件(
OnClicked
,OnValueChanged
)是信号(Subject),而处理这些事件的蓝图逻辑则是观察者(Observer)。这种模式将UI表现与业务逻辑解耦。
-
-
设计原则 (Design Principles):
-
单一职责原则 (Single Responsibility Principle, SRP): 每个Widget都聚焦于一个明确的功能。
W_GraphicSetting
只负责展示和响应一组(低、中、高、极高)图形选项;W_ServerSlot
只负责展示一个服务器的信息。这使得代码逻辑清晰,易于定位和修改。 -
关注点分离 (Separation of Concerns, SoC): 将UI(视图)与控制逻辑和数据(模型)分离。
-
UI与控制器分离: 菜单的显示/隐藏、输入模式的切换等高层逻辑由
PlayerController
负责,而Widget本身只负责内部的渲染和事件派发。 -
菜单与游戏逻辑分离: 通过引入
MainMenu_GameMode
,将主菜单的规则和流程与游戏世界的核心玩法规则彻底分开。
-
-
四、 核心技术点与难点
本章节的实现涉及多个虚幻引擎的核心技术,并解决了一些具有挑战性的问题。
-
核心技术点:
-
UMG (Unreal Motion Graphics): 深度应用UMG系统,包括但不限于各类控件的自定义样式、数据绑定 (
Binding
)、以及使用Widget Switcher
和Scroll Box
进行动态内容管理。 -
Game User Settings
API: 利用此API实现图形和视频设置的读取、应用和持久化存储。这是一个标准化的、跨平台的设置管理方案。 -
Enhanced Input System
运行时重映射: 核心难点在于动态修改InputMappingContext
。正确流程是:获取EnhancedInputLocalPlayerSubsystem
,清除所有现有映射,直接修改内存中的InputMappingContext
对象(设置新的按键),然后将修改后的InputMappingContext
重新添加到Subsystem中。 -
Advanced Sessions
插件应用: 熟练运用该插件替代引擎原生会话节点,实现了创建带自定义元数据(如服务器名、地图)的会话和异步查找会话的功能。 -
自定义
SaveGame
对象: 当Game User Settings
不满足需求时(如音频设置),通过创建自定义的SaveGame
派生类来灵活地实现数据的持久化存储。
-
-
技术难点与解决方案:
难点 (Challenge) | 解决方案 (Solution) | 优势/劣势 (Pros/Cons) |
---|---|---|
主菜单动态背景视差效果 | 在Event Tick 中,获取鼠标相对于视口的位置百分比。将此百分比乘以不同的系数,分别作为前景和背景图像的Render Translation 偏移量。对前景图像的偏移量取反,从而实现视差效果。使用FInterpTo 节点进行平滑插值,避免画面突变。 |
优势: 纯蓝图实现,成本低,效果显著,提升了菜单的视觉质感。 劣势: Event Tick 有性能开销,但对于主菜单这种独立场景几乎可以忽略不计。 |
从会话结果中解析自定义数据 | 在创建会话时,使用Make Literal Session Property String 节点将服务器名和地图名等自定义数据以键值对(Key-Value)形式存入Extra Settings 。在查找到会话后,从BlueprintSessionResult 中获取Extra Settings ,并使用Get Session Property String 节点通过相同的键(Key)来提取对应的值。 |
优势: 灵活、可扩展,允许在不修改引擎代码的情况下传递任意自定义的会话信息。 劣势: 依赖字符串键匹配,如果键名在创建和读取时不一致会导致数据解析失败,需要仔细管理。 |
Steamworks SDK集成与配置 | 严格按照官方文档,在Config/DefaultEngine.ini 文件中添加和配置OnlineSubsystemSteam 。关键在于确保配置项的正确性和顺序,例如OnlineSubsystem 的定义必须在NetDriverDefinitions 之前,且要指定正确的Steam App ID(开发阶段使用480)。 |
优势: 实现了与Steam平台的集成,为后续的服务器列表、好友邀请、成就等功能奠定了基础。 劣势: 配置过程繁琐且极易出错,一个错误的配置项或顺序就可能导致Steam子系统初始化失败。 |
五、 自我批判与重构
本章节的实现虽已满足核心功能,但在设计和实践中也暴露出一些可优化之处。
-
遇到的“坑”或关键问题:
-
引擎版本迭代导致API变更:
Enhanced Input System
的按键重映射逻辑在引擎更新后发生了重大变化。旧的Unmap Key
/Map Key
方法失效,必须重构为直接修改InputMappingContext
并重新注册的方案。 -
配置文件顺序问题: 在配置
DefaultEngine.ini
以启用Steam时,由于配置项的顺序不当(例如VoiceEnabled=true
放在了OnlineSubsystem
定义之上),导致Steam子系统未能正确初始化,这是一个难以发现的配置陷阱。 -
Widget引用混淆: 在实现“出生菜单”时,错误地复用了为“重生菜单”设计的
W_RespawnZone
,而不是新复制的W_SpawnZone
,导致逻辑不匹配。这强调了在复制和重用资产时保持清晰命名的重要性。
-
-
对前期设计的反思与修正:
-
单人模式过于简化: 当前的单人模式只是一个直接加载地图的快捷方式。反思认为,一个更完善的设计应该引入一个中间UI,让玩家能够管理存档、选择地图或调整特定于单人游戏的设置,这在讲座中也有提及。
-
缺少游戏内菜单: 前期设计中忽略了游戏进程中的暂停/菜单需求。本章通过添加ESC菜单弥补了这一核心体验的缺失,是必要的设计修正。
-
-
重构优化设想 (If I were to do it again):
-
全面采用接口通信: 当前部分UI间的通信(如图形设置按钮与其父容器)依赖于
GetPlayerController
后的强制类型转换 (Cast
)。如果重来,会全面采用**蓝图接口(Blueprint Interface)**进行通信。这可以彻底解耦UI组件,使其不依赖于任何特定的PlayerController
或父Widget,从而实现真正的“即插即用”。 -
引入中心化UI管理器: 当前UI的创建和销毁逻辑散布在各个触发点(如A按钮点击创建B窗口)。可以设计一个单例的
UI_Manager
,负责所有顶层UI面板的堆栈式管理(Push/Pop)。所有UI创建请求都发往该管理器,由它来处理显隐、层级和输入模式切换,使UI流程控制更集中、更清晰。 -
数据驱动UI生成: 图形设置菜单当前是在UMG编辑器中手动布局每一行。更优的方案是将其数据驱动化。可以创建一个数据表(Data Table),定义每项图形设置的名称、类型(下拉、滑块)、以及对应的
GameUserSettings
函数。Widget在构建时读取数据表,动态生成所有设置行。这样做将极大简化未来新增或修改图形选项的工作量。
-