對於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++里完成的,就不再往下分析了。
能力有限,分析有誤處請指正。