本节主要讲一下如何在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)cocoseditor-support;$(EngineRoot)cocos;$(EngineRoot)cocosplatform;$(EngineRoot)cocosplatformdesktop;$(EngineRoot)externalglfw3includewin32;$(EngineRoot)externalwin32-specificglesincludeOGLES;$(EngineRoot)externalfreetype2includewin32freetype2;$(EngineRoot)externalfreetype2includewin32;$(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
四、其他
然而同这里 http://www.cnblogs.com/GuyaWeiren/p/4600937.html 通过glfw创建一个新的窗口一样,我这里测试最新cocos2dx-3.9版本同样存在内存泄漏。经测试,直接用cocos2dx源码也一样,只要在MFC中用了AppDelegate就存在泄漏。暂无解决办法,希望有同学知道的可以知会一下~~
完整代码地址:https://github.com/mydishes/cocos2dx-Ex/tree/master/MFCView