cocos2dx - 在MFC中使用cocos2dx

 本节主要讲一下如何在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