Cocos2d-X 2.0嵌入MFC的子窗体的方法

http://blog.csdn.net/honghaier/article/details/8009046

http://blog.csdn.net/akof1314/article/details/8133800

本节所用Cocos2d-x版本:cocos2d-2.0-x-2.0.2

之前讲解了如何将Cocos2d-x 1.0版本嵌入MFC的窗体中的具体方法,应朋友们的要求,将Cocos2d-x 2.0版本嵌入MFC窗体的方法也整理发布。

      首先,我们用VC++在Cocos2d-x的目录里建立了个Unicode字符集MFC对话框程序。这里命名为Cocos2dXEditor。按照HelloWorld工程设置把包含头文件目录,库文件目录,包含库都设置好。并且画好对话框界面

如图:

Cocos2d-X 2.0嵌入MFC的子窗体的方法_第1张图片

    我把界面设计为三部分,左边和右边用来创建对话框面板,至于要具体显示什么根据我们的工具开发需求而定。暂时先不管。而中间放一个Picture控件,做为Cocos2d-x的显示窗口。为了生成相应的窗口控件变量,我们需要将此Picture控件的ID改成自定义的一个ID,这里我们改成IDC_COCOS2DXWIN保存。

    我们画好界面后,选中Picture控件后右键单击,在弹出菜单中找到“添加变量”。为Picture控件生成一个控件变量。这里命名为m_Cocos2dXWin,并点击完成。

Cocos2d-X 2.0嵌入MFC的子窗体的方法_第2张图片

好,现在主对话框类里有了这么一句:

[cpp] view plaincopy

  1. public: 
  2.          CStatic      m_Cocos2dXWin; 

     这个变量是CStatic类型的,它只是一个最简单的CWnd派生类。并不能显示Cocos2d-x。我们需要做点工作来创建一个新的类来替代它完成显示Cocos2d-x的工作。

     在工程右键弹出菜单里找到“添加”一项,在其子菜单中点击“类”。

Cocos2d-X 2.0嵌入MFC的子窗体的方法_第3张图片

在弹出的“添加类”对话框中“MFC”项中的“MFC类”。

Cocos2d-X 2.0嵌入MFC的子窗体的方法_第4张图片

        点击“添加”。这时会弹出“MFC类向导”对话框。我们在类名里输入“CCocos2dXWin”,并选择基类CWnd。然后点击“完成”。

Cocos2d-X 2.0嵌入MFC的子窗体的方法_第5张图片

        向导会为我们的工程自动加入两个文件“Cocos2dXWin.h”和“Cocos2dXWin.cpp”。这才是我们要进行Cocos2d-x显示的窗体类,它的基类是CWnd,与Picture控件有相同的基类。

        打开Cocos2dXWin.h,在CCocos2dXWin类中增加一个public成员函数声明:

[cpp] view plaincopy

  1. //创建Cocos2dX窗口
  2. BOOL        CreateCocos2dXWindow(); 

       我们另外增加一个private变量用来标记窗口是否已经进行了Cocos2d-x的OpenGL窗口创建。

[cpp] view plaincopy

  1. private: 
  2. //是否已经初始化
  3. BOOL                m_bInitCocos2dX; 

       在CPP文件中加入需要用到的头文件:

[cpp] view plaincopy

  1. #include "../Classes/AppDelegate.h"
  2. #include "cocos2d.h"

       下面来手动增加函数定义:

[cpp] view plaincopy

  1. //创建Cocos2dX窗口
  2. BOOL    CCocos2DXWin::CreateCocos2dXWindow() 
  3. //新建一个CRect变量获取窗口的客户区大小
  4.     CRect   tClientRect; 
  5.     GetClientRect(&tClientRect); 
  6. //取得使用的OpenGL视窗
  7.     CCEGLView* eglView = CCEGLView::sharedOpenGLView(); 
  8. //以指定的客户区大小创建视窗,这里我们对setFrameSize增加了参数3以传入当前控件的窗口句柄。
  9.     eglView->setFrameSize(tClientRect.Width(),tClientRect.Height(),GetSafeHwnd()); 
  10. //调用程序的运行函数,增加参数bool型变量控制是否进行消息循环。因为MFC控件本身有自已的消息响应处理。如果不改动的话,这里就会进入死循环。
  11.     cocos2d::CCApplication::sharedApplication()->run(false); 
  12. //这里将变量设置为TRUE
  13.     m_bInitCocos2dX = TRUE; 
  14. return TRUE; 

       我们要修改两处地方。我们先对CCApplication动个小手术,使相应参数能够发挥作用。

       找到CCApplication.cpp中的run函数做以下修改:

