本節主要講一下如何在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
四、其他
然而同這里 http://www.cnblogs.com/GuyaWeiren/p/4600937.html 通過glfw創建一個新的窗口一樣,我這里測試最新cocos2dx-3.9版本同樣存在內存泄漏。經測試,直接用cocos2dx源碼也一樣,只要在MFC中用了AppDelegate就存在泄漏。暫無解決辦法,希望有同學知道的可以知會一下~~
完整代碼地址:https://github.com/mydishes/cocos2dx-Ex/tree/master/MFCView