UE中如何优雅地在GUI界面禁用游戏输入
最近软工的大程需要在UE中制作GUI,我之前并没有使用过,所以基本上都是现查现用,但在搜索过程中发现网上并没有GUI打开期间禁用游戏输入的比较优雅的方案(也可能是我没找到),最后在实践中发现一种比较好的解决方案。
首先明确一下我想实现的最终效果,即游戏最终有多个GUI菜单,按下不同按钮打开不同的菜单,但是按下任意控制菜单的按键都能够关闭当前菜单,打开菜单后,用户将不能继续控制人物移动等,但游戏仍继续运行(即不停止游戏时间)。
在这里我首先是在Edit-Project Settings-Engine-Input-Bindings-Action Mappings里添加对应的按钮映射。
一种非常直接的想法是按下按钮打开GUI,之后Set Input Mode UI Only,但是UI Only模式下按钮映射将不起作用。
另一种方案是UE里UMG支持Stop Action,直接在Designer里选中该蓝图勾选Stop Action就能实现禁用游戏输入。我的最终方案也基于这个。通过勾选Stop Action,我们能实现在打开UI后禁用游戏输入,但是这个时候UI还不能用按钮关闭,我们需要在该UI的Construct Event里添加对Input Action的监听,在Input Action事件发生的回调函数里Remove From Parent,这样子就实现了关闭GUI。
但这个方案依然有一定的局限性,很容易发现,它的扩展性并不好。我们想要实现按下任意控制菜单的按钮都能关闭当前菜单,但是现在如果我们需要添加一个菜单,那么就需要在所有已有的菜单里添加对该按钮对应Input Action的监听以实现其他按钮也能关闭该菜单。
为了便于扩展,我们把这个过程抽取出来,作为BaseMenuWidget_BP
,这个GUI只有一个空的Canvas,勾选Stop
Action,我们在它的Construct事件中添加对所有GUI的Input
Action的监听,并在回调函数中摧毁它的子UI和它本身。
每当我们想要创建一个GUI时,我们创建一个Input
Action的监听,在回调函数里创建BaseMenuWidget_BP
,然后将我们想要创建的GUI作为它的Child。由于BaseMenuWidget_BP
已经勾选了Stop
Action,所以我们想要创建的真正的GUI就不需要再勾选Stop
Action。在打开后,我们按下任意控制GUI的按钮,BaseMenuWidget_BP
会连带它的child一起被摧毁,就达到了我们想要的效果。
下面是BaseMenuWidget_BP
的完整蓝图。之后每当我们需要新增一个菜单只需要在这里添加一个Input
Action的监听。
下面是创建一个菜单的示例,每当我们想要创建一个菜单,需要先创建BaseMenuWidget_BP
,然后把真正的菜单作为它的child。这里我对添加为子窗体做了一定的封装。
封装的内容实际上就是这样一个简单的函数蓝图。
但是这样还有最后一个问题,我们会发现打开Widget后,需要先点一下才能focus在Widget,关闭Widget后也需要再点一下才能重新控制视角。解决方案是在BaseMenuWidget_BP
的Event
Construct中Set Input Mode Game And UI,主要要取消Hide Cursor During
Capture,在HideWidget中将mode切回到GameMode,也就是Set Input Mode Game
Only。最终的蓝图如下。