cocos2dx --- Touch (二)
本文是关于cocos2dx获取并进行处理Android的滑屏事件,实现一个动态壁纸的效果。关于Android的本身的滑屏处理不在本文范围内。
在Android层面需要继承XXXWallPaperService,并实现onOffesetsChanged方法,当然为了使得cocos2dx获取onOffsetsChaneged事件,需要额外定义JNI接口,通过JNI接口,实现Cocos2dx的动态滑屏效果。
实现:
1).JNI接口(Java,C++)
1 public class ClassName implements GLWallpaperService.Renderer { 2 private boolean isCreate = false; 3 public VRenderer mRenderer; 4 public ClassName(int width,int height){ 5 mRenderer = new VRenderer(); 6 mRenderer.setScreenWidthAndHeight(width, height); 7 } 8 public void handleActionDown(final int pID, final float pX, final float pY) { 9 if(mRenderer!=null){ 10 mRenderer.handleActionDown(pID, pX, pY); 11 } 12 } 13 public void handleActionMove(final int[] pIDs, final float[] pXs, final float[] pYs) { 14 if(mRenderer!=null){ 15 mRenderer.handleActionMove(pIDs, pXs, pYs); 16 } 17 } 18 public void handleActionUp(final int pID, final float pX, final float pY) { 19 if(mRenderer!=null){ 20 mRenderer.handleActionUp(pID, pX, pY); 21 } 22 } 23 public void handleActionCancel(final int[] pIDs, final float[] pXs, final float[] pYs) { 24 if(mRenderer!=null){ 25 mRenderer.handleActionCancel(pIDs, pXs, pYs); 26 } 27 } 28 public void onDrawFrame(GL10 gl) { 29 VRenderer.nativeRender(); 30 } 31 public void onSurfaceChanged(GL10 gl, int width, int height){ 32 mRenderer.onSurfaceChanged(gl, width, height); 33 } 34 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 35 if(!isCreate){ 36 mRenderer.onSurfaceCreated(gl, config); 37 isCreate = true; 38 } else { 39 mRenderer.handleOnResume(); 40 } 41 42 } 43 public enum Status{ 44 pause,resume; 45 } 46 public void onPause(){ 47 // mRenderer.nativeStatus(Status.pause); 48 } 49 public void onResume(){ 50 // mRenderer.nativeStatus(Status.resume); 51 } 52 /** 53 * Called when the engine is destroyed. Do any necessary clean up because 54 * at this point your renderer instance is now done for. 55 */ 56 public void release() { 57 } 58 public void onOffsetsChanged(float xOffset, float yOffset,float xOffsetStep, float yOffsetStep, int xPixelOffset,int yPixelOffset) { 59 LoggerFactory.getLogger(getClass()).info("xOffset:{} yOffset:{} xStep:{} yStep:{} xOffset:{} yOffset:{}", new Object[]{xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset}); 60 mRenderer.handleSlideScreen(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset); 61 } 62 }
1 #include "cocoa/CCSet.h" 2 #include "CCDirector.h" 3 #include "keypad_dispatcher/CCKeypadDispatcher.h" 4 #include "touch_dispatcher/CCTouch.h" 5 #include "../CCEGLView.h" 6 #include "touch_dispatcher/CCTouchDispatcher.h" 7 #include <android/log.h> 8 #include <jni.h> 9 10 using namespace cocos2d; 11 12 extern "C" { 13 void Java_packagename_classname_nativeTouchesBegin(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y) { 14 cocos2d::CCDirector::sharedDirector()->getOpenGLView()->handleTouchesBegin(1, &id, &x, &y); 15 } 16 void Java_packagename_classname_nativeTouchesEnd(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y) { 17 cocos2d::CCDirector::sharedDirector()->getOpenGLView()->handleTouchesEnd(1, &id, &x, &y); 18 } 19 void Java_packagename_classname_nativeTouchesMove(JNIEnv * env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys) { 20 int size = env->GetArrayLength(ids); 21 jint id[size]; 22 jfloat x[size]; 23 jfloat y[size]; 24 env->GetIntArrayRegion(ids, 0, size, id); 25 env->GetFloatArrayRegion(xs, 0, size, x); 26 env->GetFloatArrayRegion(ys, 0, size, y); 27 cocos2d::CCDirector::sharedDirector()->getOpenGLView()->handleTouchesMove(size, id, x, y); 28 } 29 void Java_packagename_classname_nativeTouchesCancel(JNIEnv * env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys) { 30 int size = env->GetArrayLength(ids); 31 jint id[size]; 32 jfloat x[size]; 33 jfloat y[size]; 34 env->GetIntArrayRegion(ids, 0, size, id); 35 env->GetFloatArrayRegion(xs, 0, size, x); 36 env->GetFloatArrayRegion(ys, 0, size, y); 37 cocos2d::CCDirector::sharedDirector()->getOpenGLView()->handleTouchesCancel(size, id, x, y); 38 } 39 void Java_packagename_classname_nativeSlideScreen(JNIEnv * env,jfloat offsetx,jfloat offsety,jfloat stepx,jfloat stepy,jfloat pixelx,jfloat pixely){ 40 cocos2d::CCDirector::sharedDirector()->getOpenGLView()->handleSlideScreen(offsetx,offsety,stepx,stepy,pixelx,pixely); 41 } 42 #define KEYCODE_BACK 0x04 43 #define KEYCODE_MENU 0x52 44 jboolean Java_packagename_classname_nativeKeyDown(JNIEnv * env, jobject thiz, jint keyCode) { 45 CCDirector* pDirector = CCDirector::sharedDirector(); 46 switch (keyCode) { 47 case KEYCODE_BACK: 48 if (pDirector->getKeypadDispatcher()->dispatchKeypadMSG(kTypeBackClicked)) 49 return JNI_TRUE; 50 break; 51 case KEYCODE_MENU: 52 if (pDirector->getKeypadDispatcher()->dispatchKeypadMSG(kTypeMenuClicked)) 53 return JNI_TRUE; 54 break; 55 default: 56 return JNI_FALSE; 57 } 58 return JNI_FALSE; 59 } 60 }
在上述代码中,主要关心的是SlideScreen相关的实现。
2).cocos2dx中涉及触屏事件的类主要有:CCEGLView,CCEGLViewProtocal,EGLTouchDelegate,CCTouchDispatcher,CCTouchDelegate,CCTouch.其主要关系为,CCEGLView继承CCEGLViewProtocal,通过CCDirector的静态实例获取EGLView后,调用了CCEGLViewProtocal的handleSlideScreen方法。在handleSlideScreen方法中设置Touch事件的信息,并将事件委托给EGLTouchDelegate的slideScreenByTouches,EGLTouchDelegate同样是纯虚类,有CCTouchDispatcher继承并实现,这个过程主要用于确定事件类型和事件分发。在事件分发过程中将事件同样委托给CCTouchDelegate,由于CCTargetedTouchDelegate、CCStandardTouchDelegate继承了CCTouchDelegate,并且在CCTouchDispatcher过程中确定了事件类型,因此将调用响应的ccSlideScreenByTouches或ccSlideScreenByTouch。当然最终要何种效果,有用户继承ccSlideScreenByTouch(ccSlideScreenByTouches)实现。另外一点需要是,需要在CCTouch中实现对应的方法,以便设置和获取滑屏的信息。
Java_packagename_classname_nativeSlideScreen中调用了handleSlideScreen(),因此需要在CCEGLViewProtocal定义并实现handleSlideScreen,具体如下:
1 CCSet set; 2 CCLog("CCEGLViewProtocol slide value (%f,%f,%f,%f,%f,%f)",offsetx,offsety,stepx,stepy,pixelx,pixely); 3 uniq_Touch = new CCTouch(); 4 if (uniq_Touch){ 5 CCLog("CCEGLViewProtocol slide screen"); 6 uniq_Touch->setSlideScreenInfo(offsetx,offsety,stepx,stepy,pixelx,pixely); 7 uniq_Touch->release(); 8 } else{ 9 CCLOG("CCEGLViewProtocol slide screen error"); 10 return; 11 } 12 if (set.count() == 0){ 13 CCLOG("CCEGLViewProtocol slide screen count = 0"); 14 return; 15 } 16 m_pDelegate->sliedScreenByTouches(&set,NULL);
slideScreenByTouches在EGLTouchDelegate定义,EGLTouchDelegate是一个纯虚类,CCTouchDispatcher继承并实现了slideScreenByTouches,如下:
1 void CCTouchDispatcher::sliedScreenByTouches(CCSet* touches, CCEvent* pEvent) { 2 CCLog("CCTouchDispatcher::sliedScreenByTouches begin"); 3 if (m_bDispatchEvents) { 4 CCLog("CCTouchDispatcher::sliedScreenByTouches init,CCSet contians %d",touches->count()); 5 CCSet *pMutableTouches; 6 unsigned int uTargetedHandlersCount = m_pTargetedHandlers->count(); 7 unsigned int uStandardHandlersCount = m_pStandardHandlers->count(); 8 bool bNeedsMutableSet = (uTargetedHandlersCount&& uStandardHandlersCount); 9 pMutableTouches =(bNeedsMutableSet ? touches->mutableCopy() : touches); 10 CCTouch *pTouch; 11 CCSetIterator setIter; 12 for (setIter = touches->begin(); setIter != touches->end();++setIter) { 13 pTouch = (CCTouch *) (*setIter); 14 CCLog("1---CCTouchDispatcher::sliedScreenByTouches"); 15 CCTargetedTouchHandler *pHandler = NULL; 16 CCObject* pObj = NULL; 17 CCARRAY_FOREACH(m_pTargetedHandlers, pObj) { 18 pHandler = (CCTargetedTouchHandler *) (pObj); 19 if (!pHandler) { 20 CCLog("2---CCTouchDispatcher::sliedScreenByTouches"); 21 break; 22 } else{ 23 CCLog("3---CCTouchDispatcher::sliedScreenByTouches"); 24 pHandler->getDelegate()->ccSlideScreenByTouch(pTouch,pEvent); 25 pHandler->getClaimedTouches()->removeObject(pTouch); 26 } 27 } 28 CCLog("4---CCTouchDispatcher::sliedScreenByTouches"); 29 if (pHandler->isSwallowsTouches()) { 30 if (bNeedsMutableSet) { 31 CCLog("5---CCTouchDispatcher::sliedScreenByTouches"); 32 pMutableTouches->removeObject(pTouch); 33 } 34 break; 35 } 36 } 37 if (uStandardHandlersCount > 0 && pMutableTouches->count() > 0) { 38 CCLog("6---CCTouchDispatcher::sliedScreenByTouches"); 39 CCStandardTouchHandler *pHandler = NULL; 40 CCObject* pObj = NULL; 41 CCARRAY_FOREACH(m_pStandardHandlers, pObj) { 42 pHandler = (CCStandardTouchHandler*) (pObj); 43 if (!pHandler) { 44 CCLog("7---CCTouchDispatcher::sliedScreenByTouches"); 45 break; 46 } 47 CCLog("8---CCTouchDispatcher::sliedScreenByTouches"); 48 pHandler->getDelegate()->ccSlideScreenByTouches(pMutableTouches, 49 pEvent); 50 } 51 } 52 CCLog("CCTouchDispatcher::sliedScreenByTouches end"); 53 } 54 }
通过CCTouchDispatcher后,将滑屏交给了CCTouchHandler去处理,CCTouchHandler获取委托类型,并交给相应的委托类进行处理。因为从Android层将滑屏的参数传递给了cocos2dx,因此需要在CCTouch中实现对参数的处理。
1 void setSlideScreenInfo(float offsetx,float offsety,float stepx,float stepy,float pixelx,float pixely){ 2 m_slideScreen.m_offsetX = offsetx; 3 m_slideScreen.m_offsetY = offsety; 4 m_slideScreen.m_stepX = stepx; 5 m_slideScreen.m_stepY = stepy; 6 m_slideScreen.m_pixelX = pixelx; 7 m_slideScreen.m_pixelY = pixely; 8 } 9 SlideScreen getSlideScreenInfo()const{return m_slideScreen;}