cocos2dx android平台事件系统解析
对于cocos2dx在android平台事件的响应过程很模糊,于是分析了下源码,cocos2dx 版本3.4,先导入一个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 通过 EventDispatcher::dispatchEvent进行事件的分发,调用事件响应函数,都是C++里完成的,就不再往下分析了。
能力有限,分析有误处请指正。