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

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

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

public boolean onTouchEvent(final MotionEvent pMotionEvent) {
        // 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;
        }

            return true;
    }

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

    private static native void nativeTouchesBegin(final int id, final float x, final float y);
    private static native void nativeTouchesEnd(final int id, final float x, final float y);
    private static native void nativeTouchesMove(final int[] ids, final float[] xs, final float[] ys);
    private static native void nativeTouchesCancel(final int[] ids, final float[] xs, final float[] ys);

    public void handleActionDown(final int id, final float x, final float y) {
        Cocos2dxRenderer.nativeTouchesBegin(id, x, y);
    }

    public void handleActionUp(final int id, final float x, final float y) {
        Cocos2dxRenderer.nativeTouchesEnd(id, x, y);
    }

    public void handleActionCancel(final int[] ids, final float[] xs, final float[] ys) {
        Cocos2dxRenderer.nativeTouchesCancel(ids, xs, ys);
    }

    public void handleActionMove(final int[] ids, final float[] xs, final float[] ys) {
        Cocos2dxRenderer.nativeTouchesMove(ids, xs, ys);
    }

第三步:  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,内容如下:

 protected void onLoadNativeLibraries() {
        try {
            ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
            Bundle bundle = ai.metaData;
            String libName = bundle.getString("android.app.lib_name");
            System.loadLibrary(libName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

bundle.getString("android.app.lib_name")文件是找出.so文件。和它相关内容在Android工程中AndroidManifest.xml里,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="org.cocos.CocosProject4"
      android:versionCode="1"
      android:versionName="1.0"
      android:installLocation="auto">

    <uses-sdk android:minSdkVersion="9"/>
    <uses-feature android:glEsVersion="0x00020000" />

    <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>

    <supports-screens android:anyDensity="true"
                      android:smallScreens="true"
                      android:normalScreens="true"
                      android:largeScreens="true"
                      android:xlargeScreens="true"/>

    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>

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

#include "base/CCDirector.h"
#include "base/CCEventKeyboard.h"
#include "base/CCEventDispatcher.h"
#include "platform/android/CCGLViewImpl-android.h"

#include <android/log.h>
#include <jni.h>

using namespace cocos2d;

extern "C" {
    JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesBegin(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y) {
        intptr_t idlong = id;
        cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesBegin(1, &idlong, &x, &y);
    }

    JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesEnd(JNIEnv * env, jobject thiz, jint id, jfloat x, jfloat y) {
        intptr_t idlong = id;
        cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesEnd(1, &idlong, &x, &y);
    }

    JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesMove(JNIEnv * env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys) {
        int size = env->GetArrayLength(ids);
        jint id[size];
        jfloat x[size];
        jfloat y[size];

        env->GetIntArrayRegion(ids, 0, size, id);
        env->GetFloatArrayRegion(xs, 0, size, x);
        env->GetFloatArrayRegion(ys, 0, size, y);

        intptr_t idlong[size];
        for(int i = 0; i < size; i++)
            idlong[i] = id[i];

        cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesMove(size, idlong, x, y);
    }

    JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesCancel(JNIEnv * env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys) {
        int size = env->GetArrayLength(ids);
        jint id[size];
        jfloat x[size];
        jfloat y[size];

        env->GetIntArrayRegion(ids, 0, size, id);
        env->GetFloatArrayRegion(xs, 0, size, x);
        env->GetFloatArrayRegion(ys, 0, size, y);

        intptr_t idlong[size];
        for(int i = 0; i < size; i++)
            idlong[i] = id[i];

        cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesCancel(size, idlong, x, y);
    }

    }

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

void GLView::handleTouchesBegin(int num, intptr_t ids[], float xs[], float ys[])
{
    intptr_t id = 0;
    float x = 0.0f;
    float y = 0.0f;
    int unusedIndex = 0;
    EventTouch touchEvent;

    for (int i = 0; i < num; ++i)
    {
        id = ids[i];
        x = xs[i];
        y = ys[i];

        auto iter = g_touchIdReorderMap.find(id);

        // it is a new touch
        if (iter == g_touchIdReorderMap.end())
        {
            unusedIndex = getUnUsedIndex();

            // The touches is more than MAX_TOUCHES ?
            if (unusedIndex == -1) {
                CCLOG("The touches is more than MAX_TOUCHES, unusedIndex = %d", unusedIndex);
                continue;
            }

            Touch* touch = g_touches[unusedIndex] = new (std::nothrow) Touch();
			touch->setTouchInfo(unusedIndex, (x - _viewPortRect.origin.x) / _scaleX,
                                     (y - _viewPortRect.origin.y) / _scaleY);

            CCLOGINFO("x = %f y = %f", touch->getLocationInView().x, touch->getLocationInView().y);

            g_touchIdReorderMap.insert(std::make_pair(id, unusedIndex));
            touchEvent._touches.push_back(touch);
        }
    }

    if (touchEvent._touches.size() == 0)
    {
        CCLOG("touchesBegan: size = 0");
        return;
    }

    touchEvent._eventCode = EventTouch::EventCode::BEGAN;
    auto dispatcher = Director::getInstance()->getEventDispatcher();
    dispatcher->dispatchEvent(&touchEvent);
}

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

 auto listener = EventListenerTouchAllAtOnce::create();
    listener->onTouchesBegan = CC_CALLBACK_2(ParticleDemo::onTouchesBegan, this);
    listener->onTouchesMoved = CC_CALLBACK_2(ParticleDemo::onTouchesMoved, this);
    listener->onTouchesEnded = CC_CALLBACK_2(ParticleDemo::onTouchesEnded, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

其次就是我们实际操作,使交互产生什么样的变化,代码如下:

void ParticleDemo::onTouchesBegan(const std::vector<Touch*>& touches, Event  *event)
{
    onTouchesEnded(touches, event);
}

void ParticleDemo::onTouchesMoved(const std::vector<Touch*>& touches, Event  *event)
{
    return onTouchesEnded(touches, event);
}

void ParticleDemo::onTouchesEnded(const std::vector<Touch*>& touches, Event  *event)
{
    auto touch = touches[0];

    auto location = touch->getLocation();

    auto pos = Vec2::ZERO;
    if (_background)
    {
        pos = _background->convertToWorldSpace(Vec2::ZERO);
    }

    if (_emitter != nullptr)
    {
        _emitter->setPosition(location -pos);
    }
}

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

好了,以上就是这个过程,当然,要想完全理解,那就要修炼内功了,怎么做,你懂的~

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-25 11:33:28

Cocos2d-x-3.6 用户交互原理---------如何通过JNI连接Java和C++的相关文章

浅析Java web程序之客户端和服务器端交互原理(转)

转载自http://www.cnblogs.com/lys_013/archive/2012/05/05/2484561.html 1. 协议 a. TCP/IP整体构架概述 TCP/IP协议并不完全符合OSI的七层参考模型.传统的开放式系统互连参考模型,是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务. 该模型的目的是使各种硬件在相同的层次上相互通信.这7层是:物理层.数据链路层.网路层.传输层.话路层.表示层和应用层.而TCP/IP通讯协议采用 了4层的层级结构,每一层都呼叫它

浅析Java web程序之客户端和应用服务器端交互原理

最近一直在思考一个问题,为什么在用struts框架开发的时候FormBean都需要序列化,即实现java.io.Serializable接口,本着勤学好问的精神我Google了下对象序列化方面的文章,虽然大体了解了怎么做,但是还是没有搞清楚为什么要这样做:最后我想解决一个问题要找问题的根源和本质,于是从web程序客户端和服务器端交互的原理入手,终于找到了我要的答案. 1. 对象序列化是什么东东? 简单地说,Java对象列化就是要把内存中的Java对象保存下来(持久化),以便可以在网络上传输或今后

【转】使用 WebGL 进行 3D 开发,第 3 部分: 添加用户交互

转自HTML5游戏开发者社区 使用 WebGL 进行 3D 开发,第 1 部分: WebGL 简介使用 WebGL 进行 3D 开发,第 2 部分: 使用 WebGL 库以更少的编码做更多的事情使用 WebGL 进行 3D 开发,第 3 部分: 添加用户交互 WebGL API 为 JavaScript 开发人员提供了直接利用当今的 PC 和移动设备硬件中的强大内置 3D 图形加速功能的能力.现代浏览器已经明确支持 WebGL,WebGL 使得人们可以为主流 Web 用户创建高性能的 3D 游戏

[转]HTTP报文接口及客户端和服务器端交互原理

1. 协议 a. TCP/IP整体构架概述 TCP/IP协议并不完全符合OSI的七层参考模型.传统的开放式系统互连参考模型,是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务.该模型的目的是使各种硬件在相同的层次上相互通信.这7层是:物理层.数据链路层.网路层.传输层.话路层.表示层和应用层.而TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求.这4层分别为: i. 应用层:应用程序间沟通的层,如超文本传送协议(HTTP).简单电子邮件传输(

Python学习笔记一:第一个Python程序,变量,字符编码与二进制,用户交互程序

第一个python程序 Windows:设置环境变量,X:\pthonxxx,xxx是版本号 在命令提示符下 输入python,进入解释器 >>>print("Hello World!") >>>exit() 编辑文件helloworld.py 执行:python helloworld.py Linux:./helloworld.py   声明解释器:#!/usr/bin/env python  在环境变量中找python Chmod 755 hel

Cocos2d-x 系列七之用户交互

如同android中的用户交互,cocos2d-x通常也需要对一些用户点击.触摸事件进行监听: 一. 简单触摸事件 auto listener = EventListenerTouchAllAtOnce::create(); listener->onTouchesBegan = [](const std::vector<Touch*>&, Event*) { log("onTouchesBegan"); }; listener->onTouchesMov

Python基础知识-用户交互和运算符

今日学习内容 用户交互 用户交互就是人向机器发出指令,机器分析处理后,给人们返回操作结果(装13的说法).直白地讲,就是人往计算机中输入(input)数据,计算机输出(output)结果.交互的本质就是输入.输出. input() 输入 在python 3.* 的版本中,input() 接收到输入的任何信息,都会以字符串的形式存储 name = input("请输入您的用户名:") print(name) print(type(name)) age = input("请输入您

python变量及用户交互,用户名格式化输出

变量 name = wwjun Name2 = "wwjun" print ("name,Name2") 用户交互 Username = input ("username:") Password = input ("password:") Print(username,password) 用户名格式化输出 name = input ("name:") age = input ("age:"

python-FIrst1--变量赋值-注释-用户交互-条件判断与缩进

变量与赋值 name='mike'          #这里一定要注意,如果右边的值不是数字,就一定要加引号,否则系统会认为右边也是一个变量,而右边我们希望是一个值,所以这时候我们就需要给右边加上单引号或者双引号,以表示右边是一个字符串. age=39 把右边的值赋予左边,就是赋值,左边的name和age就叫做变量. 注释 可以用#符号来表示,也可以用一对三个连续的单引号和双引号来表示多行注释,当要注释的内容不多的时候用#比较方便,当要注释很多行内容尤其是超过三行的时候最好用,一对 三个单引号或