ImGui作为游戏内嵌工具GUI库的集成过程

最近研究接触了下ImGui, 发现这货结合Cocos2d-x系列引擎写游戏工具非常方便,据笔者分析,有如下优点:

  • 不会污染游戏逻辑
  • 复用游戏场景功能
  • 无需美术提供工具资源,自动布局的菜单按钮,程序员轻松搞定
  • 非常丰富的控件,可以写出非常易用的游戏工具,提高工具使用者体验和效率
  • C++可用宏来控制,避免release游戏将GM工具发布出去了

于是笔者产生了将ImGui集成到EGNX引擎中的想法,本着复用原则,笔者先在github搜索一番,按stars数量排序(搜索优秀开源库的基本方法),点击查看搜索结果,按照常规,自然先使用了 c0iimguix: https://github.com/c0i/imguix,但这个最是基于3.17.1的,而EGNX是基于cocos2d-x-4.0发展而来,因此经过简单修改,笔者使其支持了EGNX,并给作者提了PR: https://github.com/c0i/imguix/pull/32

如果到此为止,也就是简单集成而已,但经过多番查看github相关issues,发现imguix不支持mutli-view-ports,与此同时也通过github了解到imgui官方仓库的docking分支,是支持mutli-viewports的,也就是说ImGui的窗口可以拖出游戏窗口之外,因此笔者找到了这个仓库: https://github.com/Xrysnow/cocos2d-x-imgui,通过简单了解发现,这个貌似也是基于imguix优化的版本,在imguix的基础上基于imgui官方仓库的docking分支,同时master分支主要支持cocos2d-x-4.0,于是笔者经过简单的修改,成功将该版本集成为EGNX的扩展,同时做了如下重点优化:

  • Mac平台Mutli-Viewports拖动时导致游戏界面黑屏,因此禁用(tips: 跑了imgui官方的示例,也是无法拖出主窗口之外的)
  • 整理扩展管理单利类,重命名为: ImGuiEXT
  • 修正概念ImGuiLayer其实仅仅做事件跟踪监测,并无实际渲染功能,因此重构为ImGuiEXTEventTracker并隐藏到扩展本身,不暴露给外部
  • 重构为ImGuiEXT的addRenderLoop/removeRenderLoop接口来管理ImGui的渲染循环
  • 提供非常简单易用的字体管理接口addFont,removeFont,clearFonts
  • 优化ImGui的beginFrame, endFrame时机,使用者可以在addRenderLoop的渲染循环里处理ImGui的控件逻辑来直接安全地添加或删除游戏场景里的对象,有效避免迭代器被破坏
  • 优化ImGuiEXT单利的生命周期管理,准确清理和初始化ImGui Context,避免destroyInstance后,再次ImGuiEXT::getInstacne使用时奔溃
  • DPI缩放支持 API: ImGuiEXT::getInstance()->scaleAllByDPI(1.0);
  • 在扩展内部自己计算需要赋值给ImGui::GetIO()的deltaTime,以避免暂停Director后,ImGui报错
  • 其他代码优化

Tips: 这里有个小点,就是之前版本EGNX或者cocos系列引擎,在Director暂停后会将帧率限制特别低,导致ImGui作为游戏内嵌工具的窗口拖动特别慢,笔者认为完全没必要,因此笔者加了宏来控制,详见:https://github.com/c4games/engine-x/commit/2d5fb7f77d671b3bb0f7ee5a4ded0e4fca2b8178

有了以上优化,EGNX的 ImGuiEXT 才真正达到易用和稳定性的程度,用法如下:

#include "ImGuiEXT/CCImGuiEXT.h"
USING_NS_CC;
USING_NS_CC_EXT;

class GameScene : public Scene {
public:
    void onEnter() override
    {
        Scene::onEnter();
        ImGuiEXT::getInstance()->addRenderLoop("#im01", CC_CALLBACK_0(GameScene::onImGuiDraw, this), this);
    }
    void onExit() override
    {
        ImGuiEXT::getInstance()->removeRenderLoop("#im01");
        Scene::onExit();
    }
    void onImGuiDraw()
    {
        ImGui::Begin("window");
        ImGui::Text("FPS=%.1f", 1.f / ImGui::GetIO().DeltaTime);
        ImGui::End();
    }
}

另外EGNX同时也写了test case,可以直接按照编译步骤跑ImGui的使用用例,效果如下

怎么样,是不是非常简单,以下贴出ImGuiEXTImGui官方链接,赶紧下载体验吧

非常感谢github的前辈们提供的cocos2dx imgui实现版本:

Tips:

  • 本文是以egnx为例, 理论上cocos2d-x-4.0官方版本也是可以直接使用的
  • 以上某些主观描述纯属个人观点,欢迎大神指正讨论

论坛其他相关帖子:

imgui作为编辑器UI,游戏画面在中间,类似unity的方式。楼主有思路么?

切到新的imgui docker branch,拿一个render texture做game界面

例子https://wujiayish.github.io/cocos2d-x-examples/index.html?5

用cocos2dx重写imgui的渲染器/render即可,官方源码有opengl/vulcan/dx的案例。
我有个demo,用filament+imgui的编辑器
222

1赞

您这个代码我看了。我觉得做编辑器应该独立于游戏结构之外的东西。您用scene,add imgui。如果,游戏replace scene。 显示就会有问题了。我现在的思路是,启动游戏,用framebuffer 渲染游戏界面,随后渲染imgui。不过有些问题还没有解决。

请问有例子吗?请问 filament 是什么。

1赞

google 开源的一个渲染引擎

用imgui docker分支,rendertxture
https://github.com/WuJiayiSH/cocos2d-x-imgui-editor