UI框架(2022.1.12)
之前任由ui逻辑自行发展,出现了很多难以解决的问题,如交互按钮与菜单重合、要隐藏hud时不能一键处理,某些外部创建的ui如任务追踪,hud并不能拿到其实例,造成不知如何去隐藏它的窘境,必须立刻规范ui的创建和管理流程,理清思路。
首先将ui按层级区分,定义一个RootWidget,它来维护各个ui的层级关系,枚举暂时先分三个:Low、Middle、Top,然后为每一层创建一个SOverlay,外部创建的ui根据传入的层级加到相应的Overlay上,删除的时候同理。要注意的是还需要一个RootOverlay来装所有的层级Overlay,然后在RebuildWidget
中返回。
UIManager的实例由插件的Module在初始化时创建,然后游戏中用GameInstance去拿。
为每个HUD单独创建RootWidget(2022.2.9)
为了能在调试时支持多个客户端,将RootWidget按HUD分离,创建一个UIControlComponent
专门管理,这样本地有多个Player就会有多个HUD,就会有多个RootWidget了,而且刚好也可以将项目的HUD创建流程规范一下。
Plugin相关
由于需要给其他Plugin使用,干脆将框架内的类也做成一个Plugin,这样一来就将ui管理和游戏逻辑完全分开了。有很多东西需要配置,下面一一列举:
- 类声明前面要加插件名+
_API
的宏 build.cs
中要告诉项目我们要使用这个插件- 插件相互引用时,需要在
.uplugin
文件中增加要引用插件的名称,如果相互引用了就都要加 - 插件中如果使用了引擎中的模块,如
UMG
也要添加进配置中
static变量要在cpp重新定义
Bug
- 明明将RootWidget加到Viewport上了,并且将新创建的ui加进了Overlay的Slot,但是看不到任何东西,后来得知是一个UserWidget自己必须也有一个类似Root的控件,然后把其他ui放进去,通过重写
RebuildWidget
方法,创建一个SOverlay作为Root,再把创建好的层级进去,就能正常显示了。 - 底层的ui居然会盖在上层的ui上面,多天的debug和求助之后发现是之前创建ui的地方遗留了一个将所创建ui加到Viewport上的代码,而此时我们其实希望它在Manager所管理的RootWidget上。
- gc问题导致崩溃:Manager中的RootWidget在AddToViewport之后,会在场景切换的时候被清除,但是Manager并不会,因此当Manager重新初始化创建RootWidget的时候需要进行判断,如果之前存的指针内容有效(
IsValidLowLevel
),则需要RemoveFromParent并告诉引擎将其回收(MarkPendingKill
)。 - 优化UI框架后发现Remove方法失效,排查发现是使用的World不同,全局的GWorld和
GetWorld
拿到的World不一定是同一个,而UserWidget自己可以拿到World,Remove的时候直接用自己World就行了 - UserWidget中有一个MyGCObject的东西,它在被gc时Widget本身还在,但是lua实例可能会被前一步gc,此时如果调用了这个ui上的某个lua实现的方法,会导致lua报错崩溃。解决方法是除了判Widget,加一个
GetCachedWidget
的判断 - lua使用GetUIManager过早导致引擎卡死
- LobbyChar身上不存在的Component初始化报错
- 摄像机状态初始位置始终不对
- 武器信息转移到新角色后丢失,原因是前一个模型对象保存的是武器Actor指针,模型在Destroy的时候一并将指针内容gc了