关于windows下制作cocos2d-x的工具用到的最多的就是MFC,相关的MFC嵌入cocos2d-x的文章也非常多,不过主要是来用的cocos2d-x 2.x的版本,而且有个问题是所见过的解决方案都是用glfw做一个子窗口然后挂在父窗口上,就是用的::setParent()
这个方法。考虑到这个方法在表现效果以及用法上都有局限,所以想说下关于在Single Document上用OpenGL渲染。好处就是表现上会有很大的提升,在窗口放大缩小的时候也有很好的表现。同时也把cocos2d-x的版本提升到3.x,目前最高版本是3.7,但是我做这个工具的时候还是3.2的时候,所以这里就用的3.2,不过想来差别应该不会大。
具体效果如图所示:
创建新的GLView
在cocos2d-x 3.x中glview都是通过GLFW来处理事件,以及创建windows窗口的,而在2.x中是直接通过windows api CreateWindow()
的,然后设置事件循环处理事件。所以可以仿造2.x的这种方试来创建glview.而其中最重要的东西就是窗口句柄
,通过传递窗口句柄,初始化openGL,然后得到渲染区域。所以继承了CCGLView.得到MFCGLView ,其中最关建的初始化过程如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41//MFCGLView.h
#ifndef __MFC_GLVIEW__H_
#define __MFC_GLVIEW__H_
#include "cocos2d.h"
#include "cocos-ext.h"
#include "CCGLView.h"
NS_CC_BEGIN
class MFCGLView : public GLView
{
public:
//创建MFCGLView
static MFCGLView* create(HWND hWnd);
//构造析构函数
MFCGLView(void);
virtual ~MFCGLView(void);
//自定义GLView必须重写的函数
virtual bool isOpenGLReady();
virtual void end();
virtual void swapBuffers();
virtual void setFrameSize(float width, float height);
virtual void setIMEKeyboardState(bool bOpen);
//初始化GLView
virtual bool init(HWND hWnd);
//窗口消息处理
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
private:
//初始化OpenGL
bool InitGL();
//释放OpenGL
void ReleaseGL();
HWND m_hWnd; //View对应的窗口句柄
HDC m_hDC; //窗口绘图设备
HGLRC m_hRC; //OpenGL渲染环境
bool m_bCaptured; //是否捕捉鼠标
float m_fFrameZoomFactor; //帧缩放比例
};
NS_CC_END
#endif // !__MFC_GLVIEW__H_
1 | bool MFCGLView::InitGL() |
新的AppDelegate
Appdelegate和原来的没有太多的区别,替换原来的CCGLView,建立循环,还有一些事件的支持,比如MFC窗口大小变化的时候的事件OnSize()
,具体如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52void AppDelegate::init(HWND uWind, int32_t nWidth, int32_t nHeight)
{
m_uWnd = uWind;
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if(!glview) {
glview = MFCGLView::create(uWind);
director->setOpenGLView(glview);
}
if (!applicationDidFinishLaunching())
{
return;
}
cocosInited = true;
}
int AppDelegate::run()
{
if (!m_uWnd)
return Application::run();
else
{
if (cocosInited)
Director::getInstance()->mainLoop();
return 1;
}
}
void AppDelegate::onSize(int nWidth, int nHeight)
{
auto glview = Director::getInstance()->getOpenGLView();
if (glview)
{
if (cocosInited)
{
glview->setFrameSize(nWidth, nHeight);
}
}
}
void AppDelegate::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
auto glview = (MFCGLView*)Director::getInstance()->getOpenGLView();
if (glview)
{
if (cocosInited)
{
glview->WindowProc(message, wParam, lParam);
}
}
}
接入到MFC中
最后关键一步就是接入到MFC中,创建一个新的单文档的MFC程序,然后在对应的视图入口(OnInitialUpdate()函数
)处加入一个AppDelegate,然后取得文档区域的句柄,然后新建一个timer用于整个cocos2dx的循环,根据帧率的需要设置调用频率,以及接入事件。例如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34void CsceneEditorView::OnInitialUpdate()
{
CView::OnInitialUpdate();
RECT rc;
::GetClientRect(m_hWnd, &rc);
m_app.init(m_hWnd, rc.right - rc.left, rc.bottom - rc.top);
SetTimer(1, 15, NULL);
// TODO: 在此添加专用代码和/或调用基类
}
void CsceneEditorView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_app.run();
CView::OnTimer(nIDEvent);
}
void CsceneEditorView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
m_app.onSize(cx, cy);
// TODO: 在此处添加消息处理程序代码
}
LRESULT CsceneEditorView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: 在此添加专用代码和/或调用基类
m_app.WindowProc(message, wParam, lParam);
return CView::WindowProc(message, wParam, lParam);
}
这样整个程序就能跑起来,然后可以后续建立更多的通用工具,例如cocos中的控件选中框什么的。以及CString到string的转换工具,这些都会在工具中经常用到。另外如果再有点想法把Lua接进去也是可以的。还有多文档的话也可以,不过要用到多视口。原理也差不多。
再来一张图看关闭一些Dock后,文档区域就会变大,这样就会显得比较高大上了。
补上github地址:
https://github.com/enhhh/cocos2dx-MFC