[cpp] view plaincopy

  1. [Cocos2d-x相关教程来源于红孩儿的游戏编程之路 CSDN博客地址:http://blog.csdn.net/honghaier] 
  2. int CCApplication::run(bool bMsgLoop) 
  3.     PVRFrameEnableControlWindow(false); 
  4. // Main message loop:
  5.     MSG msg; 
  6.     LARGE_INTEGER nFreq; 
  7.     LARGE_INTEGER nNow; 
  8. //帧定时器取得CPU时钟频率和计数
  9.     QueryPerformanceFrequency(&nFreq); 
  10.     QueryPerformanceCounter(&m_nLast); 
  11. // 调用派生类的程序启动处理函数
  12. if (!applicationDidFinishLaunching()) 
  13.     { 
  14. return 0; 
  15.     } 
  16.       CCEGLView* pMainWnd = CCEGLView::sharedOpenGLView(); 
  17. //手动修改
  18. if(true == bMsgLoop) 
  19.     { 
  20. //窗口居中显示
  21.         mainWnd->centerWindow(); 
  22.         ShowWindow(mainWnd->getHWnd(), SW_SHOW); 
  23. while (1) 
  24.         { 
  25. if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
  26.             { 
  27. // Get current time tick.
  28.                 QueryPerformanceCounter(&nNow); 
  29. //由帧间隔来控制刷新
  30. if (nNow.QuadPart - m_nLast.QuadPart > m_nAnimationInterval.QuadPart) 
  31.                 { 
  32.                     m_nLast.QuadPart = nNow.QuadPart; 
  33.                     CCDirector::sharedDirector()->mainLoop(); 
  34.                 } 
  35. else
  36.                 { 
  37.                     Sleep(0); 
  38.                 } 
  39. continue; 
  40.             } 
  41. //如果收到退出消息,中断消息循环。
  42. if (WM_QUIT == msg.message) 
  43.             { 
  44. // Quit message loop.
  45. break; 
  46.             } 
  47. // 按键消息处理
  48. if (! m_hAccelTable || ! TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg)) 
  49.             { 
  50.                 TranslateMessage(&msg); 
  51.                 DispatchMessage(&msg); 
  52.             } 
  53.         } 
  54. return (int) msg.wParam; 
  55.     } 
  56. return 0; 

          修改.h中函数声明与cpp保持一致,再打开CCEGLView.cpp,找到setFrameSize函数,继续手术:

[cpp] view plaincopy

  1. void CCEGLView::setFrameSize(float width, float height,HWND hWnd) 
  2. //由指定的大小和句柄创建窗体
  3.     Create((LPCTSTR)m_szViewName, (int)width, (int)height,hWnd); 
  4. //调用基类的setFrameSize函初始化整屏幕和分辨率
  5.         CCEGLViewProtocol::setFrameSize(width, height); 

        再找到Create函数:

