cocos2d-x游戏引擎核心(3.x)----事件分发机制之事件从(android,ios,desktop)系统传到cocos2dx的过程浅析
(一) Android平台下:
cocos2dx 版本3.2,先导入一个android工程,然后看下AndroidManifest.xml
<application android:label="@string/app_name"
android:icon="@drawable/icon"> <!-- Tell Cocos2dxActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="cocos2dcpp" /> <activity android:name="org.cocos2dx.cpp.AppActivity"
android:label="@string/app_name"
android:screenOrientation="landscape"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:configChanges="orientation"> <intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
由此得知启动窗口类为 org.cocos2dx.cpp.AppActivity,并继承之 Cocos2dxActivity.
package org.cocos2dx.cpp;
import org.cocos2dx.lib.Cocos2dxActivity;
public class AppActivity extends Cocos2dxActivity {
}
public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelperListener
看下 Cocos2dxActivity 的 onCreate
@Override
protected void onCreate(final Bundle savedInstanceState) {
Log.i(TAG, "------onCreate----");
super.onCreate(savedInstanceState);
CocosPlayClient.init(this, false); onLoadNativeLibraries();//加载了一些静态库 sContext = this;
this.mHandler = new Cocos2dxHandler(this); Cocos2dxHelper.init(this); this.mGLContextAttrs = getGLContextAttrs();
this.init();//初始化 if (mVideoHelper == null) {
mVideoHelper = new Cocos2dxVideoHelper(this, mFrameLayout);
} if(mWebViewHelper == null){
mWebViewHelper = new Cocos2dxWebViewHelper(mFrameLayout);
}
}
onCreate 调用了 init() 初始化
public void init() {
// FrameLayout
ViewGroup.LayoutParams framelayout_params =
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
mFrameLayout = new FrameLayout(this);
mFrameLayout.setLayoutParams(framelayout_params);
// Cocos2dxEditText layout
ViewGroup.LayoutParams edittext_layout_params =
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
Cocos2dxEditText edittext = new Cocos2dxEditText(this);
edittext.setLayoutParams(edittext_layout_params);
// ...add to FrameLayout
mFrameLayout.addView(edittext);
// Cocos2dxGLSurfaceView
this.mGLSurfaceView = this.onCreateView();
// ...add to FrameLayout
mFrameLayout.addView(this.mGLSurfaceView);
// Switch to supported OpenGL (ARGB888) mode on emulator
if (isAndroidEmulator())
this.mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());
this.mGLSurfaceView.setCocos2dxEditText(edittext);
// Set framelayout as the content view
setContentView(mFrameLayout);
}
最终显示的视图为 this.mGLSurfaceView = this.onCreateView();
public Cocos2dxGLSurfaceView onCreateView() {
Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this);
//this line is need on some device if we specify an alpha bits
if(this.mGLContextAttrs[3] > 0) glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
Cocos2dxEGLConfigChooser chooser = new Cocos2dxEGLConfigChooser(this.mGLContextAttrs);
glSurfaceView.setEGLConfigChooser(chooser);
return glSurfaceView;
}
Cocos2dxGLSurfaceView 就是最终显示的视图,事件处理也在这个类中,包括 onResume,onPause,onSizeChanged,onKeyDown,onTouchEvent等 主要看下onTouchEvent事件的处理过程.
@Override
public boolean onTouchEvent(final MotionEvent pMotionEvent) { //Log.d(TAG, "------onTouchEvent action=----"+pMotionEvent.getAction()); // these data are used in ACTION_MOVE and ACTION_CANCEL
final int pointerNumber = pMotionEvent.getPointerCount();
final int[] ids = new int[pointerNumber];
final float[] xs = new float[pointerNumber];
final float[] ys = new float[pointerNumber]; for (int i = 0; i < pointerNumber; i++) {
ids[i] = pMotionEvent.getPointerId(i);
xs[i] = pMotionEvent.getX(i);
ys[i] = pMotionEvent.getY(i);
} switch (pMotionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
final int indexPointerDown = pMotionEvent.getAction() >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int idPointerDown = pMotionEvent.getPointerId(indexPointerDown);
final float xPointerDown = pMotionEvent.getX(indexPointerDown);
final float yPointerDown = pMotionEvent.getY(indexPointerDown); this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionDown(idPointerDown, xPointerDown, yPointerDown);
}
});
break; case MotionEvent.ACTION_DOWN:
// there are only one finger on the screen
final int idDown = pMotionEvent.getPointerId(0);
final float xDown = xs[0];
final float yDown = ys[0]; this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionDown(idDown, xDown, yDown);
}
});
break; case MotionEvent.ACTION_MOVE:
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionMove(ids, xs, ys);
}
});
break; case MotionEvent.ACTION_POINTER_UP:
final int indexPointUp = pMotionEvent.getAction() >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int idPointerUp = pMotionEvent.getPointerId(indexPointUp);
final float xPointerUp = pMotionEvent.getX(indexPointUp);
final float yPointerUp = pMotionEvent.getY(indexPointUp); this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionUp(idPointerUp, xPointerUp, yPointerUp);
}
});
break; case MotionEvent.ACTION_UP:
// there are only one finger on the screen
final int idUp = pMotionEvent.getPointerId(0);
final float xUp = xs[0];
final float yUp = ys[0]; this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionUp(idUp, xUp, yUp);
}
});
break; case MotionEvent.ACTION_CANCEL:
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionCancel(ids, xs, ys);
}
});
break;
} /*
if (BuildConfig.DEBUG) {
Cocos2dxGLSurfaceView.dumpMotionEvent(pMotionEvent);
}
*/
return true;
}
看下 MotionEvent.ACTION_DOWN,调用了Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionDown.
public void handleActionDown(final int id, final float x, final float y) {
Log.i("Cocos2dxRenderer","-----handleActionDown--");
Cocos2dxRenderer.nativeTouchesBegin(id, x, y);
}
这里的nativeTouchesBegin 是一个jni方法,是现在cocos2d\cocos\platform\android\jni\TouchesJni.cpp里,
private static native void nativeTouchesBegin(final int id, final float x, final float y);
JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesBegin(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y) {
intptr_t idlong = id;
log("----Info:nativeTouchesBegin id = %d, x=%f, y=%f",id,x,y);
cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesBegin(1, &idlong, &x, &y);
}
最后调用GLView::handleTouchesBegin (其实GLView并没有重写父类的handleTouchesBegin方法,所以android下的触发事件,最后是通过GLViewProtocol类的handleTouchesBegin方法进行处理的). 通过 EventDispatcher::dispatchEvent进行事件的分发,调用事件响应函数,都是C++里完成的,就不再往下分析了。
附注:
C++里对事件的分发机制是通过Event,EventListener和EventDispatcher三个主要类完成的,具体详见cocos2d-x 源码分析 : EventDispatcher、EventListener、Event 源码分析 (新触摸机制,新的NotificationCenter机制).
(二) 上面针对的是Android平台下,其他系统事件通知到cocos2dx的流程,在desktop和ios下的流程类似,都有相应平台下的处理文件接收系统事件,如下:
/home/yangxt/document/cocos2d-x-3.2/cocos/platform/CCGLViewProtocol.cpp:
: void GLViewProtocol::handleTouchesBegin(int num, intptr_t ids[], float xs[], float ys[]) /home/yangxt/document/cocos2d-x-3.2/cocos/platform/CCGLViewProtocol.h:
: virtual void handleTouchesBegin(int num, intptr_t ids[], float xs[], float ys[]); /home/yangxt/document/cocos2d-x-3.2/cocos/platform/android/jni/TouchesJni.cpp:
: cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesBegin(, &id, &x, &y); /home/yangxt/document/cocos2d-x-3.2/cocos/platform/desktop/CCGLView.cpp:
: this->handleTouchesBegin(, &id, &_mouseX, &_mouseY); /home/yangxt/document/cocos2d-x-3.2/cocos/platform/ios/CCEAGLView.mm:
: glview->handleTouchesBegin(i, (intptr_t*)ids, xs, ys);
从上面可以看出,android下的系统调用最后是调用到了TouchesJni.cpp文件下的触摸事件.也即本文第(一)部分所分析的结果.如果在ios平台下,可以看到是通过CCEAGLView.mm文件处理的.ios下这里不做过多分析. 而desktop平台下,直接通过CCGLView.cpp处理.下面看看desktop平台下的处理过程:
我们可以在GLView.cpp下找到下面的方法:
bool GLView::initWithRect(const std::string& viewName, Rect rect, float frameZoomFactor)
{
setViewName(viewName); _frameZoomFactor = frameZoomFactor; glfwWindowHint(GLFW_RESIZABLE,GL_FALSE); _mainWindow = glfwCreateWindow(rect.size.width * _frameZoomFactor,
rect.size.height * _frameZoomFactor,
_viewName.c_str(),
_monitor,
nullptr);
glfwMakeContextCurrent(_mainWindow); glfwSetMouseButtonCallback(_mainWindow, GLFWEventHandler::onGLFWMouseCallBack);
glfwSetCursorPosCallback(_mainWindow, GLFWEventHandler::onGLFWMouseMoveCallBack);
glfwSetScrollCallback(_mainWindow, GLFWEventHandler::onGLFWMouseScrollCallback);
glfwSetCharCallback(_mainWindow, GLFWEventHandler::onGLFWCharCallback);
glfwSetKeyCallback(_mainWindow, GLFWEventHandler::onGLFWKeyCallback);
glfwSetWindowPosCallback(_mainWindow, GLFWEventHandler::onGLFWWindowPosCallback);
glfwSetFramebufferSizeCallback(_mainWindow, GLFWEventHandler::onGLFWframebuffersize);
glfwSetWindowSizeCallback(_mainWindow, GLFWEventHandler::onGLFWWindowSizeFunCallback); setFrameSize(rect.size.width, rect.size.height); // check OpenGL version at first
const GLubyte* glVersion = glGetString(GL_VERSION); if ( utils::atof((const char*)glVersion) < 1.5 )
{
char strComplain[] = {};
sprintf(strComplain,
"OpenGL 1.5 or higher is required (your version is %s). Please upgrade the driver of your video card.",
glVersion);
MessageBox(strComplain, "OpenGL version too old");
return false;
} initGlew(); // Enable point size by default.
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); return true;
}
glfwCreateWindow方法里面就完成了窗口的创建以及其他的一些初始化工作,并且也设置了鼠标,键盘等一下响应回调函数,这里,我们看看glfwSetMouseButtonCallback(_mainWindow, GLFWEventHandler::onGLFWMouseCallBack);的回调函数:
void GLView::onGLFWMouseCallBack(GLFWwindow* window, int button, int action, int modify)
{
if(GLFW_MOUSE_BUTTON_LEFT == button)
{
if(GLFW_PRESS == action)
{
_captured = true;
if (this->getViewPortRect().equals(Rect::ZERO) || this->getViewPortRect().containsPoint(Vec2(_mouseX,_mouseY)))
{
intptr_t id = ;
this->handleTouchesBegin(, &id, &_mouseX, &_mouseY);
}
}
else if(GLFW_RELEASE == action)
{
if (_captured)
{
_captured = false;
intptr_t id = ;
this->handleTouchesEnd(, &id, &_mouseX, &_mouseY);
}
}
} //Because OpenGL and cocos2d-x uses different Y axis, we need to convert the coordinate here
float cursorX = (_mouseX - _viewPortRect.origin.x) / _scaleX;
float cursorY = (_viewPortRect.origin.y + _viewPortRect.size.height - _mouseY) / _scaleY; if(GLFW_PRESS == action)
{
EventMouse event(EventMouse::MouseEventType::MOUSE_DOWN);
event.setCursorPosition(cursorX, cursorY);
event.setMouseButton(button);
Director::getInstance()->getEventDispatcher()->dispatchEvent(&event);
}
else if(GLFW_RELEASE == action)
{
EventMouse event(EventMouse::MouseEventType::MOUSE_UP);
event.setCursorPosition(cursorX, cursorY);
event.setMouseButton(button);
Director::getInstance()->getEventDispatcher()->dispatchEvent(&event);
}
}
可以看到,在GLView里面直接处理窗口鼠标事件,并通过dispatchEvent将事件分发给cocos2dx. cocos2dx里面的事件分发这里也不作过多阐述.
附注:
上面对事件分发机制的分析中,我们可以看到,GLViewProtocol类实际负责了窗口级别的功能管理和实现, 包括:坐标和缩放管理, 画图工具,按键事件,而这些正是cocos2d-x游戏引擎核心(3.x)----启动渲染流程 博文分析中可以看到的.
cocos2d-x游戏引擎核心(3.x)----事件分发机制之事件从(android,ios,desktop)系统传到cocos2dx的过程浅析的更多相关文章
- cocos2d-x 事件分发机制 ——加速计事件监听
加速计事件监听机制 在上一篇中介绍了cocos2d-x中的触摸事件机制,这篇来介绍下游戏中也常常常使用到的加速计事件,这些都是游戏中的常常要用到的. 移动设备上一个非常重要的输入源是设备的方向.大多数 ...
- cocos2d-x 事件分发机制 ——触摸事件监听
cocos2d-x 3.0 出来已经好久了,也已经用3.0写了几个小游戏,感觉3.0的事件触发机制太赞了,随这里总结一下.也算是对知识的一种回顾和加深理解. 3.0的事件分发机制中.须要也只须要通过创 ...
- 【Unity游戏开发】用C#和Lua实现Unity中的事件分发机制EventDispatcher
一.简介 最近马三换了一家大公司工作,公司制度规范了一些,因此平时的业余时间多了不少.但是人却懒了下来,最近这一个月都没怎么研究新技术,博客写得也是拖拖拉拉,周六周天就躺尸在家看帖子.看小说,要么就是 ...
- 本以为精通Android事件分发机制,没想到被面试官问懵了
文章中出现的源码均基于8.0 前言 事件分发机制不仅仅是核心知识点更是难点,并且还是View的一大难题滑动冲突解决方法的理论基础,因此掌握好View的事件分发机制是十分重要的. 一.基本认识 1. 事 ...
- Android事件分发机制源码分析
Android事件分发机制源码分析 Android事件分发机制源码分析 Part1事件来源以及传递顺序 Activity分发事件源码 PhoneWindow分发事件源码 小结 Part2ViewGro ...
- Android面试收集录6 事件分发机制
转自:秋招面试宝典. 一. 基础认知 1.1 事件分发的对象是谁? 答:事件 当用户触摸屏幕时(View或ViewGroup派生的控件),将产生点击事件(Touch事件). Touch事件相关细节(发 ...
- Android进阶——Android事件分发机制之dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent
Android事件分发机制可以说是我们Android工程师面试题中的必考题,弄懂它的原理是我们避不开的任务,所以长痛不如短痛,花点时间干掉他,废话不多说,开车啦 Android事件分发机制的发生在Vi ...
- 浅谈Android中的事件分发机制
View事件分发机制的本质就是就是MotionEvent事件的分发过程,即MotionEvent产生后是怎样在View之间传递及处理的. 首先介绍一下什么是MotionEvent.所谓MotionEv ...
- cocos2d-x游戏引擎核心之五——触摸事件和触摸分发器机制
一.触摸事件 为了处理屏幕触摸事件,Cocos2d-x 提供了非常方便.灵活的支持.在深入研究 Cocos2d-x 的触摸事件分发机制之前,我们利用 CCLayer 已经封装好的触摸接口来实现对简单的 ...
随机推荐
- Internet Explorer 11:不要再叫我IE
上周,Internet Explorer 11搭载Windows 8.1预览版而来,相信很多浏览迷也已经在使用中.Internet Explorer 11 Preview 改进了与 Web 标准.其他 ...
- 8-06. 畅通project之局部最小花费问题(35)(最小生成树_Prim)(ZJU_PAT)
题目链接:http://pat.zju.edu.cn/contests/ds/8-06 某地区经过对城镇交通状况的调查.得到现有城镇间高速道路的统计数据,并提出"畅通project" ...
- 设置Tab键缩进2字符
默认是1.74cm,是1.5字符. 论文是4个空格显示为4个点,或者全角下2个空格,显示为2个空格框.看上方的首航缩进标志是否在2. 看图 在段落 格式里面进行设置! 点上图的制表位 打开下图 选默认 ...
- Mui 下拉刷新,刷新完成功能实现
Mui中,正在刷新后,就直接回弹了,没有刷新完成这个过程,然后我就在中间添加了一个过程. 代码如下: //-----------日期格式化------------- function form ...
- loopback文件系统
回环设备(loop-back devices) 实验环境 centos7.2 回环设备( 'loopback device')允许用户以一个普通磁盘文件虚拟一个块设备.(磁盘文件 --> 块设备 ...
- puppet应用案例
- Python操作redis系列之 列表(list) (五)
# -*- coding: utf- -*- import redis r =redis.Redis(host=,password=") 1. Lpush 命令将一个或多个值插入到列表头部. ...
- 解决MySQL8.0报错:Unknown system variable 'validate_password_policy'
一.问题描述 1.在安装MySQL8.0时,修改临时密码,因密码过于简单(如:123456),不符合MySQL密码规范,会触发一个报错信息: ERROR 1819 (HY000): Your pass ...
- 【SqlServer】SqlServer中的更新锁(UPDLOCK)
UPDLOCK.UPDLOCK 的优点是允许您读取数据(不阻塞其它事务)并在以后更新数据,同时确保自从上次读取数据后数据没有被更改.当我们用UPDLOCK来读取记录时可以对取到的记录加上更新锁,从而加 ...
- [Aaronyang紫色博客] 写给自己的WPF4.5-Blend5公开课系列 2-更进一步
我的文章一定要做到对读者负责,否则就是失败的文章 --------- www.ayjs.net aaronyang技术分享 欢迎大家支持我的力作<[Aaronyang] 写给自己的 ...