• Cocos2d-x-3.6 用户交互原理---------如何通过JNI连接Java和C++


                用户交互这里指的就是用户在手机上的点击,滑动以及晃动手机等行为,从而得到相应的反馈。今天学习Cocos2dx,遇到交互问题,所以就写出来和大家分享一下。我这里是以Android连接为例的,因为目前我只会Android相关的开发。好了,不多说,看下面步骤:

    第一步:在Android中,交互操作的入口在SurfaceView或是GLSurfaceView中的onTouchEvent时间中。本例代码所在位置org.cocos2dx.lib---->Cocos2dxGLSurfaceView.java

    [java] view plaincopy
    1. public boolean onTouchEvent(final MotionEvent pMotionEvent) {  
    2.         // these data are used in ACTION_MOVE and ACTION_CANCEL  
    3.         final int pointerNumber = pMotionEvent.getPointerCount();  
    4.         final int[] ids = new int[pointerNumber];  
    5.         final float[] xs = new float[pointerNumber];  
    6.         final float[] ys = new float[pointerNumber];  
    7.   
    8.         for (int i = 0; i < pointerNumber; i++) {  
    9.             ids[i] = pMotionEvent.getPointerId(i);  
    10.             xs[i] = pMotionEvent.getX(i);  
    11.             ys[i] = pMotionEvent.getY(i);  
    12.         }  
    13.   
    14.         switch (pMotionEvent.getAction() & MotionEvent.ACTION_MASK) {  
    15.             case MotionEvent.ACTION_POINTER_DOWN:  
    16.                 final int indexPointerDown = pMotionEvent.getAction() >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;  
    17.                 final int idPointerDown = pMotionEvent.getPointerId(indexPointerDown);  
    18.                 final float xPointerDown = pMotionEvent.getX(indexPointerDown);  
    19.                 final float yPointerDown = pMotionEvent.getY(indexPointerDown);  
    20.   
    21.                 this.queueEvent(new Runnable() {  
    22.                     @Override  
    23.                     public void run() {  
    24.                         Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionDown(idPointerDown, xPointerDown, yPointerDown);  
    25.                     }  
    26.                 });  
    27.                 break;  
    28.   
    29.             case MotionEvent.ACTION_DOWN:  
    30.                 // there are only one finger on the screen  
    31.                 final int idDown = pMotionEvent.getPointerId(0);  
    32.                 final float xDown = xs[0];  
    33.                 final float yDown = ys[0];  
    34.   
    35.                 this.queueEvent(new Runnable() {  
    36.                     @Override  
    37.                     public void run() {  
    38.                         Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionDown(idDown, xDown, yDown);  
    39.                     }  
    40.                 });  
    41.                 break;  
    42.   
    43.             case MotionEvent.ACTION_MOVE:  
    44.                 this.queueEvent(new Runnable() {  
    45.                     @Override  
    46.                     public void run() {  
    47.                         Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionMove(ids, xs, ys);  
    48.                     }  
    49.                 });  
    50.                 break;  
    51.   
    52.             case MotionEvent.ACTION_POINTER_UP:  
    53.                 final int indexPointUp = pMotionEvent.getAction() >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;  
    54.                 final int idPointerUp = pMotionEvent.getPointerId(indexPointUp);  
    55.                 final float xPointerUp = pMotionEvent.getX(indexPointUp);  
    56.                 final float yPointerUp = pMotionEvent.getY(indexPointUp);  
    57.   
    58.                 this.queueEvent(new Runnable() {  
    59.                     @Override  
    60.                     public void run() {  
    61.                         Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionUp(idPointerUp, xPointerUp, yPointerUp);  
    62.                     }  
    63.                 });  
    64.                 break;  
    65.   
    66.             case MotionEvent.ACTION_UP:  
    67.                 // there are only one finger on the screen  
    68.                 final int idUp = pMotionEvent.getPointerId(0);  
    69.                 final float xUp = xs[0];  
    70.                 final float yUp = ys[0];  
    71.   
    72.                 this.queueEvent(new Runnable() {  
    73.                     @Override  
    74.                     public void run() {  
    75.                         Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionUp(idUp, xUp, yUp);  
    76.                     }  
    77.                 });  
    78.                 break;  
    79.   
    80.             case MotionEvent.ACTION_CANCEL:  
    81.                 this.queueEvent(new Runnable() {  
    82.                     @Override  
    83.                     public void run() {  
    84.                         Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionCancel(ids, xs, ys);  
    85.                     }  
    86.                 });  
    87.                 break;  
    88.         }  
    89.   
    90.             return true;  
    91.     }  

    第二步: Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionDown(idDown, xDown, yDown)等相关语句的方法在org.cocos2dx.lib------>Cocos2dxRender.java,代码如下:

    [java] view plaincopy
    1. private static native void nativeTouchesBegin(final int id, final float x, final float y);  
    2. private static native void nativeTouchesEnd(final int id, final float x, final float y);  
    3. private static native void nativeTouchesMove(final int[] ids, final float[] xs, final float[] ys);  
    4. private static native void nativeTouchesCancel(final int[] ids, final float[] xs, final float[] ys);  
    5.   
    6. public void handleActionDown(final int id, final float x, final float y) {  
    7.     Cocos2dxRenderer.nativeTouchesBegin(id, x, y);  
    8. }  
    9.   
    10. public void handleActionUp(final int id, final float x, final float y) {  
    11.     Cocos2dxRenderer.nativeTouchesEnd(id, x, y);  
    12. }  
    13.   
    14. public void handleActionCancel(final int[] ids, final float[] xs, final float[] ys) {  
    15.     Cocos2dxRenderer.nativeTouchesCancel(ids, xs, ys);  
    16. }  
    17.   
    18. public void handleActionMove(final int[] ids, final float[] xs, final float[] ys) {  
    19.     Cocos2dxRenderer.nativeTouchesMove(ids, xs, ys);  
    20. }  


    第三步:  private static native void nativeTouchesBegin(final int id, final float x, final float y)这是本地方法,调用c++内容的语句。而这些内容被打包在Android工程中的libs/armeabi/cocos2dcpp.so文件中。所以我们在使用这些方法时一定要加载这个.so文件。代码位置在org.cocos2dx.lib--->Cocos2dxActivity.java,内容如下:

    [java] view plaincopy
    1. protected void onLoadNativeLibraries() {  
    2.        try {  
    3.            ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);  
    4.            Bundle bundle = ai.metaData;  
    5.            String libName = bundle.getString("android.app.lib_name");  
    6.            System.loadLibrary(libName);  
    7.        } catch (Exception e) {  
    8.            e.printStackTrace();  
    9.        }  
    10.    }  
    bundle.getString("android.app.lib_name")文件是找出.so文件。和它相关内容在Android工程中AndroidManifest.xml里,内容如下:

    [html] view plaincopy
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    3.       package="org.cocos.CocosProject4"  
    4.       android:versionCode="1"  
    5.       android:versionName="1.0"  
    6.       android:installLocation="auto">  
    7.   
    8.     <uses-sdk android:minSdkVersion="9"/>  
    9.     <uses-feature android:glEsVersion="0x00020000" />  
    10.   
    11.     <application android:label="@string/app_name"  
    12.                  android:icon="@drawable/icon">  
    13.                        
    14.         <!-- Tell Cocos2dxActivity the name of our .so -->  
    15.         <meta-data android:name="android.app.lib_name"  
    16.                   android:value="cocos2dcpp" />  
    17.   
    18.         <activity android:name="org.cocos2dx.cpp.AppActivity"  
    19.                   android:label="@string/app_name"  
    20.                   android:screenOrientation="landscape"  
    21.                   android:theme="@android:style/Theme.NoTitleBar.Fullscreen"  
    22.                   android:configChanges="orientation">  
    23.   
    24.             <intent-filter>  
    25.                 <action android:name="android.intent.action.MAIN" />  
    26.                 <category android:name="android.intent.category.LAUNCHER" />  
    27.             </intent-filter>  
    28.         </activity>  
    29.     </application>  
    30.   
    31.     <supports-screens android:anyDensity="true"  
    32.                       android:smallScreens="true"  
    33.                       android:normalScreens="true"  
    34.                       android:largeScreens="true"  
    35.                       android:xlargeScreens="true"/>  
    36.   
    37.     <uses-permission android:name="android.permission.INTERNET"/>  
    38. </manifest>   

    第四步:cocos2dcpp.so文件的生成,因为native 方法都在这里面。它的生成在Android工程中的jni文件里么的Android.mk文件(相关内容参考链接)。native方法所在文件路径cocos2d-x-3.6/cocos/platform/android/jni/TouchesJni.cpp,内容如下:

    1. #include "base/CCDirector.h"  
    2. #include "base/CCEventKeyboard.h"  
    3. #include "base/CCEventDispatcher.h"  
    4. #include "platform/android/CCGLViewImpl-android.h"  
    5.   
    6. #include <android/log.h>  
    7. #include <jni.h>  
    8.   
    9. using namespace cocos2d;  
    10.   
    11. extern "C" {  
    12.     JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesBegin(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y) {  
    13.         intptr_t idlong = id;  
    14.         cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesBegin(1, &idlong, &x, &y);  
    15.     }  
    16.   
    17.     JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesEnd(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y) {  
    18.         intptr_t idlong = id;  
    19.         cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesEnd(1, &idlong, &x, &y);  
    20.     }  
    21.   
    22.     JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesMove(JNIEnv * env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys) {  
    23.         int size = env->GetArrayLength(ids);  
    24.         jint id[size];  
    25.         jfloat x[size];  
    26.         jfloat y[size];  
    27.   
    28.         env->GetIntArrayRegion(ids, 0, size, id);  
    29.         env->GetFloatArrayRegion(xs, 0, size, x);  
    30.         env->GetFloatArrayRegion(ys, 0, size, y);  
    31.   
    32.         intptr_t idlong[size];  
    33.         for(int i = 0; i < size; i++)  
    34.             idlong[i] = id[i];  
    35.   
    36.         cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesMove(size, idlong, x, y);  
    37.     }  
    38.   
    39.     JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesCancel(JNIEnv * env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys) {  
    40.         int size = env->GetArrayLength(ids);  
    41.         jint id[size];  
    42.         jfloat x[size];  
    43.         jfloat y[size];  
    44.   
    45.         env->GetIntArrayRegion(ids, 0, size, id);  
    46.         env->GetFloatArrayRegion(xs, 0, size, x);  
    47.         env->GetFloatArrayRegion(ys, 0, size, y);  
    48.   
    49.         intptr_t idlong[size];  
    50.         for(int i = 0; i < size; i++)  
    51.             idlong[i] = id[i];  
    52.   
    53.         cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesCancel(size, idlong, x, y);  
    54.     }  
    55.      
    56.     }  

    第五步:cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesBegin(1, &idlong, &x, &y)这个方法是如何起作用的呢,文件位置在cocos2d-x-3.6/cocos/platform/CCGLView.cpp,内如如下:

    1. void GLView::handleTouchesBegin(int num, intptr_t ids[], float xs[], float ys[])  
    2. {  
    3.     intptr_t id = 0;  
    4.     float x = 0.0f;  
    5.     float y = 0.0f;  
    6.     int unusedIndex = 0;  
    7.     EventTouch touchEvent;  
    8.       
    9.     for (int i = 0; i < num; ++i)  
    10.     {  
    11.         id = ids[i];  
    12.         x = xs[i];  
    13.         y = ys[i];  
    14.   
    15.         auto iter = g_touchIdReorderMap.find(id);  
    16.   
    17.         // it is a new touch  
    18.         if (iter == g_touchIdReorderMap.end())  
    19.         {  
    20.             unusedIndex = getUnUsedIndex();  
    21.   
    22.             // The touches is more than MAX_TOUCHES ?  
    23.             if (unusedIndex == -1) {  
    24.                 CCLOG("The touches is more than MAX_TOUCHES, unusedIndex = %d", unusedIndex);  
    25.                 continue;  
    26.             }  
    27.   
    28.             Touch* touch = g_touches[unusedIndex] = new (std::nothrow) Touch();  
    29.             touch->setTouchInfo(unusedIndex, (x - _viewPortRect.origin.x) / _scaleX,  
    30.                                      (y - _viewPortRect.origin.y) / _scaleY);  
    31.               
    32.             CCLOGINFO("x = %f y = %f", touch->getLocationInView().x, touch->getLocationInView().y);  
    33.               
    34.             g_touchIdReorderMap.insert(std::make_pair(id, unusedIndex));  
    35.             touchEvent._touches.push_back(touch);  
    36.         }  
    37.     }  
    38.   
    39.     if (touchEvent._touches.size() == 0)  
    40.     {  
    41.         CCLOG("touchesBegan: size = 0");  
    42.         return;  
    43.     }  
    44.       
    45.     touchEvent._eventCode = EventTouch::EventCode::BEGAN;  
    46.     auto dispatcher = Director::getInstance()->getEventDispatcher();  
    47.     dispatcher->dispatchEvent(&touchEvent);  
    48. }  

    第六步:使用。首先要给_eventDispathcer(在CCNote.cpp文件中)添加listener,示例如下:

    1. auto listener = EventListenerTouchAllAtOnce::create();  
    2.    listener->onTouchesBegan = CC_CALLBACK_2(ParticleDemo::onTouchesBegan, this);  
    3.    listener->onTouchesMoved = CC_CALLBACK_2(ParticleDemo::onTouchesMoved, this);  
    4.    listener->onTouchesEnded = CC_CALLBACK_2(ParticleDemo::onTouchesEnded, this);  
    5.    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);  
    其次就是我们实际操作,使交互产生什么样的变化,代码如下:

    1. void ParticleDemo::onTouchesBegan(const std::vector<Touch*>& touches, Event  *event)  
    2. {  
    3.     onTouchesEnded(touches, event);  
    4. }  
    5.   
    6. void ParticleDemo::onTouchesMoved(const std::vector<Touch*>& touches, Event  *event)  
    7. {  
    8.     return onTouchesEnded(touches, event);  
    9. }  
    10.   
    11. void ParticleDemo::onTouchesEnded(const std::vector<Touch*>& touches, Event  *event)  
    12. {  
    13.     auto touch = touches[0];  
    14.   
    15.     auto location = touch->getLocation();  
    16.   
    17.     auto pos = Vec2::ZERO;  
    18.     if (_background)  
    19.     {  
    20.         pos = _background->convertToWorldSpace(Vec2::ZERO);  
    21.     }  
    22.   
    23.     if (_emitter != nullptr)  
    24.     {  
    25.         _emitter->setPosition(location -pos);  
    26.     }  
    27. }  

    上面代码是ParticleTest中的内容,通过dispathcer将参数最终传递给要变化的_mitter,就是粒子发射器的移动。


  • 相关阅读:
    Javascript Promise技术
    什么是CPS
    移动端input file 提示没有应用可执行此操作
    黄聪:wordpress+Windows下安装Memcached服务及安装PHP的Memcached扩展
    黄聪:Windows下安装Memcached服务及安装PHP的Memcached扩展
    用VScode配置Python开发环境
    在VSCode中使用码云(Gitee)进行代码管理
    网页链接分享到微信朋友圈带图标和摘要的完美解决方法
    解决百度统计被刷广告的办法,屏蔽非法广告
    Visual Studio代码PHP Intelephense继续显示不必要的错误
  • 原文地址:https://www.cnblogs.com/Anzhongliu/p/6091993.html
Copyright © 2020-2023  润新知