UI 上下文系统

介绍
在虚幻引擎中制作UI时,时常会面临将一组数据在不同的UI之间,或者不同层级的UI之间进行共享和传递的需求。
尽管我们可以在父级UI中通过传参的方式为子层级上的UI传递数据,但当UI的层次结构非常深的时候,这种方式会显得特别繁琐。同时不同层级的UI之间的数据通信,也要提前拿到它们之间的引用再进行事件绑定。
而UE5 通用游戏系统中的UI上下文系统则提供一种更优的方式来更好的解决这种问题,该系统允许你针对游戏中的每一个玩家,跨UI共享/传递特定的一组数据,可以避免UI之间的交叉引用,以及数据的层层传递和包装。
什么是上下文
简单来讲,上下文是一个在不同的UI之间扮演中间人的一个UObject。
以我的库存系统举例,库存系统中的库存菜单是具备可复用性的,玩家查看自己的道具,通过商店购买/销售道具,从装备菜单中选择要装备什么道具,以及从关卡中的宝箱中搜刮物品时,都是共享的同一个“库存菜单”。只是库存菜单激活时,会根据不同的上下文,修改库存菜单的内部行为。
当玩家与商人交易时,“玩家及其库存,商人NPC及其库存,是购买还是销售,玩家选择了哪个道具进行购买/销售等”就是上下文所存储的信息。购买时,库存菜单展示的是商人的库存中的道具,标题栏显示的是“Buy”;销售时,库存菜单展示的是玩家库存中的道具,标题菜单显示的是“Sell”。
创建上下文类型
在GGS中,你通过创建GUIS_GameUIContext
来创建新的上下文类型。

注册和取消注册上下文
下面的蓝图展示了我在“与商人交易”的交互Ability中,如何构建UIContext。



你可以看到,我并没有将UI所需的参数通过Cast的方式进行传递,而是将所需的数据塞入上下文,之后UI可以通过上下文对数据进行访问。
访问上下文
上下文一般是在UI打开前就已经注册好,所以后续的UI可以直接访问,也可以往里面存储新数据,触发事件等。

在上图中,库存菜单激活时,会根据UI上下文类型,修改自身行为(开关某些功能)。
该截图第一眼看起来可能有些混乱,但不然,这让UI本身变得更加自包含。
你可以完全换一个Widget来实现商店交易的UI部分,但其数据通信,Context是可以无需修改的。
注意事项
- 每一个LocalPlayer之间的所有上下文是隔离开的。
- 同一类型的上下文只能被注册1次。
- 最好由注册上下文的对象来负责上下文的取消注册。