Tizeng's blog Ordinary Gamer

Gaia笔记6——UI框架

2022-01-12
Tizeng

UML

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了

Comments

Content