[ cocos2d-x ] -JNIによるJava連携-

cocos2d-xでスマートフォンのアプリを作成していると
ネイティブ側(※1)でしか行えない処理を実装したいと思った方もいると思います。
※1.ここでは各アプリを作成するために使用するObjective-C,Javaのことを指します。

cocos2d-xは2Dに特化したゲームエンジンです。
アニメーションやアクション等の描画に関する便利な関数は多数ありますが
上記に記したようなことを行う場合は
cocos2dからネイティブ側に命令し処理を実行するという流れになります。

Objective-CとC++間の連携は比較的簡単に行うことが出来るのですが
JavaとC++を連携されるためには、JNI(※2)というAPIを使用する必要があります。
※2.Java Native Interface

文頭で「ネイティブ側でしか行えない処理」と表記しましたが
具体的には以下のようなものがあります。

・カメラ機能
・SNS連携
・ブラウザの起動
・課金処理 等

本記事からは、この中にあるカメラ機能を使用することを目的とし
数回に分けてJNIの簡単なご紹介をしたいと思います。

まずは、C/C++(cocos2d-x)からJavaを呼ぶためのファイルの用意です。

Link2Java.cppとLink2Java.hを作成します。
※ファイル名・クラス名はお好きに決めてください。

Link2Java.h

#ifndef __LINK_2_JAVA__
#define __LINK_2_JAVA__

using namespace cocos2d;
 
class Link2Java
{
	public:
    	static void C2JavaEvent();
};

Link2Java.cpp

#include "Link2Java.h"
#include "platform/android/jni/JniHelper.h"
#include <jni.h>
 
// 呼び出し先のメソッドを記載しているパッケージ名とクラス名をdefineで定義しておく
#define CLASS_NAME "com/test/test/JNItest"
 
void Link2Java::C2JavaEvent()
{
    JniMethodInfo methodInfo;

    // クラス名とメソッド名を指定
    if (JniHelper::getStaticMethodInfo(methodInfo, CLASS_NAME, "C2JavaEvent", "()V")) {

    	//Java側のメソッドを実行する
        methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);

		//開放
        methodInfo.env->DeleteLocalRef(methodInfo.classID);
    }
}

今回はカメラを起動するだけのサンプルのため
戻り値なし(void)の関数を呼ぶ処理です。

呼び出す先のJava関数がstaticのため getStaticMethodInfo を使用します。

CLASS_NAME 呼び出す先のクラス名を指定。
C2JavaEvent 呼び出す先のメソッド名を指定。
()V 戻り値を指定。今回は戻り値がない為、括弧のなかは空。

上記の処理により、呼び出し先のメソッド情報をを取得でき
その情報を引数にして CallStaticVoidMethod によってJava側のメソッドを実行します。

戻り値がvoidではない場合、Java側のメソッドを呼ぶ関数は変わってきます。
例えば、Int型の値を返すメソッドの場合は CallStaticIntMethod になる。
またこの場合、getStaticMethodInfoの戻り値の指定は
戻り値無しであった場合では “()V” であったものが
Int型の戻り値があるメソッドの取得の際には “()I” になるなど
多少変わる部分があるので、使用する関数によって使い分けが必要です。

それでは、上記の実装をHelloWorldに実装します。

尚、デフォルトの状態で実装されている、cocos2d-x画像のSpriteやラベル等は
今回のカメラアプリでは使用しないので、処理を削除しています。

CCMenuだけは、コールバック関数まで用意されていますから
せっかくですので「メニューが押された場合にカメラを起動する」
というプログラムを作ることにします。

HelloWorldScene.cpp


#include "HelloWorldScene.h"

USING_NS_CC;

CCScene* HelloWorld::scene()
{
    CCScene *scene = CCScene::create();
    
    HelloWorld *layer = HelloWorld::create();

    scene->addChild(layer);

    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    if ( !CCLayer::init() )
    {
        return false;
    }
    
    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
    CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();

    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                                        "CloseNormal.png",
                                        "CloseSelected.png",
                                        this,
                                        menu_selector(HelloWorld::menuCloseCallback));
    
	pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
                                origin.y + pCloseItem->getContentSize().height/2));

    CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
    pMenu->setPosition(CCPointZero);
    this->addChild(pMenu, 1);
    
    return true;
}

void HelloWorld::menuCloseCallback(CCObject* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)

#elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
	
	/* Javaメソッドを呼ぶ処理を記載する
	   本記事では未だ、実装はしません。 */
		
#endif
}

以上で、C++からJavaの呼び方の説明は終了となります。

<次回以降の更新について>
次回は、C++の呼び先であるJava側の実装のほうをご紹介します。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*