[cpp] view plaincopy

  1. //创建窗口
  2. bool CCEGLView::Create(LPCTSTR pTitle, int w, int h, HWND hWnd) 
  3. bool bRet = false; 
  4. do
  5.     { 
  6. //如果已经创建了窗体,直接返回,不允许再重复创建。
  7.         CC_BREAK_IF(m_hWnd); 
  8. //在这里做个判断,如果参数中的窗口句柄不为空,则使用参数句柄做为成员变量m_hWnd的值。
  9. if(hWnd) 
  10.         { 
  11.             m_hWnd = hWnd ; 
  12. //新增bool变量m_bIsPopupWin,用于标记是否使用已经创建好的WINDOWS控件窗口句柄做为当前OpenGL视窗的WINDOWS窗口句柄。
  13.             m_bIsPopupWin = false; 
  14.         } 
  15. else
  16.         { 
  17. HINSTANCE hInstance = GetModuleHandle( NULL ); 
  18.             WNDCLASS  wc;       // Windows Class Structure
  19. // Redraw On Size, And Own DC For Window.
  20.             wc.style          = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;   
  21.             wc.lpfnWndProc    = _WindowProc;                    // WndProc Handles Messages
  22.             wc.cbClsExtra     = 0;                              // No Extra Window Data
  23.             wc.cbWndExtra     = 0;                              // No Extra Window Data
  24.             wc.hInstance      = hInstance;                      // Set The Instance
  25.             wc.hIcon          = LoadIcon( NULL, IDI_WINLOGO );  // Load The Default Icon
  26.             wc.hCursor        = LoadCursor( NULL, IDC_ARROW );  // Load The Arrow Pointer
  27.             wc.hbrBackground  = NULL;                           // No Background Required For GL
  28.             wc.lpszMenuName   = NULL;                           // We Don't Want A Menu
  29.             wc.lpszClassName  = kWindowClassName;               // Set The Class Name
  30.             CC_BREAK_IF(! RegisterClass(&wc) && 1410 != GetLastError());         
  31. // center window position
  32.             RECT rcDesktop; 
  33.             GetWindowRect(GetDesktopWindow(), &rcDesktop); 
  34. WCHAR wszBuf[50] = {0}; 
  35.             MultiByteToWideChar(CP_UTF8, 0, m_szViewName, -1, wszBuf, sizeof(wszBuf)); 
  36. // create window
  37.             m_hWnd = CreateWindowEx( 
  38.                 WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, // Extended Style For The Window
  39.                 kWindowClassName,                                   // Class Name
  40.                 wszBuf,                                             // Window Title
  41.                 WS_CAPTION | WS_POPUPWINDOW | WS_MINIMIZEBOX,       // Defined Window Style
  42.                 0, 0,                                               // Window Position
  43.                 0,                                                  // Window Width
  44.                 0,                                                  // Window Height
  45.                 NULL,                                               // No Parent Window
  46.                 NULL,                                               // No Menu
  47.                 hInstance,                                          // Instance
  48.                 NULL ); 
  49.         } 
  50. //判断窗口句柄有效
  51. CC_BREAK_IF(! m_hWnd); 
  52. //调整窗口大小
  53.         resize(w, h); 
  54. //初始化OpenGL
  55.                  bRet = initGL(); 
  56.              CC_BREAK_IF(!bRet); 
  57.                  s_pMainWindow = this; 
  58. bRet = true; 
  59.     } while (0); 
  60. return bRet; 

        修改.h中函数声明与cpp保持一致。这样我们就完成了对于创建窗口函数的修改。但是因为屏蔽了原窗口的创建,所以也同时屏蔽了Cocos2d-x对于窗口消息的处理。我们在类视图中找到CCocos2dXWin,在右键弹出菜单中点击“属性”。打开类属性编辑框。

Cocos2d-X 2.0嵌入MFC的子窗体的方法_第6张图片

      在WindowProc一栏中增加函数WindorProc,完成后进入CCocos2dXWin的WindorProc函数,因为我们在CCEGLView的Create函数中可以找到在注册窗口类时,其设定的窗口消息处理回调函数是WindowProc.而其实例对象是单件。故可以这样修改:

[cpp] view plaincopy

  1. LRESULT CCocos2DXWin::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  2. // 这里我们先判断一下是否初始化完成Cocos2dX再进行消息处理
  3. if(m_bInitCocos2dX) 
  4.     { 
  5.         CCEGLView::sharedOpenGLView()->WindowProc(message, wParam, lParam); 
  6.     } 
  7. return CWnd::WindowProc(message, wParam, lParam); 

       这样Cocos2dXWin所实例化的窗口就可以接收到鼠标等对于窗口的消息了。但是!我们屏幕了Cocos2d-x的消息循环,而Cocos2d-x的渲染处理函数是在消息循环中调用的。我们就算现在运行程序,也看不到帅气的小怪物。所以我们必须想办法实时的调用Cocos2d-x的渲染处理函数。对于工具来说,我们并不需要考虑太高的FPS刷新帧数,所以我们只需要使用一个定时器,并在定时触发函数中进行Cocos2d-x的渲染处理函数的调用就可以了。

       在CCocos2DXWin::CreateCocos2dXWindow()函数尾部加入一句:

        SetTimer(1,1,NULL);

       加入一个ID为1的定时器,设置它每1毫秒响应一次,其处理函数为默认,则使用CCocos2DXWin的WINDOWS消息处理函数对于WM_TIMER进行响应就可以了。

       按之前增加WindorProc函数的方式找到CCocos2DXWin的消息WM_TIMER一项,增加函数OnTimer.如图:

Cocos2d-X 2.0嵌入MFC的子窗体的方法_第7张图片

         在其生成的函数OnTimer中我们新写一个函数调用,则每次定时响应调用:

[cpp] view plaincopy

  1. void CCocos2DXWin::OnTimer(UINT_PTR nIDEvent) 
  2. //我们写一个renderWorld函数代表Cocos2d-x的世界渲染
  3.     cocos2d::CCApplication::sharedApplication()->renderWorld(); 
  4.     CWnd::OnTimer(nIDEvent); 

          我们打开CCApplication.h,为CCApplication类增加一个public的renderWorld函数。

[cpp] view plaincopy

  1. //帧循环调用渲染
  2. bool    renderWorld(); 

          在cpp中我们将消息循环中的相关处理移入进来

[cpp] view plaincopy

  1. bool CCApplication::renderWorld() 
  2. {    
  3.     LARGE_INTEGER nNow; 
  4. // Get current time tick.
  5.     QueryPerformanceCounter(&nNow); 
  6. // If it's the time to draw next frame, draw it, else sleep a while.
  7. if (nNow.QuadPart - m_nLast.QuadPart > m_nAnimationInterval.QuadPart) 
  8.     { 
  9.         m_nLast.QuadPart = nNow.QuadPart; 
  10.         CCDirector::sharedDirector()->mainLoop(); 
  11. return true; 
  12.     } 
  13. return false; 

OK,这样我们就可以在外部来调用Cocos2d-x的显示设备进行渲染处理了。当然,我们也不能忘了在CCocos2dXWin窗口销毁时把定时器资源进行一下释放。找到类消息WM_DESTROY新增函数OnDestroy。

Cocos2d-X 2.0嵌入MFC的子窗体的方法_第8张图片

[cpp] view plaincopy

  1. void CCocos2DXWin::OnDestroy() 
  2. //在Cocos2d-x的引擎文件CCEGLView_win32.cpp中CCEGLView::release()会再次发送调用DestroyWindow,所以这里用变量m_bInitCocos2dX做下判断,避免二次销毁
  3. if(TRUE == m_bInitCocos2dX) 
  4.     { 
  5. //退出将m_bInitCocos2dX设为FALSE
  6.         m_bInitCocos2dX = FALSE; 
  7. //释放定时器资源
  8.         KillTimer(1); 
  9.         CWnd::OnDestroy(); 
  10.     } 

          我们知道在Cocos2d-x程序退出时先后响应WM_CLOSE和WM_DESTROY。在CCEGLView::WindowProc可以看到

[cpp] view plaincopy

  1. case WM_CLOSE: 
  2.     CCDirector::sharedDirector()->end(); 
  3. break; 
  4. case WM_DESTROY: 
  5.                destroyGL(); 
  6.     PostQuitMessage(0); 
  7. break; 

         而CCDirector的end函数并不是立即执行停止,他设置成员变量m_bPurgeDirecotorInNextLoop为true,并在下一帧mainLoop循环时调用purgeDirector()函数进行显示设备和场景的最终释放。所以我们要想在窗口退出时释放Cocos2d-x显示设备和场景,必须做一下相关处理。理解了这一点。其实就很简单了。

          只需要在CCocos2DXWin::OnDestroy()中增加两句代码即可:

[cpp] view plaincopy

  1. void CCocos2DXWin::OnDestroy() 
  2.     … 
  3.     KillTimer(1); 
  4. //调用显示设备单件实例对象的end函数
  5.     CCDirector::sharedDirector()->end(); 
  6. //处理一次下一帧,必须调用.
  7.     CCDirector::sharedDirector()->mainLoop(); 
  8.     CWnd::OnDestroy(); 
  9.     } 

OK,CCocos2DXWin类基本完成。现在在Cocos2dXEditorDlg.h中将

CStatic            m_Cocos2dXWin;

改为

CCocos2DXWin       m_Cocos2dXWin;

       并将CCocos2DXWin的头文件包含进来就可以顺利编译成功。在控件初始化(比如OnInitDialog函数)中调用一下m_Cocos2dXWin.CreateMainCoco2dWindow()。此时我们就算完成了将Cocos2d-x嵌入MFC的CWnd控件的过程。不过,您需要在窗口大小变化时对这个控件重设位置及大小以及投影矩阵。

[cpp] view plaincopy

  1. void CCocos2DXWin::OnSize(UINT nType, int cx, int cy) 
  2.     CWnd::OnSize(nType, cx, cy); 
  3. // TODO: 在此处添加消息处理程序代码
  4. if(TRUE == m_bInitCocos2dX) 
  5.     { 
  6.         CRect   tClientRect; 
  7.         GetClientRect(&tClientRect); 
  8. //重新设置窗口大小及投影矩阵
  9.         CCEGLView::sharedOpenGLView()->resize(tClientRect.Width(),tClientRect.Height()); 
  10.         CCDirector::sharedDirector()->reshapeProjection(CCSizeMake(tClientRect.Width(),tClientRect.Height())); 
  11.         } 
  12. } 

做下总结:

与1.0相比,作者删除了对于过多的目标平台的区分。(1)只保留了WINDOWS,ANDROID,IOS三个目标平台,(2)各类更清晰紧凑了,CCEGLView与CCApplication之间的耦合性大大降低。(3)将引用改成了指针,这点需要多留心。

最后运行一下看下成果吧。

       下面是我我现在做的编辑器的截图:

Cocos2d-X 2.0嵌入MFC的子窗体的方法_第9张图片

 

 

===========================================================================================================================================================================================================

需要Cocos2d-x运行在MFC中,可能是因为需要直接看配置的效果,也可能是因为打算制作工具。参考网上的一篇文章,实践出本文。

1.打开cocos2d-win32.vc2008.sln,右键新建项目;
2.选择MFC应用程序,工程名为Cocos2dXEdit,路径默认;
3.在下一步中选择“基于对话框”,其余默认;
4.按如下图步好局:
Cocos2d-X 2.0嵌入MFC的子窗体的方法_第10张图片
5.右键工程属性,开始如下设置:

1
2
3
4
5
6
7

General→Output Directory:$(SolutionDir)$(ConfigurationName).win32
Debugging→Working Directory:$(ProjectDir)\Resources
C/C++→General→Additional Include Directories:"$(SolutionDir)cocos2dx";"$(SolutionDir)cocos2dx\include";"$(SolutionDir)cocos2dx\kazmath\include";"$(SolutionDir)cocos2dx\platform\win32";"$(SolutionDir)cocos2dx\platform\third_party\win32";"$(SolutionDir)cocos2dx\platform\third_party\win32\OGLES";"$(SolutionDir)";"$(SolutionDir)chipmunk\include\chipmunk";"$(SolutionDir)CocosDenshion\include";
C/C++→Preprocessor→Preprocessor Definitions:WIN32;_DEBUG;_WINDOWS;_USE_MATH_DEFINES;GL_GLEXT_PROTOTYPES;COCOS2D_DEBUG=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS
(Release版)WIN32;NDEBUG;_WINDOWS;_USE_MATH_DEFINES;GL_GLEXT_PROTOTYPES;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS
Linker→General→Additional Library Directories:$(OutDir)
Linker→Input→Additional Dependencies:libcocos2d.lib libCocosDenshion.lib opengl32.lib glew32.lib libBox2d.lib libchipmunk.lib libcurl_imp.lib

6.拷贝HelloWorld示例里的“Classes”、“Resources”文件夹到当前工程目录下,把“Classes”里的文件加到工程中,对“HelloWorldScene.cpp”、“AppDelegate.cpp”文件增加头文件定义“#include "stdafx.h"”,或者去掉这两个文件的预编译选项;

7.在“AppDelegate.h”文件中,添加自定义函数:

int runMy();

在“AppDelegate.cpp”文件中,添加如下代码:

static void PVRFrameEnableControlWindow(bool bEnable);
int AppDelegate::runMy()
{
    PVRFrameEnableControlWindow(false);
// Main message loop:
    MSG msg;
    LARGE_INTEGER nFreq;
    LARGE_INTEGER nLast;
    LARGE_INTEGER nNow;
    QueryPerformanceFrequency(&nFreq);
    QueryPerformanceCounter(&nLast);
// Initialize instance and cocos2d.
if (!applicationDidFinishLaunching())
    {
return 0;
    }
    CCEGLView& mainWnd = CCEGLView::sharedOpenGLView();
//mainWnd.centerWindow();   // 为了把这句给屏蔽掉
    ShowWindow(mainWnd.getHWnd(), SW_SHOW);
while (1)
    {
if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
// Get current time tick.
            QueryPerformanceCounter(&nNow);
// If it's the time to draw next frame, draw it, else sleep a while.
if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)
            {
                nLast.QuadPart = nNow.QuadPart;
                CCDirector::sharedDirector()->mainLoop();
            }
else
            {
                Sleep(0);
            }
continue;
        }
if (WM_QUIT == msg.message)
        {
// Quit message loop.
break;
        }
// Deal with windows message.
if (! m_hAccelTable || ! TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
return (int) msg.wParam;
}
static void PVRFrameEnableControlWindow(bool bEnable)
{
    HKEY hKey = 0;
// Open PVRFrame control key, if not exist create it.
if(ERROR_SUCCESS != RegCreateKeyExW(HKEY_CURRENT_USER,
        L"Software\\Imagination Technologies\\PVRVFRame\\STARTUP\\",0,0,
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,0,
        &hKey,
NULL))
    {
return;
    }
const WCHAR* wszValue = L"hide_gui";
const WCHAR* wszNewData = (bEnable) ? L"NO" : L"YES";
    WCHAR wszOldData[256] = {0};
    DWORD   dwSize = sizeof(wszOldData);
    LSTATUS status = RegQueryValueExW(hKey, wszValue, 0, NULL, (LPBYTE)wszOldData, &dwSize);
if (ERROR_FILE_NOT_FOUND == status              // the key not exist
        || (ERROR_SUCCESS == status                 // or the hide_gui value is exist
        && 0 != wcscmp(wszNewData, wszOldData)))    // but new data and old data not equal
    {
        dwSize = sizeof(WCHAR) * (wcslen(wszNewData) + 1);
        RegSetValueEx(hKey, wszValue, 0, REG_SZ, (const BYTE *)wszNewData, dwSize);
    }
    RegCloseKey(hKey);
}

8.在“HelloWorldScene.h”文件添加如下:

enum ChildTag{
    kTagMainLayer,
};

在“HelloWorldScene.cpp”文件修改为如下:

CCScene* HelloWorld::scene()
{
// 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
    HelloWorld *layer = HelloWorld::create();
// add layer as a child to scene
    scene->addChild(layer, 0, kTagMainLayer);   //在这里修改
// return the scene
return scene;
}

9.从“...\tests\Resources\Images”文件夹中,拷贝“grossini.png”图片到工程的“Resources”文件夹;
10.在“Cocos2dXEditDlg.cpp”文件中,添加如下代码:

#include "Classes/AppDelegate.h"
#include "Classes/HelloWorldScene.h"
#include "CCEGLView.h"
USING_NS_CC;
// “Open Cocos2d-x”按钮事件
void CCocos2dXEditDlg::OnBnClickedButton1()
{
    GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
    AppDelegate app;
    CCEGLView& eglView = CCEGLView::sharedOpenGLView();
    eglView.setViewName("Hello World");
    eglView.setFrameSize(480, 320);
    ::SetParent(eglView.getHWnd(), this->GetSafeHwnd());
    SetWindowLong(eglView.getHWnd(), GWL_STYLE, GetWindowLong(eglView.getHWnd(), GWL_STYLE) & ~WS_CAPTION);
// IDC_STATIC_X为图片控件ID
    CRect rc;
    GetDlgItem(IDC_STATIC_X)->GetWindowRect(&rc);
    ScreenToClient(&rc);
    ::SetWindowPos(eglView.getHWnd(), HWND_TOP, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOCOPYBITS | SWP_HIDEWINDOW);
    app.runMy();
// 之后的阻塞
}
// “Create Sprite”按钮事件
void CCocos2dXEditDlg::OnBnClickedButton2()
{
    CCScene* pScene = CCDirector::sharedDirector()->getRunningScene();
    HelloWorld* pLayer = (HelloWorld*)pScene->getChildByTag(kTagMainLayer);
if (!pLayer)
    {
return;
    }
    CCSize sz = CCDirector::sharedDirector()->getWinSize();
    CCSprite* pSprite = CCSprite::create("grossini.png");
    pSprite->setPosition(ccp(rand() % (int)sz.width, rand() % (int)sz.height));
    pLayer->addChild(pSprite);
}
// “Exit”按钮事件
void CCocos2dXEditDlg::OnBnClickedCancel()
{
if (!GetDlgItem(IDC_BUTTON1)->IsWindowEnabled())
    {
        CCDirector::sharedDirector()->end();
        CCDirector::sharedDirector()->mainLoop();
    }
    OnCancel();
}

11.编译运行,如下图所示:
Cocos2d-X 2.0嵌入MFC的子窗体的方法_第11张图片
Cocos2d-X 2.0嵌入MFC的子窗体的方法_第12张图片
注意:使用本文方法,在关闭MFC窗体后,会出现内存泄露,但也只在关闭的时候才出现,暂时未找到解决的方法。参考文章为《Cocos2d-X 2.0嵌入MFC的子窗体的方法(1.0姐妹篇)》,但是方法有点不同,本文不改动源码,直接把运行Cocos2d-x的窗体附加在对话框上,缺点是不能跟随对话框一起创建。

你可能感兴趣的:(Cocos2d-X 2.0嵌入MFC的子窗体的方法)