急 Cocos2d-xの処理をAndroidとiOSで分ける LuaとJava/Objective-Cの間で関数を呼び出す

#目次
1 はじめに
2 AndroidとiOSの場合で処理を分ける
3 LuaからJavaやObjective-CのAPIを呼ぶ
4 JavaやObjective-CからLuaの関数を呼ぶ
5 今後の予定

#はじめに
本記事は、cocos2d-xおよびCocos Code IDEを導入し、AndroidやiPhoneの実機端末で動かした人で、Android、iOSといったプラットフォーム毎に処理を分けたい人向けの、覚書きです。例えば3rdパーティのランキングサービスとの結合で、AndroidとiOSでAPIが異なっており、Luaからは直接アクセスできない場合に有効です。

#AndroidとiOSでLuaの処理を分岐する

```GameScene.lua
...             
                if cc.Application:getInstance():getTargetPlatform() == cc.PLATFORM_OS_ANDROID then
                    -- Androidの場合の処理をここに書く

                elseif cc.Application:getInstance():getTargetPlatform() == cc.PLATFORM_OS_IPHONE or 
                    cc.Application:getInstance():getTargetPlatform() == cc.PLATFORM_OS_IPAD then
                    -- iOS(iPhone、iPad)の場合の処理をここに書く

                end
...
```

#LuaからJavaやObjective-CのAPIを呼ぶ

Cocos Code IDE

```GameScene.lua
... 
                -- 
                self.point = 100
                
                -- Androidの場合
                if cc.Application:getInstance():getTargetPlatform() == cc.PLATFORM_OS_ANDROID then
                    -- Lua->Javaブリッジのライブラリを読み込む
                    local luaj = require "src/cocos/cocos2d/luaj"
                    -- 呼び出す対象のJava関数が記述されているクラスを設定
                    local className = "org/cocos2dx/lua/AppActivity"
                    -- 対象のJava関数へ渡す引数データを設定
                    local args ={ self.point }
                    -- 呼び出すJava関数名を指定して、(I)整数型引数、V戻り値なしで呼び出す
                    luaj.callStaticMethod(className, "setScoreJava", args, '(I)V')
                
                -- iOS(iPhone、iPad)の場合
                elseif cc.Application:getInstance():getTargetPlatform() == cc.PLATFORM_OS_IPHONE or 
                    cc.Application:getInstance():getTargetPlatform() == cc.PLATFORM_OS_IPAD then
                    -- Lua->Objective-Cブリッジのライブラリを読み込む                    
                    local luaoc = require "src/cocos/cocos2d/luaoc"
                    -- 対象のObjC関数へ渡す引数データを設定
                    local args = { score = self.point }
                    -- 呼び出すObjC関数名を指定して呼び出す
                    luaoc.callStaticMethod("AppController", "setScoreObjC", args ) 
                end
...
```

(Lua→)Android Java

![9-1 AppActivity.png](https://qiita-image-store.s3.amazonaws.com/0/90495/b0cd8c75-fc9e-d8d7-a090-583fd07dd79a.png)

```AppActivity.java
...
import org.cocos2dx.lib.Cocos2dxLuaJavaBridge;
...
public class AppActivity extends Cocos2dxActivity{
...
	public static void setScoreJava(final int type) {
             //call 3rd party Ranking API here, but do not forget runOnUiThread IF running into UI thread 
	}
}
```

(Lua→)iOS ObjC

```AppController.h
...
// Cocos2dxからコールされる関数
+ (void)setScoreObjC:(NSDictionary *)dict;
...
```

```AppController.mm
...
+ (void)setScoreObjC:(NSDictionary *)dict{
    if ([dict objectForKey:@"score"])
    {
        int input = [[dict objectForKey:@"score"] intValue];
        //call 3rd party Ranking API here
    }
}
...
```

#JavaやObjective-CからLuaの関数を呼ぶ

Cocos Code IDE

```GameScene.lua
...
    -- Java/ObjCからカスタムイベントを使って呼び出される
    local listener = cc.EventListenerCustom:create("callLuaFunc",
        function(event)
            ...
        end)
    local eventDispatcher = layer:getEventDispatcher()
    eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
...

-- Javaから呼び出されるグローバルなLua関数
function callLuaFunc(param)
    local evt = cc.EventCustom:new("callLuaFunc")
    cc.Director:getInstance():getEventDispatcher():dispatchEvent(evt)
end

return GameScene
```

Android Java(→Lua)

```AppActivity.java
// Java->Lua
Cocos2dxLuaJavaBridge.callLuaGlobalFunctionWithString("callLuaFunc", "callLuaFunc");
```

iOS ObjC(→Lua)

```AppController.mm
// ObjC->Lua
cocos2d::Director::getInstance()->getEventDispatcher()->dispatchCustomEvent("callLuaFunc");
```

#今後の予定
ミニゲームで使える初期化、ゲーム開始、ゲームオーバー、再開といった状態変化の実装について説明します。