本节主要讲一下如何在MFC窗口中使用cocos2dx
在做比较复杂的游戏,有时需要通过一些工具来编辑生成关卡或者特效,技能等的配置文件。为了方便配置,需要可以通过修改参数直观得到显示的效果。这就需要将引擎加载到工具中进行效果显示,这里我们将cocos2dx应用到MFC,得到最终效果如下:
一、通过HWND创建cocos2dx窗口View
通过参考 GLViewImpl 及 GLView 创建MFC中可以使用的 CMyEGLView 。在GLView中我们可以看到如下所示,Win32中实际使用的窗口指针就是HWND。
同时,继承GLView时有4个必须重载实现的函数如下:
因此,我们自己实现的 CMyEGLView 需要 接口如下:
class /*CC_DLL*/ CMyEGLView : public cocos2d::GLView{public: static CMyEGLView* createWithRect(const std::string& viewName, Rect size, HWND handle, float frameZoomFactor = 1.0f); bool initWithRect(const std::string& viewName, Rect rect, HWND handle, float frameZoomFactor);/* override functions */ virtual bool isOpenGLReady() override; virtual void end() override; virtual void swapBuffers() override; virtual void setIMEKeyboardState(bool bOpen) override; virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) HWND getWin32Window() { return m_hWnd; }#endif /* (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) */protected: CMyEGLView(); virtual ~CMyEGLView(); bool initGlew(); float _frameZoomFactor; HDC m_hDC; HGLRC m_hRC; HWND m_hWnd; bool _captured;};
由上述代码可以看到,这里多出了一个WindowProc接口,这是用来将MFC窗口的指令传入cocos2dx中并对应转成相应的消息。主要通过参考GLViewImpl 中的回调实现,详细可以参考文章结尾的源码。
同时在initWithRect中通过窗口指针 m_hWnd 取得窗口 m_hDC 并通过SetupPixelFormat中设置如下代码实现窗口对Opengl的支持。
static void SetupPixelFormat(HDC hDC){ int pixelFormat; PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size 1, // version PFD_SUPPORT_OPENGL | // OpenGL window PFD_DRAW_TO_WINDOW | // render to window PFD_DOUBLEBUFFER, // support double-buffering PFD_TYPE_RGBA, // color type 32, // preferred color depth 0, 0, 0, 0, 0, 0, // color bits (ignored) 0, // no alpha buffer 0, // alpha bits (ignored) 0, // no accumulation buffer 0, 0, 0, 0, // accum bits (ignored) 24, // depth buffer 8, // no stencil buffer 0, // no auxiliary buffers PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0, // no layer, visible, damage masks }; pixelFormat = ChoosePixelFormat(hDC, &pfd); SetPixelFormat(hDC, pixelFormat, &pfd);}
其余初始化opengl es等同样直接参考GLViewImpl 中实现。
二、在AppDelegate中创建CMyEGLView
参考Application::run() 实现并将其拆成3部分在AppDelegate中实现,添加如下接口:
// 传入窗口指针并创建 virtual void CreateWnd(HWND hwnd); // 刷新显示 virtual void Run2(); // 窗口大小变化 void Resize(int width, int height); // MFC 消息 LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
1、CreateWnd用于传入MFC窗口指针,同时调用applicationDidFinishLaunching来实现View的创建等;
2、Run2用于原来run中的while循环部分,即执行 director->mainLoop();
3、在析构函数中添加对view释放等操作。
详细可以参考文章结尾的源码。
三、在MFCAPPView中使用AppDelegate
1、首先在cocos2dx项目中添加一个MFC项目,如下图所示:
2、添加MFC项目对cocos2dx的项目引用
右键属性->通用属性->引用->添加新引用->libcocos2d
3、在视图->属性管理器中添加现有的cocos2dx属性表,如下:
右键添加现有属性表,在~/cocos2d/cocos/2d 目录找到对应的属性表进行添加,注意先后顺序。
然后在项目的属性页->C/C++->常规->附加包含目录中添加如下头文件引用目录:
$(EngineRoot)cocos\editor-support;$(EngineRoot)cocos;$(EngineRoot)cocos\platform;$(EngineRoot)cocos\platform\desktop;$(EngineRoot)external\glfw3\include\win32;$(EngineRoot)external\win32-specific\gles\include\OGLES;$(EngineRoot)external\freetype2\include\win32\freetype2;$(EngineRoot)external\freetype2\include\win32\;$(EngineRoot)external
4、然后对应的在MFCApplicationView.h中添加如下:
// 操作public: afx_msg void OnTimer(UINT_PTR nIDEvent); virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); afx_msg void OnSize(UINT nType, int cx, int cy);protected: AppDelegate m_app; bool m_bCreated;
在MFCApplicationView.cpp中添加对应的消息映射
BEGIN_MESSAGE_MAP(CMFCApplicationView, CView) // 标准打印命令 ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CMFCApplicationView::OnFilePrintPreview) ON_WM_CONTEXTMENU() ON_WM_RBUTTONUP() ON_WM_TIMER() ON_WM_SIZE()END_MESSAGE_MAP()
同时实现.h中的三个函数,如下:
void CMFCApplicationView::OnTimer(UINT_PTR nIDEvent){ // TODO: 在此添加消息处理程序代码和/或调用默认值 if (m_bCreated) { m_app.Run2(); }}void CMFCApplicationView::OnSize(UINT nType, int cx, int cy){ CView::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 if (cx != 0 && cy != 0) { if (!m_bCreated) { m_app.CreateWnd(m_hWnd); SetTimer(1, 16, NULL); m_bCreated = true; } m_app.Resize(cx, cy); }}LRESULT CMFCApplicationView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam){ // TODO: 在此添加专用代码和/或调用基类 if (1 == m_app.WindowProc(message, wParam, lParam)) return 1; return CView::WindowProc(message, wParam, lParam);}
到这里,即可以在MFC中正常使用cocos2dx了,同时还可以正常响应点击等消息。
5、编译后发现MFC中定义OS_WINDOWS冲突,在stdafx.h添加如下:
//去除MFC中与cocos2dx冲突的默认定义#ifdef OS_WINDOWS#undef OS_WINDOWS#endif
四、其他
然而同这里 通过glfw创建一个新的窗口一样,我这里测试最新cocos2dx-3.9版本同样存在内存泄漏。经测试,直接用cocos2dx源码也一样,只要在MFC中用了AppDelegate就存在泄漏。暂无解决办法,希望有同学知道的可以知会一下~~
完整代码地址: