Cocos2d-X 2.2嵌入MFC的子窗口

1.在cocos2dx目录下创建基于对话框的MFC工程,对话框中间放一个Picture控件

2.添加cocos2dx的相关头文件包含路径、库包含路径和依赖项,可以参考其他cocos工程设置

3.选中Picture控件后右键单击,在弹出菜单中找到“添加变量”。为Picture控件生成一个控件变量。这里命名为m_cocosWin,并点击完成

4.右击工程添加MFC类,类名里输入“CCocos2dXWin”,并选择基类CWnd。把上面的m_cocosWin变量类型改为CCocoWin 然后点击“完成”并做如下修改。

 4.1头文件添加变量和函数

    //是否已经初始化
    
    BOOL                m_bInitCocos2dX;
    //创建Cocos2dX窗口
    BOOL        CreateCocos2dXWindow();

4.2 cpp添加COCOS的头文件,并加入一个全局变量

#include "AppDelegate.h"
#include "cocos2d.h"

USING_NS_CC;

AppDelegate CocoApp;

4.3函数实现

//创建Cocos2dX窗口
BOOL CCocoWin::CreateCocos2dXWindow()
{
    //新建一个CRect变量获取窗口的客户区大小
    CRect    tClientRect;
    GetClientRect(&tClientRect);
    //取得使用的OpenGL视窗
    CCEGLView* eglView = CCEGLView::sharedOpenGLView(false,GetSafeHwnd());
    //指定客户区大小。
    eglView->setFrameSize(tClientRect.Width(),tClientRect.Height());
    //调用程序的运行函数,增加参数bool型变量控制是否进行消息循环。因为MFC控件本身有自已的消息响应处理。如果不改动的话,这里就会进入死循环。
    cocos2d::CCApplication::sharedApplication()->run();
    //这里将变量设置为TRUE
    m_bInitCocos2dX = TRUE;

    SetTimer(1,15,NULL);

    return TRUE;
}

 4.4在CCocoToolDlg的OnInitDialog()方法中调用 CreateCocos2dXWindow()

m_cocosWin.CreateCocos2dXWindow();

5.利用类视图为CCocoWin添加如下方法

代码实现如下:

void CCocoWin::OnTimer(UINT_PTR nIDEvent)
{
    //我们写一个renderWorld函数代表Cocos2d-x的世界渲染  
    cocos2d::CCApplication::sharedApplication()->renderWorld();  
    CWnd::OnTimer(nIDEvent);  
}


void CCocoWin::OnDestroy()
{
    //在Cocos2d-x的引擎文件CCEGLView_win32.cpp中CCEGLView::release()会再次发送调用DestroyWindow,所以这里用变量m_bInitCocos2dX做下判断,避免二次销毁  
    if(TRUE == m_bInitCocos2dX)  
    {  
        //退出将m_bInitCocos2dX设为FALSE  
        m_bInitCocos2dX = FALSE;  
        //释放定时器资源  
        KillTimer(1);  
        //调用显示设备单件实例对象的end函数  
        CCDirector::sharedDirector()->end();  
        //处理一次下一帧,必须调用.  
        CCDirector::sharedDirector()->mainLoop();  
        CWnd::OnDestroy();  
    }  
}


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

    }
}

6.CCEGLView做如下修改

 头文件

    virtual bool Create(bool bCreateWin=true,HWND hWnd=NULL);
public:
    bool m_bIsSelfCreWin;//是否cocos自己创建了窗口

static CCEGLView* sharedOpenGLView(bool bCreateWin=true,HWND hWnd=NULL);//bCreateWin是否自己创建窗口,hWnd已有的MFC窗口句柄

cpp

void CCEGLView::centerWindow()
{
    if (! m_hWnd||!m_bIsSelfCreWin)
    {
        return;
    }
....

}


bool CCEGLView::Create(bool bCreateWin,HWND hWnd)
{
    bool bRet = false;
    do
    {
        CC_BREAK_IF(m_hWnd);

        m_bIsSelfCreWin=bCreateWin;

        if (bCreateWin)
        {

            HINSTANCE hInstance = GetModuleHandle( NULL );
            WNDCLASS  wc;        // Windows Class Structure

            // Redraw On Size, And Own DC For Window.
            wc.style          = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
            wc.lpfnWndProc    = _WindowProc;                    // WndProc Handles Messages
            wc.cbClsExtra     = 0;                              // No Extra Window Data
            wc.cbWndExtra     = 0;                                // No Extra Window Data
            wc.hInstance      = hInstance;                        // Set The Instance
            wc.hIcon          = LoadIcon( NULL, IDI_WINLOGO );    // Load The Default Icon
            wc.hCursor        = LoadCursor( NULL, IDC_ARROW );    // Load The Arrow Pointer
            wc.hbrBackground  = NULL;                           // No Background Required For GL
            wc.lpszMenuName   = m_menu;                         //
            wc.lpszClassName  = kWindowClassName;               // Set The Class Name

            CC_BREAK_IF(! RegisterClass(&wc) && 1410 != GetLastError());

            // center window position
            RECT rcDesktop;
            GetWindowRect(GetDesktopWindow(), &rcDesktop);

            WCHAR wszBuf[50] = {0};
            MultiByteToWideChar(CP_UTF8, 0, m_szViewName, -1, wszBuf, sizeof(wszBuf));

            // create window
            m_hWnd = CreateWindowEx(
                WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,    // Extended Style For The Window
                kWindowClassName,                                    // Class Name
                wszBuf,                                                // Window Title
                WS_CAPTION | WS_POPUPWINDOW | WS_MINIMIZEBOX,        // Defined Window Style
                0, 0,                                                // Window Position
                //TODO: Initializing width with a large value to avoid getting a wrong client area by 'GetClientRect' function.
                1000,                                               // Window Width
                1000,                                               // Window Height
                NULL,                                                // No Parent Window
                NULL,                                                // No Menu
                hInstance,                                            // Instance
                NULL );

            
        }else
        {
            m_hWnd=hWnd;
        }

        CC_BREAK_IF(! m_hWnd);

        bRet = initGL();
        if(!bRet) destroyGL();
        CC_BREAK_IF(!bRet);

        s_pMainWindow = this;
        bRet = true;
    } while (0);

#if(_MSC_VER >= 1600)
    m_bSupportTouch = CheckTouchSupport();
    if(m_bSupportTouch)
    {
        m_bSupportTouch = (s_pfRegisterTouchWindowFunction(m_hWnd, 0) != 0);
    }
#endif /* #if(_MSC_VER >= 1600) */

    return bRet;
}



CCEGLView* CCEGLView::sharedOpenGLView(bool bCreateWin,HWND hWnd)
{
  
    if (s_pEglView == NULL)
    {
        s_pEglView = new CCEGLView();
        if(!s_pEglView->Create(bCreateWin,hWnd))
        {
            delete s_pEglView;
            s_pEglView = NULL;
        }
    }

    return s_pEglView;
}

7.CCEGLView做如下修改

头文件添加方法

    //帧循环调用渲染  
    virtual bool renderWorld(); 

cpp

bool CCApplication::renderWorld()
{
    static LARGE_INTEGER nFreq;
    static LARGE_INTEGER nLast;
    static LARGE_INTEGER nNow;
    static bool sbinit=true;

    //只执行一次
    if (sbinit)
    {
        QueryPerformanceFrequency(&nFreq);
        QueryPerformanceCounter(&nLast);
        sbinit=false;
    }    
    // 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();

        return true;
    }


    return false;
    
}
int CCApplication::run()
{
    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* pMainWnd = CCEGLView::sharedOpenGLView();
    //pMainWnd->centerWindow();
    ShowWindow(pMainWnd->getHWnd(), SW_SHOW);

    //cocos自己创建的窗口才要循环处理消息
    bool bloop=CCEGLView::sharedOpenGLView()->m_bIsSelfCreWin;
    if (bloop)
    {
        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;
    }


    return 0;
}

8.新建个Classes文件夹,并把AppDelegate两个文件复制过去,在VS中右击包含到工程里

 9.把工程的工作目录指向Resources文件夹,可以是以前的COCOS工程的Resources目录

如果出现类似 error LNK2005: "void * __cdecl operator new(unsigned int)的错误,参考

http://m.blog.csdn.net/blog/dotphoenix/13511863

运行效果:

具体修改的思路不做详细说明,具体请参考

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

原文地址:https://www.cnblogs.com/gamesky/p/3668223.html