Cocos2dx集成于windows桌面窗口程序的步骤
2D游戏需要做编辑器,而编辑器总是希望可以复用游戏中的逻辑来运行场景试看效果。
对于cocos2dx开发的程序,这个需求可以描述为:
实现一种方法,在桌面窗口程序中的某个控件上显示cocos2dx的场景,而其他部分保持该操作系统原生ui的功能。
初级版v1.0
这里以windows桌面程序为例,描述如何实现这一点,cocos2dx版本为2.2.5
代码用qt实现,但是没有用到太多qt的东西,windows api通用。
1 创建工程。这里我们依然使用cocos2dx提供的工程生成器创建工程,以得到完美的cocos2dx+box2d的环境。
2 将qt环境引入工程。将qt的include目录和lib目录加到项目设置中的c++目录中,然后加上qt的对应lib。
3 在某个widget上显示qt场景。
这一段比较关键,首先我们的代码应该以qt为主框架,因此删除main函数中CCEGLView初始化部分
//eglView->setViewName("test");
//eglView->setFrameSize(480, 320);
注意必须保留appdelegate,因为cocos2dx运行需要有这个。
接着创建qapp:
QApplication qapp(count, NULL);
在最后,我们在main函数调用
CCApplication::sharedApplication()->run();
而不是调用qt的主循环,因为这个run里还要执行一些cocos2dx的初始化方法。而qt主循环不调用则不影响。
然后我们得修改cocos2dx源代码了,首先修改CCEGLView,增加一个方法CreateByHWND,里面基本复制Create,唯独创建窗口一块删除,直接用参数提供的hWND赋值。
然后增加一个静态方法sharedOpenGLViewCreateByHWND,里面基本复制sharedOpenGLView,只是不调用create,调用我们刚才写的CreateByHWND。
接着就可以开始我们的外部调用了。
首先获得目标widget的winId,这个过程将widget转化成了native。然后将获得的winId(其实就是hWnd)传入 sharedOpenGLViewCreateByHWND,创建出Cocosdx的绘图表面EGLView。
为了得到连续的刷新,定义一个定时器,每次时间触发代码:
CCDirector::sharedDirector()->drawScene();
遇到的问题:
1 显示一个大黑框,这是因为没有设置frameSize,在定位的时候,getVisibleSize全部返回了0,0。这里我们需要在创建完EGLView之后调用一句:
eglView->setFrameSize(w->size().width(), w->size().height());
把widget的size设上去。
2 游戏画面不占全部widget,有偏移。这是因为setFrameSize调用了centerWindow,centerWindow会根据屏幕来定位到中间,对此我们需要把centerwindow注释不执行。
4 实现事件传向cocos2Dx
由于我们自己创建了窗体,因此没有使用cocos2dx的WndProc,解决方案是在CCApplication的主循环中处理消息的部分加上:
TranslateMessage(&msg);
DispatchMessage(&msg);
CCEGLView::sharedOpenGLView()->WindowProc(msg.message, msg.wParam, msg.lParam); //加上此句
进化版version 2.0
之前的版本 对cocos2dx改动太大,不好集成。hack代码的行为,还是越少越好吧,又想出了一个新改法,尽量减少对cocos2dx代码的修改:
1 写一个新的继承自CCEGLView的类,名为CCEGLViewForHWND。
头文件如下:
#pragma once
#include "CCEGLView.h"
namespace cocos2d
{
class CCEGLViewForHWND : public CCEGLView
{
public:
CCEGLViewForHWND(HWND);
~CCEGLViewForHWND();
void centerWindow();
void setCurrent();
static LRESULT HWNDProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
protected:
bool CreateWithHWND(HWND hWnd);
WNDPROC wndProc;
static CCEGLViewForHWND* s_current;
};
}
源文件如下:
#include "CEGLViewForHWND.h"
#include "CCDirector.h"
namespace cocos2d
{ CCEGLViewForHWND* CCEGLViewForHWND::s_current = NULL;
CCEGLViewForHWND::CCEGLViewForHWND(HWND hWnd)
{
CreateWithHWND(hWnd);
} LRESULT CCEGLViewForHWND::HWNDProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CCEGLViewForHWND* This = (CCEGLViewForHWND*)GetWindowLong(hWnd, GWL_USERDATA);
if (This != NULL && This == s_current)
{
LRESULT res = CCEGLView::sharedOpenGLView()->WindowProc(msg, wParam, lParam);
if (msg == WM_DESTROY)
{
CCDirector::sharedDirector()->end();
}
if (This->wndProc)
{
return This->wndProc(hWnd, msg, wParam, lParam);
}
else
{
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
else
{
return DefWindowProc(hWnd, msg, wParam, lParam);
}
} CCEGLViewForHWND::~CCEGLViewForHWND()
{
} void CCEGLViewForHWND::setCurrent()
{
RegisterView(this);
RECT rect;
GetClientRect(m_hWnd, &rect);
setFrameSize(rect.right - rect.left, rect.bottom - rect.top);
s_current = this;
wglMakeCurrent(m_hDC, m_hRC);
} bool CCEGLViewForHWND::CreateWithHWND(HWND hWnd)
{
m_hWnd = hWnd;
bool bRet = false;
do
{
CC_BREAK_IF(!m_hWnd); bRet = initGL();
if (s_current != NULL)
{
wglMakeCurrent(s_current->m_hDC, s_current->m_hRC);
}
bRet = true;
wndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
SetWindowLong(hWnd, GWL_WNDPROC, (long)&CCEGLViewForHWND::HWNDProc);
SetWindowLong(hWnd, GWL_USERDATA, (long)this);
} while ();
SetupTouch();
return bRet;
} void CCEGLViewForHWND::centerWindow()
{
return;
}
}
这个类完成的作用是,封装将已有HWND作为渲染目标的功能。
2 写一个新的继承自qwidget的类QtCocosWidget
头文件如下:
#pragma once
#include "cocos2d.h"
#include <QtWidgets\qwidget.h> namespace cocos2d
{
class CCEGLViewForHWND;
}
class QtCocosWidget : public QWidget
{
public:
QtCocosWidget(QWidget* parent = );
~QtCocosWidget();
void MakeActive();
protected:
virtual void resizeEvent(QResizeEvent *);
cocos2d::CCEGLViewForHWND* view;
};
源文件如下:
#include "QtCocosWidget.h"
#include "cocos2d.h"
#include "CEGLViewForHWND.h"
#include <QtGui\qevent.h> using namespace cocos2d; QtCocosWidget::QtCocosWidget(QWidget* parent) : QWidget(parent)
{
HWND id = (HWND)winId();
view = new CCEGLViewForHWND(id);
} void QtCocosWidget::MakeActive()
{
view->setCurrent();
} void QtCocosWidget::resizeEvent(QResizeEvent* ev)
{
//CCDirector::sharedDirector()->setViewport();
QWidget::resizeEvent(ev);
} QtCocosWidget::~QtCocosWidget()
{
}
这个类的作用是,将第一步实现的类和qt结合起来。
3 还是要小改cocos2d的代码(没办法,谁让CCEGLView使用了单例呢)
加入函数
static void RegisterView(CCEGLView* view);
函数实现如下:
void CCEGLView::RegisterView(CCEGLView* view)
{
s_pMainWindow = view; s_pEglView = view;
}
完工!
使用方法:
#include "QtCocosWidget.h" ...
...
...
... AppDelegate ccapp;
int argc = ;
QApplication app(argc, NULL);
...
QtCocosWidget* target = new QtCocosWidget(parent);
target->MakeActive();
return CCApplication::sharedApplication()->run();
可以看到出来效果了!
Cocos2dx集成于windows桌面窗口程序的步骤的更多相关文章
- Visual C++ Windows 桌面应用程序样例(摘抄)
//================================== //Windows应用程序框架结构(例子) //参考:<Visual C++宝典>陈国建等编著 //======= ...
- 适用于Windows桌面应用程序的.NET Core 3
介绍 9月,微软发布了新版.NET Core,用于构建Windows桌面应用程序,包括WPF和Windows Forms.从那时起开发人员可以将传统的nfx桌面应用程序(和控件库)迁移到.NET Co ...
- 对Windows桌面应用程序进行UI自动化测试
题记:本文简述如何利用appium对Windows桌面应用程序进行UI自动化测试. 所谓UI自动化测试,就是模拟一个用户,对应用程序的UI进行操作,以完成特定场景的功能性集成测试. 要对Windows ...
- C++使用代码创建一个Windows桌面应用程序
WinMain函数 Windows应用程序的唯一程序入口. 函数原型 int WINAPI WinMain { HINSTANCE hInstancem HINSTANCE hPreInstance, ...
- 使用PHP-GTK编写一个windows桌面应用程序
PHP-GTK的下载地址:http://gtk.php.net/download.php?language=en-US, 猿哥选择了最新版本(beta版),可能有人会问我们为啥不选最新的stable版 ...
- C#开发Windows窗体应用程序的步骤
使用C#开发应用程序时,一般包括创建项目.界面设计.设置属性.编写程序代码.保存项目.程序运行等6个步骤. 1.创建项目 在Visual Studio2017开发环境中选择“文件”→“新建”→“项目” ...
- Windows桌面.exe程序安装、卸载、升级测试用例
一.安装 1) 系统:XP.win 7.win 8.win 10 2)安全类型软件:360杀毒.360安全卫士.金山毒霸.百度杀毒.腾讯电脑管家等. 3)同类型软件兼容 4)用户名称:中文用户.英文用 ...
- 将python项目打包为可运行的windows桌面exe程序
---恢复内容开始--- 步骤大概如下: 1.需要一个python文件/项目.也就是我们想要打包的文件 2.安装pyinstaller,目的是将我们的python文件生成为exe可执行程序. 3.使用 ...
- Windows普通窗口程序
2015-10-09 12:55:38 KWindow.h #pragma once #include <windows.h> class KWindow { virtual void O ...
随机推荐
- JS实现选择不同select标签option值的验证
js实现不同select标签option值的验证 功能描述: 选择中文时,匹配中文的正则表达式,选择英文选项是匹配英文的表达式,并且有对应的提示信息. html代码片段: <select id= ...
- Thymeleaf 常用属性
Thymeleaf 常用属性 如需了解thymeleafThymeleaf 基本表达式,请参考<Thymeleaf 基本表达式>一文 th:action 定义后台控制器路径,类似<f ...
- AdaBoost 和 Real Adaboost 总结
AdaBoost 和 Real Adaboost 总结 AdaBoost Real AdaBoost AdaBoost AdaBoost, Adaptive Boosting(自适应增强), 是一种集 ...
- MyIsam和InnoDB的区别
个人见解: 1.最主要的差别就是Innodb 支持事务处理与外键和行级锁.而MyISAM不支持 所以有用到事务处理和外键的,要用Innodb 2. InnoDB 中不保存表的具体行数,也就是说,执行s ...
- HDU 2861 (DP+打表)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2861 题目大意:n个位置,m个人,分成k段,统计分法.S(n)=∑nk=0CknFibonacci(k ...
- android 自定义 view 和 ViewGroup
---恢复内容开始--- ViewGroup的职能为:给childView计算出建议的宽和高和测量模式 :决定childView的位置:为什么只是建议的宽和高,而不是直接确定呢,别忘了childVie ...
- [知识点]Trie树和AC自动机
// 此博文为迁移而来,写于2015年5月27日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w1s8.html 1.前 ...
- 【BZOJ】1135: [POI2009]Lyz
题意 有\(1\)到\(n(1 \le n \le 200000)\)号的溜冰鞋各\(k(1 \le k \le 10^9)\)双.已知\(x\)号脚的人可以穿\(x\)到\(x+d\)的溜冰鞋. 有 ...
- qt编译常见错误
一.fatal error: QWidget: 没有那个文件或目录 类似于找不到文件目录的,在.pro文件中添加 QT +=\ widgets 类似就可以编译通过
- JavaScript放置位置区别
JavaScript放置位置区别 页面中的脚本会在页面载入浏览器后立即执行.我们并不总希望这样.有时,我们希望当页面载入时执行脚本,而另外的时候,我们则希望当用户触发事件时才执行脚本. 位于 head ...