Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-xの深層
2016/08/24 @ CEDEC 2016
久富⽊ 隆⼀ (KUBUKI Ryuichi)
Cocos2d-x組み込みによる
ピュアAndroid/iOSアプリの
外科⼿術的統合
Copyright © GREE, Inc. All Rights Reserved.
本⽇お話する内容
2
1.  ⾃⼰紹介
2.  前提の共有: Cocos2d-xとは何か
3.  Android/iOSクライアント統合という問題
-  2-1. 問題の状況と⽬指すべきゴール
-  2-2. 統合案の検討と採⽤案
4.  Cocos2d-x組み込みによるクライアント統合
-  3-1. Android/iOSアプリの構造
-  3-2. Cocos2d-xのAndroid/iOS実装の構造
-  3-3. Cocos2d-x組み込みの技術的詳細
-  3-4. これからのCocos2d-x
5.  総括
Copyright © GREE, Inc. All Rights Reserved.
⾃⼰紹介
3
• 久富⽊ 隆⼀ (KUBUKI Ryuichi)
• グリー株式会社
• West Game事業本部
GREE International Entertainment(⽶国サ
ンフランシスコ)等、海外ゲーム事業を担当
Copyright © GREE, Inc. All Rights Reserved.
⾃⼰紹介
4
Crime City
•  Android / iOS
•  2011-
•  Over tens of millions
download globally
Modern War
•  Android / iOS
•  2011-
•  Over tens of millions
download globally
Copyright © GREE, Inc. All Rights Reserved.
⾃⼰紹介
5
• 久富⽊ 隆⼀ (KUBUKI Ryuichi)
Twitter: @ryukbk
『ゲームアプリの数学
Unityで学ぶ基礎からシェーダーまで』
(SBクリエイティブ刊)
•  リアルタイム3Dグラフィックスを成
り⽴たせている数学要素をUnityサン
プルプロジェクト付きで解説
•  OpenGL ESレンダリングパイプライ
ンやGPUアーキテクチャー、モバイ
ル向け最適化も紹介
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-xとは何か
6
•  Cocos2d
•  iOS向けの2Dゲームエンジン(Objective-C,
Ricardo Quesada, 2008)
•  Cocos2d-x
•  Cocos2dのAPIを保持しつつAndroid/
Windows向けに移植(C++, Zhe Wang,
2010)
•  Cocos2d-xの現在
•  Cocos2d作者も合流した主流となり、APIを独
⾃発展。中国Chukong Technologiesを主な
⽀援者としてオープンソース開発中
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-xとは何か
7
•  Cocos2d-xは完全にオープンソース
•  Unityは完全にオープンソースではない
•  Cocos2d-xは完全無料
•  Unity、Unreal Engineは有料
メリット
デメリット
•  Cocos2d-xにはベンダーサポートはない(コミュ
ニティはある)
•  3Dや開発環境など発展途上
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
8
Crime City
•  Android / iOS
•  2011-
Modern War
•  Android / iOS
•  2011-
•  iOS/Androidクライアントを、別々のチーム
がそれぞれ独⽴して開発(ピュアObj-C/Java)
•  通信するサーバー、スタティックデータ(マ
スターデータ)は共通
•  それ以外(ビュー/UI、ロジック)は全てプ
ラットフォーム別に独⾃実装
状況把握
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
9
• 問題1: 同じゲームの複数の実装
• ⾞輪の再発明
• Android/iOS開発者が別個にい
るためヘッドカウントが2倍
• Android/iOS実装間での⾒た⽬
や挙動の差異
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
10
• 問題2: データ駆動ではないデザイ
ンパイプライン
• エンジニアがUIやアニメーショ
ンの調整を実施
• エンジニアがステート遷移を
コードで実装
• スタティックデータの変更以外
エンジニアの助⼒なしに⾏えな
い
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
11
•  問題3: 将来にわたって安⼼(future-proof)
ではないレガシーアーキテクチャー
•  描画がOpenGL ES 1.1に留まる
•  新OSバージョンへの対応コスト
•  3D、パーティクル、物理、AIなどゲー
ムデザインに影響を与える技術要素の追
加困難
•  Objective-CはSwiftに取って代わられる
•  開発者を探しにくい
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
12
1.  同じゲームの複数の実装
2.  データ駆動ではないデザイ
ンパイプライン
3.  将来にわたって安⼼
(future-proof)ではないレ
ガシーアーキテクチャー
問題
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
13
よし、Android/iOSで
分かれているクライア
ントを1つに統合しよ
う!
結論
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
14
1.  単⼀の実装への統合
•  Write Once, Run Everywhere
•  ユニットテスト/テスト⾃動化が楽
2.  データ駆動デザインパイプライン
•  エンジニアリングリソースがボトルネックと
ならない
3.  将来にわたって安⼼(future-proof)なアー
キテクチャー
•  ⼀般的なゲームエンジンの最新版を利⽤
•  既に流通しているソフトウェアコンポーネン
トの再利⽤
ゴール
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
15
1. なるべく早期のローンチを
2. なるべく移⾏をスムースに
3. なるべく低い⾦銭的コストで
4. なるべく低い開発者教育コストで
5. サーバーとスタティックデータは
現在のものを流⽤
6. オリジナルの⾒た⽬を踏襲
現実的な追加要件
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
16
1. 保守的な案
•  現実的、低リスク、地味、
コード駆動、旧式
2. ⾰新的な案
•  理想的、⾼リスク、派⼿、
データ駆動、モダン
2つの案
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
17
•  今回のゲーム(既存アプリ)内に、スク
リプトエンジン等を組み込むのと同様
に、Cocos2d-xゲームエンジンをまる
ごと組み込み(embed)
•  新フィーチャーのみCocos2d-xで開発
•  既存アプリのコードを原則再利⽤し、
必要に応じてCocos2d-x部分へ漸次移
植
保守的な案
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
18
1.  単⼀の実装への統合
•  C++でAndroid/iOS向けに実装できる
•  ただし既存アプリ部分とのブリッジAPIを実装
するコードは複雑になる
•  ただし既存コード(Obj-C/Java)のメインテナ
ンスは必要
2.  データ駆動デザインパイプライン
•  Cocos Studio/Cocos Creatorが使える
3.  将来にわたって安⼼(future-proof)なアー
キテクチャー
•  最新のオープンソースゲームエンジン
保守的な案(Cocos2d-x組み込み)
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
19
•  Unityへ移植
•  現在のサーバー&スタティックデータ
&アセットデータとの互換性を持つク
リーン実装
•  課⾦や通知など再実装/再検証コスト
が⾼い部分のみ既存アプリ実装をネイ
ティブプラグイン化して再利⽤
•  データ駆動デザインを促進するUnity
アセットの利⽤
⾰新的な案
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
20
1.  単⼀の実装への統合
•  C#でAndroid/iOS向けに実装できる
2.  データ駆動デザインパイプライン
•  Unity Editor中⼼の開発
•  MarkUX: XMLによるMVVMでUI作成
•  NodeCanvas: Behaviour TreeやHierarchical
State Machineで状態遷移作成
3.  将来にわたって安⼼(future-proof)なアー
キテクチャー
•  最新のトレンドを押さえたゲームエンジン
⾰新的な案(Unity移植)
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
21
•  保守的な案(Cocos2d-x組み込み)と
⾰新的な案(Unity移植)を3つのゴー
ルの達成度で⽐較した場合、⾰新的
な案の⽅が優位となった
•  しかし、追加的要件も勘案すると、
保守的な案(Cocos2d-x組み込み)が
優位となったため、今回はそちらを
採⽤した
採⽤案
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
22
1.  なるべく早期のローンチを
2.  なるべく移⾏をスムースに
3.  なるべく低い⾦銭的コストで
4.  なるべく低い開発者教育コストで
5.  サーバーとスタティックデータは現在のものを
流⽤
6.  オリジナルの⾒た⽬を踏襲
Cocos2d-x組み込みはこれらの要件を満たす
1: (Cocos2d-x組み込みの技術さえ確⽴できれば)移植より早く済む。
2/5/6: 既存部分の流⽤が多いので問題が少ない。
3: Cocos2d-xは無料である。
4: 偶然今回のプロジェクトチームではCocos2d-x経験者が多かったので
問題とならなかった。
Copyright © GREE, Inc. All Rights Reserved.
Android/iOSクライアント統合という問題
23
•  Unityのネイティブプラグインは独
⾃描画を⾏えるため、既存アプリ部
分をまるごとネイティブプラグイン
化することも考えられる
•  しかし、Unity側に変更を加える必
要が出てくる可能性、既存アプリ部
分のビルドシステムとの親和性を考
え、今回は⾒送った
Unityへの既存アプリの組み込みはできないのか
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
24
•  いきなり実装の詳細に⼊って⾏く前に、全体の
⼤まかな構造をイメージし、何ができそうかを
構想してみよう
•  Cocos2d-x組み込みを思いついたのは、
Cocos2d-xの内部実装に⾃分が通暁していたか
らではなく、⼀般的なアプリを構成するゲーム
エンジンなら必ず⼀定の構造を内包しているは
ずなのでそれを再利⽤してやればよい、という
想定が⾃分の中にあったから
•  ソースコードがある以上どうにでもなるという
楽観があった(OSの仕様に阻まれないかぎりは)
実装の詳細を追う前に
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
25
•  単純化して考えると、アプリは4つの要
素から成⽴している
1.  イベントループ
2.  ロジック
3.  GLビュー
4.  ネイティブUIウィジェットビュー
アプリの抽象的構造
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
26
•  常に動作しているイベントループが必要に応じて
異なるユーザー定義ロジック(Java/Obj-C)を実⾏
•  結果を、ネイティブUIウィジェットビュー(OS固
有のダイアログなどのUIウィジェット表⽰)、また
はアプリが独⾃にOpenGL ESでカスタム描画する
GLビューへ出⼒
アプリの抽象的構造
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
27
•  常に動作しているイベントループが必要
に応じて異なるユーザー定義ロジック(C
++)を実⾏し、実⾏結果を、アプリが独
⾃にOpenGL ESで描画するGLビューへ
反映
Cocos2d-xの抽象的構造
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
28
•  Cocos2d-xのGLビューが最前⾯に描
画される
Cocos2d-xを組み込んだアプリ構造の完成形
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
29
•  UIView(とCALayer)の階層にGLビューを含む全
てのビューは属する
•  Objective-C⾔語は、ファイル拡張⼦を.mか
ら.mmにするとObjective-C++としてCだけで
はなくC++コードを混ぜることができる
•  Obj-Cの世界とC++の世界のメモリ空間は単⼀
•  Obj-C - C++ - Obj-CまたはC++ - Obj-C - C
++の呼び出しとコールバック実⾏による処理継
続は、同期で、同じスタックフレーム上で起こ
る
•  メタファー: iOSアプリの世界は、モノリシック
(⼀枚岩)な世界である
iOSアプリの特性
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
30
•  1つのアプリが複数のActivityを内包する
•  Activityは複数のFragmentを内包する
•  ActivityはWindowとViewの階層を持つ
•  ViewはGLビューであるGLSurfaceViewを含む
•  Activity同⼠はIntentで通信しあう
•  Activityが存在するJavaの世界(JVM)と、Linuxネイ
ティブのC/C++の世界(NDK)のメモリ空間は、分離さ
れており、越境(JNI)のコストは⾼い
•  Java - C++ - JavaまたはC++ - Java - C++の呼び
出しとコールバック実⾏による処理継続は、⾮同期で、
異なるスタックフレーム/スレッド上で起こる
•  メタファー: Androidの世界は、分散オブジェクト/
メッセージパッシング/疎結合マイクロサービスの世界
である
Androidアプリの特性
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
31
•  Cocos2d-x⾃⾝は、これまで⾒てきた両プラット
フォームの特性を利⽤しつつ差異を吸収する形で
実装してある
•  Cocos2d-xは、他アプリに組み込まれることを想
定した構造にはなっていないはず
•  であれば、今回やるべきことの中⼼は2つ
1.  既存アプリとCocos2d-xとのブリッジコード
を実装してやる
2.  Cocos2d-xのAndroid/iOS実装が他アプリの
存在を想定していない構造になっている部分
にパッチを適⽤(実際はほんの少しで済んだ)
Cocos2d-xのAndroid/iOS実装と組み込み
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
32
1.  (AppDelegateはstatic変数領域に起動時
⽣成)
2.  AppController#
didFinishLaunchingWithOptionsでGL
ビューであるCCEAGLViewを⽣成
3.  作成したGLビューをRootViewController
でビュー階層内に追加
4.  Cocos2d-x側からGLビューに描画を⾏う
GLViewオブジェクトを⽣成
Cocos2d-xのiOS実装の起動フロー
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
33
1.  Java: Cocos2dxActivityを⽣成
2.  C++: platform/android下のjavaactivity-
android.cppをJNIで呼び出し、Cocos2d-xア
プリケーション本体であるAppDelegateをヒー
プ領域に⽣成
3.  Java: GLビューであるGLSurfaceViewを⽣成
4.  Java: Cocos2dxRendererを⽣成
5.  C++: javaactivity-android.cppを呼んで、
Cocos2d-x側からGLビューに描画を⾏う
GLViewImplを⽣成
Cocos2d-xのAndroid実装の起動フロー
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
34
1.  既存アプリ内からCocos2d-xを起動してシーンを
作成し、全画⾯/モーダルダイアログとして表⽰
•  シーン属性情報(例えばCocos2d-xダイアログの表⽰
サイズ)はJava/Obj-C側ではなくCocos2d-x側で持つ
2.  複数回表⽰を反復しても問題ないこと(冪等性)
3.  アプリ起動直後からCocos2d-xオブジェクト
(AppDelegate)がC++側に存在すること
4.  パフォーマンス低下を防ぐこと(速度/占有メモ
リ/占有ストレージサイズ)
5.  Cocos2d-xと既存アプリのモジュールを混在させ
た単⼀バイナリを⽣成するビルドプロジェクトを
構成
Cocos2d-x組み込み要件
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
35
1. 既存アプリ側からCocos2d-xを
起動し指定したシーンを表⽰
2. Cocos2d-xから既存アプリ側の
Android/iOSネイティブ機能を
クロスプラットフォームの同じ
インターフェイスで利⽤するた
めのAPI
Cocos2d-x組み込みのために実装する機能
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
36
•  iOSアプリの中からのCocos2d-x起動は、
Cocos2d-x⾃体のiOS実装同様に、シンプル
•  Cocos2d-x起動フローと同様のGLビュー⽣成を、
既存アプリ内でCocos2d-xを起動したい場所から
呼び出すだけ
•  GLビューをどの位置にどのサイズで⽣成するか
という点のみ解決できればよい
•  [UIScreen mainScreen].applicationFrameで取得し
た画⾯サイズ(iOS 7以前はw/hが逆なので注意)と、
Cocos2d-xシーン側に設定したシーンサイズを使う
•  Obj-C++なので既存アプリからCocos2d-x側の関数
を簡単に呼び出せる
組み込みCocos2d-x起動: iOS
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
37
•  Cocos2d-xのAndroid版はActivity(Cocos2dxActivity)
として実装されているため、継承したクラスを作成し
挙動をオーバーライド。「アプリ起動直後から
AppDelegateがC++側に存在すること」という要件を
満たすために、起動直後に⽣成されるメインActivityと
してそのクラスを指定
•  Cocos2d-xのライブラリ(libcocos2dcpp.so)をロード
し、C++側のメモリ空間にAppDelegateとGLViewが
⽣成されたら、C++側からJavaのCocos2dxActivity継
承クラス側にメッセージを送り、既存アプリのActivity
を起動して、既存アプリ起動プロセスを続⾏
•  既存アプリActivityの中からCocos2d-xのActivityを起
動する
•  異種システム間でどのようにメッセージを送る?
組み込みCocos2d-x起動: Android
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
38
•  Cocos2d-x側と既存アプリ側とのブリッジAPIの
仕様を考える
•  iOS側はモノリシックな構造だがAndroid側は分
散・疎結合の構造。両⽅を抽象化し単⼀のAPIで
制御するためには制限が⼤きい⽅に合わせるべき
•  Android側の、メモリ空間が別れた⾮同期通信
モデルを基準とする
•  Cocos2d-xシーンが主体となり、離れた世界(既
存アプリ側)のリソースをC++コードで制御する
ための、RPC(remote procedure call:遠隔関数
呼出)の仕組みが要る
Cocos2d-x側と既存アプリの通信
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
39
•  Android
•  JNI(Java Native Interface)で通信
•  API呼び出し時にstd::function/ラムダ式のコール
バックを、boost::uuidで⽣成したUUIDをキーとして
マップへ登録。既存アプリ側は受け取っていたUUID
を返事を返す際に添えて返し、Cocos2d-x側は対応
コールバックを実⾏
•  iOS
•  Cocos2d-x -> 既存アプリ: Obj-C++のファイルにC
の関数を定義し、externで参照し呼び出し
•  既存アプリ -> Cocos2d-x: std::functionで渡された
コールバック関数を直接実⾏
Cocos2d-x側から既存アプリへのRPC
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
40
•  宣⾔: std::functionにコールバックとしてラムダ式を設定する
Cocos2d-x側から既存アプリへのRPC
•  実⾏: サーバーから返事が来るとラムダ式が実⾏される
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
41
•  iOS
•  同じメモリー空間でC/C++の型が共通で存在してい
るのでデータ型の問題は存在しない
•  Android
•  C++とJavaの世界でデータを翻訳/交換するための合
意が必要
•  任意のデータをペイロードとしてラップし変換/交換
(marshalling)するための便利なバッグがあればよい
•  今回使ったもの
•  boost::variant
using VariantValueType = boost::variant<int64_t,
double, std::string>;
•  JSON (rapidjson::Document)
RPCとデータ型
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
42
•  既存アプリ側から⽂字列でCocos2d-xシーンを指定したい
•  まずは可変⻑テンプレート引数を取れるC++テンプレー
ト(Variadic Templates)を使って、型リストの要素各々に
対してラムダ式を適⽤できるforEachを定義
⽂字列とデータ型の関連付け
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
43
•  登録しておいたシーンクラスのリストの要素に対し、RTTI
のtypeidで取得した型名⽂字列をabi::__cxa_demangle
でデマングルし、そのCocos2d-xシーンを作成する
Scene::create関数のラムダ式と関連付け(ラムダ引数の
autoはC++14)
⽂字列とデータ型の関連付け
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
44
•  単にデータのやり取りをするだけでなく、
既存アプリ側の特定メソッドを実⾏するAPI
が必要になった
•  各プラットフォームのリフレクションの仕
組みが使える
•  iOS
•  NSInvocation#invoke
•  Android
•  Method#invoke
⽂字列とコードの関連付け
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
45
1.  既存アプリ側からCocos2d-xを起動し指定した
シーンを表⽰
2.  Cocos2d-xから既存アプリ側のAndroid/iOSネイ
ティブ機能をクロスプラットフォームの同じイン
ターフェイスで利⽤するためのAPI
•  これらの要素が最低限あればアプリ⾃体は
Cocos2d-xを組み込んだ状態で動くように
なっているが、実際にはそのアプリをビル
ドするためのプロジェクトを整備しなけれ
ばならない
Cocos2d-x組み込みアプリのビルド
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
46
•  iOS
•  既存アプリのXcodeプロジェクトにCocos2d-xの
Xcodeプロジェクトcocos2d_libs.xcodeprojを⼊れる
•  ただしXcodeプロジェクトのマージが難しいので
Cocos2d-xバージョンアップのたびに同じ作業が必要
•  Android
•  既存アプリがモジュラーなgradleビルドシステムを採
⽤していたので、Cocos2d-xのAndroid Studio向けプ
ロジェクトをgradleモジュールとして差し込むことが
できる
•  ただしC++部分はcocosコマンドでビルドする必要が
ある
•  Android Studio 2のInstant Runとは相性が悪い
Cocos2d-x組み込みアプリのビルド
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
47
•  Cocos2d-xのビューを、全画⾯ではなく画⾯の1部に表⽰
•  矩形ではなく、丸みのある⾓など⾃由な形状に
•  フレームバッファーをアルファ値を持てるフォーマット
にする
•  iOS
•  CCEAGLViewでeaglLayer.opaque = NO、
pixelFormatをkEAGLColorFormatRGBA8に
•  AndroidはそのままでOK
•  Cocos2d-x側でそもそも⿊く塗りつぶしていたので透明
に替える
•  FrameBufferで_clearColor(Color4F(0, 0, 0, 0))、
Rendererで_clearColor.a = 0.0f
Cocos2d-xシーンのモーダルダイアログ表⽰
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
48
•  Cocos2d-xのActivityを表⽰していると、背後に回った既
存アプリのActivityがOSによって制御できないタイミン
グでkillされてしまう
トラブルシューティング: Android Activity問題
•  AndroidManifestで
@android:style/
Theme.Translucent.N
oTitleBar.Fullscreenを
指定し背後の既存アプ
リActivityが⾒えるよ
うにしてやればkillされ
ない(全画⾯表⽰でも)
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
49
•  HTC J Butterfly(HTV31)上でのリリースビルドのみで、
OpenGL ESのコンテクストがおかしいことによるエラー
が起こる(call to OpenGL ES API with no current context)
•  Cocos2d-xのAPIを操作しOpenGL ESコンテクストを操
作する可能性のあるJNI呼び出しは、全て
GLSurfaceView.queueEvent経由の呼び出しとして
Cocos2d-x描画⽤スレッドで実⾏されるように
•  逆に、Androidのビュー階層をJNIから操作する場合は
Handler(Looper.getMainLooper())でUIスレッドにポス
ト
•  Cocos2d-x側では、AndroidからJNIで受けたものは
performFunctionInCocosThreadで実⾏
トラブルシューティング: Androidスレッド問題
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
50
•  アプリ起動時にAppDelegateのみ初期化しているものの、
Android版Cocos2d-xは元々バックグラウンドからの復帰
時にGLSurfaceViewを再⽣成するようになっておりその
処理がCocos2d-xビューを⽣成時にも必要なため、重い
初期化処理が⾛ることにより表⽰されるまで時間がか
かっていた
•  Cocos2d-xは内部で使っているシェーダープログラムを
全て起動時に初期化しており、parseUniforms()と
glLinkProgramが特に重かった
•  3D向けなど使わないシェーダーの初期化を省略
•  今後シェーダーの利⽤時に初期化されるようになるかも
https://github.com/cocos2d/cocos2d-x/issues/15637
トラブルシューティング: Androidシェーダー問題
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
51
•  Cocos2d-xビュー作成時は既存アプリGLビューのレンダ
リングループを⽌める
•  Cocos2d-xビュー終了時には、Director::endを呼ぶと次
のフレームで呼ばれるGLViewImpl::end内で、GCDで
dispatch_asyncした先で、GLコンテクスト(今誰が描画
しているのか)を既存アプリのものに復帰
•  Cocos2d-xと既存アプリのGLコンテクストの競合は起
こっていないはずにもかかわらず、Cocos2d-xを起動し
て閉じた後、既存アプリのテクスチャーが時々乱れた
•  Cocos2d-xビュー作成前に開始されていた既存アプリの
テクスチャー⾮同期ダウンロードジョブが、ダウンロー
ド完了時(Cocos2d-x起動中)にglBindTextureなどGLの
関数を呼び出してしまっていたのでスキップするよう変
更
トラブルシューティング: iOSテクスチャー問題
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
52
•  C++ラムダ式での変数キャプチャには注意
•  サーバー通信などをCocos2d-xシーンからブリッジAPIを
経由して⾏うと、時間が経ち結果が帰ってきた時には元
のシーンが消滅しており、コールバックのラムダ式内に
キャプチャされたシーンのthisポインタが無効になってい
る場合がある
•  staticなSceneFactoryでシーン毎にUUIDを発⾏して
同⼀性を保証し、シーンが存在しない/そのシーンが
発⾏していないAPI実⾏の結果が来た時は弾く
•  参照キャプチャ(&)を使うとスタック変数がキャプチャさ
れてしまい、iOSではスレッドを分けない限り原則として
同⼀スタックフレーム上でブリッジAPIが最後まで実⾏さ
れるので問題ないが、Androidではコールバックのスタッ
クフレームが異なり無効なアドレスを参照して落ちる
トラブルシューティング: シーンライフサイクル問題
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
53
•  透明領域を少なくして描画負荷を抑えるために、
Cocos2d-xのGLビューのサイズを、Cocos2d-x
内部で⽣成するシーンのサイズと同じにして既存
アプリ側から⽣成する仕様とした
•  つまり、GLビューのサイズは端末画⾯サイズ
より多くの場合⼩さくなる
•  この仕様により、Cocos2d-x側で全画⾯表⽰した
場合に⾏ってくれるスケーリングに頼れないこと
になり、様々なAndroid/iOSデバイス向けのス
ケーリングのコードを⾃前実装することになり、
かなり⼿間になった
失敗点: ⾃前スケーリングは⾯倒
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
54
•  ここまでの⼿間を経て、ようやくCocos2d-x組み
込みは実⽤に耐える技術として確⽴する
•  しかし、Cocos2d-x⾃体も⽇々変化しており、明
⽇はまた異なるものになっているかもしれない
•  Director::getInstance()-
>getRunningScene()->getChildren().at(0)だ
とCameraが取れてしまう(現在のシーンはat(1))
•  Cocos2d-xのSceneは、Node/Layerと異なり、
Camera、BaseLight、NavMesh、
Physics3DWorldを持つ
•  Cocos2d-xは3D/VRゲームエンジンへと変容
を遂げつつある(Cocos2d-xからCocosへ)
これからのCocos2d-x
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
55
•  Cocos Studio開発終了
•  Cocos Creatorが主流に
•  Electronベースでオープンソース。Unityライ
クなビジュアル開発環境
•  Chukongは、コンソール版をキャンセルして
でも開発環境の充実を第⼀⽬標に置いている
•  (UnityがC#で開発するように)JavaScriptでの
ダイナミックな開発を推奨、C++は重い処理
を書く場合以外は使われなくなる
•  プロジェクト構成が従来と変わるので、新し
くCocosプロジェクトを起こすならCocos
Creatorベースとすべし
これからのCocos2d-x
Copyright © GREE, Inc. All Rights Reserved.
Cocos2d-x組み込みによるクライアント統合
56
•  余計な⾎は流さない
•  Cocos2d-xへのパッチは最⼩限に
•  Cocos2d-x最新版への追随更新を妨
げない
•  ゴールはあくまでアプリを活かすこと
•  UnityにCocos2d-xを組み込むことも
不可能ではない… かもしれない
•  ゲームエンジンの深層は学びの宝庫で
ある
総括: 外科⼿術の⼼得
Copyright © GREE, Inc. All Rights Reserved.
Thank You

Cocos2d-xの深層〜Cocos2d-x組み込みによるピュアAndroid/iOSアプリの外科手術的統合

  • 1.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-xの深層 2016/08/24 @ CEDEC 2016 久富⽊ 隆⼀ (KUBUKI Ryuichi) Cocos2d-x組み込みによる ピュアAndroid/iOSアプリの 外科⼿術的統合
  • 2.
    Copyright © GREE,Inc. All Rights Reserved. 本⽇お話する内容 2 1.  ⾃⼰紹介 2.  前提の共有: Cocos2d-xとは何か 3.  Android/iOSクライアント統合という問題 -  2-1. 問題の状況と⽬指すべきゴール -  2-2. 統合案の検討と採⽤案 4.  Cocos2d-x組み込みによるクライアント統合 -  3-1. Android/iOSアプリの構造 -  3-2. Cocos2d-xのAndroid/iOS実装の構造 -  3-3. Cocos2d-x組み込みの技術的詳細 -  3-4. これからのCocos2d-x 5.  総括
  • 3.
    Copyright © GREE,Inc. All Rights Reserved. ⾃⼰紹介 3 • 久富⽊ 隆⼀ (KUBUKI Ryuichi) • グリー株式会社 • West Game事業本部 GREE International Entertainment(⽶国サ ンフランシスコ)等、海外ゲーム事業を担当
  • 4.
    Copyright © GREE,Inc. All Rights Reserved. ⾃⼰紹介 4 Crime City •  Android / iOS •  2011- •  Over tens of millions download globally Modern War •  Android / iOS •  2011- •  Over tens of millions download globally
  • 5.
    Copyright © GREE,Inc. All Rights Reserved. ⾃⼰紹介 5 • 久富⽊ 隆⼀ (KUBUKI Ryuichi) Twitter: @ryukbk 『ゲームアプリの数学 Unityで学ぶ基礎からシェーダーまで』 (SBクリエイティブ刊) •  リアルタイム3Dグラフィックスを成 り⽴たせている数学要素をUnityサン プルプロジェクト付きで解説 •  OpenGL ESレンダリングパイプライ ンやGPUアーキテクチャー、モバイ ル向け最適化も紹介
  • 6.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-xとは何か 6 •  Cocos2d •  iOS向けの2Dゲームエンジン(Objective-C, Ricardo Quesada, 2008) •  Cocos2d-x •  Cocos2dのAPIを保持しつつAndroid/ Windows向けに移植(C++, Zhe Wang, 2010) •  Cocos2d-xの現在 •  Cocos2d作者も合流した主流となり、APIを独 ⾃発展。中国Chukong Technologiesを主な ⽀援者としてオープンソース開発中
  • 7.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-xとは何か 7 •  Cocos2d-xは完全にオープンソース •  Unityは完全にオープンソースではない •  Cocos2d-xは完全無料 •  Unity、Unreal Engineは有料 メリット デメリット •  Cocos2d-xにはベンダーサポートはない(コミュ ニティはある) •  3Dや開発環境など発展途上
  • 8.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 8 Crime City •  Android / iOS •  2011- Modern War •  Android / iOS •  2011- •  iOS/Androidクライアントを、別々のチーム がそれぞれ独⽴して開発(ピュアObj-C/Java) •  通信するサーバー、スタティックデータ(マ スターデータ)は共通 •  それ以外(ビュー/UI、ロジック)は全てプ ラットフォーム別に独⾃実装 状況把握
  • 9.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 9 • 問題1: 同じゲームの複数の実装 • ⾞輪の再発明 • Android/iOS開発者が別個にい るためヘッドカウントが2倍 • Android/iOS実装間での⾒た⽬ や挙動の差異
  • 10.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 10 • 問題2: データ駆動ではないデザイ ンパイプライン • エンジニアがUIやアニメーショ ンの調整を実施 • エンジニアがステート遷移を コードで実装 • スタティックデータの変更以外 エンジニアの助⼒なしに⾏えな い
  • 11.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 11 •  問題3: 将来にわたって安⼼(future-proof) ではないレガシーアーキテクチャー •  描画がOpenGL ES 1.1に留まる •  新OSバージョンへの対応コスト •  3D、パーティクル、物理、AIなどゲー ムデザインに影響を与える技術要素の追 加困難 •  Objective-CはSwiftに取って代わられる •  開発者を探しにくい
  • 12.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 12 1.  同じゲームの複数の実装 2.  データ駆動ではないデザイ ンパイプライン 3.  将来にわたって安⼼ (future-proof)ではないレ ガシーアーキテクチャー 問題
  • 13.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 13 よし、Android/iOSで 分かれているクライア ントを1つに統合しよ う! 結論
  • 14.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 14 1.  単⼀の実装への統合 •  Write Once, Run Everywhere •  ユニットテスト/テスト⾃動化が楽 2.  データ駆動デザインパイプライン •  エンジニアリングリソースがボトルネックと ならない 3.  将来にわたって安⼼(future-proof)なアー キテクチャー •  ⼀般的なゲームエンジンの最新版を利⽤ •  既に流通しているソフトウェアコンポーネン トの再利⽤ ゴール
  • 15.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 15 1. なるべく早期のローンチを 2. なるべく移⾏をスムースに 3. なるべく低い⾦銭的コストで 4. なるべく低い開発者教育コストで 5. サーバーとスタティックデータは 現在のものを流⽤ 6. オリジナルの⾒た⽬を踏襲 現実的な追加要件
  • 16.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 16 1. 保守的な案 •  現実的、低リスク、地味、 コード駆動、旧式 2. ⾰新的な案 •  理想的、⾼リスク、派⼿、 データ駆動、モダン 2つの案
  • 17.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 17 •  今回のゲーム(既存アプリ)内に、スク リプトエンジン等を組み込むのと同様 に、Cocos2d-xゲームエンジンをまる ごと組み込み(embed) •  新フィーチャーのみCocos2d-xで開発 •  既存アプリのコードを原則再利⽤し、 必要に応じてCocos2d-x部分へ漸次移 植 保守的な案
  • 18.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 18 1.  単⼀の実装への統合 •  C++でAndroid/iOS向けに実装できる •  ただし既存アプリ部分とのブリッジAPIを実装 するコードは複雑になる •  ただし既存コード(Obj-C/Java)のメインテナ ンスは必要 2.  データ駆動デザインパイプライン •  Cocos Studio/Cocos Creatorが使える 3.  将来にわたって安⼼(future-proof)なアー キテクチャー •  最新のオープンソースゲームエンジン 保守的な案(Cocos2d-x組み込み)
  • 19.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 19 •  Unityへ移植 •  現在のサーバー&スタティックデータ &アセットデータとの互換性を持つク リーン実装 •  課⾦や通知など再実装/再検証コスト が⾼い部分のみ既存アプリ実装をネイ ティブプラグイン化して再利⽤ •  データ駆動デザインを促進するUnity アセットの利⽤ ⾰新的な案
  • 20.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 20 1.  単⼀の実装への統合 •  C#でAndroid/iOS向けに実装できる 2.  データ駆動デザインパイプライン •  Unity Editor中⼼の開発 •  MarkUX: XMLによるMVVMでUI作成 •  NodeCanvas: Behaviour TreeやHierarchical State Machineで状態遷移作成 3.  将来にわたって安⼼(future-proof)なアー キテクチャー •  最新のトレンドを押さえたゲームエンジン ⾰新的な案(Unity移植)
  • 21.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 21 •  保守的な案(Cocos2d-x組み込み)と ⾰新的な案(Unity移植)を3つのゴー ルの達成度で⽐較した場合、⾰新的 な案の⽅が優位となった •  しかし、追加的要件も勘案すると、 保守的な案(Cocos2d-x組み込み)が 優位となったため、今回はそちらを 採⽤した 採⽤案
  • 22.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 22 1.  なるべく早期のローンチを 2.  なるべく移⾏をスムースに 3.  なるべく低い⾦銭的コストで 4.  なるべく低い開発者教育コストで 5.  サーバーとスタティックデータは現在のものを 流⽤ 6.  オリジナルの⾒た⽬を踏襲 Cocos2d-x組み込みはこれらの要件を満たす 1: (Cocos2d-x組み込みの技術さえ確⽴できれば)移植より早く済む。 2/5/6: 既存部分の流⽤が多いので問題が少ない。 3: Cocos2d-xは無料である。 4: 偶然今回のプロジェクトチームではCocos2d-x経験者が多かったので 問題とならなかった。
  • 23.
    Copyright © GREE,Inc. All Rights Reserved. Android/iOSクライアント統合という問題 23 •  Unityのネイティブプラグインは独 ⾃描画を⾏えるため、既存アプリ部 分をまるごとネイティブプラグイン 化することも考えられる •  しかし、Unity側に変更を加える必 要が出てくる可能性、既存アプリ部 分のビルドシステムとの親和性を考 え、今回は⾒送った Unityへの既存アプリの組み込みはできないのか
  • 24.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 24 •  いきなり実装の詳細に⼊って⾏く前に、全体の ⼤まかな構造をイメージし、何ができそうかを 構想してみよう •  Cocos2d-x組み込みを思いついたのは、 Cocos2d-xの内部実装に⾃分が通暁していたか らではなく、⼀般的なアプリを構成するゲーム エンジンなら必ず⼀定の構造を内包しているは ずなのでそれを再利⽤してやればよい、という 想定が⾃分の中にあったから •  ソースコードがある以上どうにでもなるという 楽観があった(OSの仕様に阻まれないかぎりは) 実装の詳細を追う前に
  • 25.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 25 •  単純化して考えると、アプリは4つの要 素から成⽴している 1.  イベントループ 2.  ロジック 3.  GLビュー 4.  ネイティブUIウィジェットビュー アプリの抽象的構造
  • 26.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 26 •  常に動作しているイベントループが必要に応じて 異なるユーザー定義ロジック(Java/Obj-C)を実⾏ •  結果を、ネイティブUIウィジェットビュー(OS固 有のダイアログなどのUIウィジェット表⽰)、また はアプリが独⾃にOpenGL ESでカスタム描画する GLビューへ出⼒ アプリの抽象的構造
  • 27.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 27 •  常に動作しているイベントループが必要 に応じて異なるユーザー定義ロジック(C ++)を実⾏し、実⾏結果を、アプリが独 ⾃にOpenGL ESで描画するGLビューへ 反映 Cocos2d-xの抽象的構造
  • 28.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 28 •  Cocos2d-xのGLビューが最前⾯に描 画される Cocos2d-xを組み込んだアプリ構造の完成形
  • 29.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 29 •  UIView(とCALayer)の階層にGLビューを含む全 てのビューは属する •  Objective-C⾔語は、ファイル拡張⼦を.mか ら.mmにするとObjective-C++としてCだけで はなくC++コードを混ぜることができる •  Obj-Cの世界とC++の世界のメモリ空間は単⼀ •  Obj-C - C++ - Obj-CまたはC++ - Obj-C - C ++の呼び出しとコールバック実⾏による処理継 続は、同期で、同じスタックフレーム上で起こ る •  メタファー: iOSアプリの世界は、モノリシック (⼀枚岩)な世界である iOSアプリの特性
  • 30.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 30 •  1つのアプリが複数のActivityを内包する •  Activityは複数のFragmentを内包する •  ActivityはWindowとViewの階層を持つ •  ViewはGLビューであるGLSurfaceViewを含む •  Activity同⼠はIntentで通信しあう •  Activityが存在するJavaの世界(JVM)と、Linuxネイ ティブのC/C++の世界(NDK)のメモリ空間は、分離さ れており、越境(JNI)のコストは⾼い •  Java - C++ - JavaまたはC++ - Java - C++の呼び 出しとコールバック実⾏による処理継続は、⾮同期で、 異なるスタックフレーム/スレッド上で起こる •  メタファー: Androidの世界は、分散オブジェクト/ メッセージパッシング/疎結合マイクロサービスの世界 である Androidアプリの特性
  • 31.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 31 •  Cocos2d-x⾃⾝は、これまで⾒てきた両プラット フォームの特性を利⽤しつつ差異を吸収する形で 実装してある •  Cocos2d-xは、他アプリに組み込まれることを想 定した構造にはなっていないはず •  であれば、今回やるべきことの中⼼は2つ 1.  既存アプリとCocos2d-xとのブリッジコード を実装してやる 2.  Cocos2d-xのAndroid/iOS実装が他アプリの 存在を想定していない構造になっている部分 にパッチを適⽤(実際はほんの少しで済んだ) Cocos2d-xのAndroid/iOS実装と組み込み
  • 32.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 32 1.  (AppDelegateはstatic変数領域に起動時 ⽣成) 2.  AppController# didFinishLaunchingWithOptionsでGL ビューであるCCEAGLViewを⽣成 3.  作成したGLビューをRootViewController でビュー階層内に追加 4.  Cocos2d-x側からGLビューに描画を⾏う GLViewオブジェクトを⽣成 Cocos2d-xのiOS実装の起動フロー
  • 33.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 33 1.  Java: Cocos2dxActivityを⽣成 2.  C++: platform/android下のjavaactivity- android.cppをJNIで呼び出し、Cocos2d-xア プリケーション本体であるAppDelegateをヒー プ領域に⽣成 3.  Java: GLビューであるGLSurfaceViewを⽣成 4.  Java: Cocos2dxRendererを⽣成 5.  C++: javaactivity-android.cppを呼んで、 Cocos2d-x側からGLビューに描画を⾏う GLViewImplを⽣成 Cocos2d-xのAndroid実装の起動フロー
  • 34.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 34 1.  既存アプリ内からCocos2d-xを起動してシーンを 作成し、全画⾯/モーダルダイアログとして表⽰ •  シーン属性情報(例えばCocos2d-xダイアログの表⽰ サイズ)はJava/Obj-C側ではなくCocos2d-x側で持つ 2.  複数回表⽰を反復しても問題ないこと(冪等性) 3.  アプリ起動直後からCocos2d-xオブジェクト (AppDelegate)がC++側に存在すること 4.  パフォーマンス低下を防ぐこと(速度/占有メモ リ/占有ストレージサイズ) 5.  Cocos2d-xと既存アプリのモジュールを混在させ た単⼀バイナリを⽣成するビルドプロジェクトを 構成 Cocos2d-x組み込み要件
  • 35.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 35 1. 既存アプリ側からCocos2d-xを 起動し指定したシーンを表⽰ 2. Cocos2d-xから既存アプリ側の Android/iOSネイティブ機能を クロスプラットフォームの同じ インターフェイスで利⽤するた めのAPI Cocos2d-x組み込みのために実装する機能
  • 36.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 36 •  iOSアプリの中からのCocos2d-x起動は、 Cocos2d-x⾃体のiOS実装同様に、シンプル •  Cocos2d-x起動フローと同様のGLビュー⽣成を、 既存アプリ内でCocos2d-xを起動したい場所から 呼び出すだけ •  GLビューをどの位置にどのサイズで⽣成するか という点のみ解決できればよい •  [UIScreen mainScreen].applicationFrameで取得し た画⾯サイズ(iOS 7以前はw/hが逆なので注意)と、 Cocos2d-xシーン側に設定したシーンサイズを使う •  Obj-C++なので既存アプリからCocos2d-x側の関数 を簡単に呼び出せる 組み込みCocos2d-x起動: iOS
  • 37.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 37 •  Cocos2d-xのAndroid版はActivity(Cocos2dxActivity) として実装されているため、継承したクラスを作成し 挙動をオーバーライド。「アプリ起動直後から AppDelegateがC++側に存在すること」という要件を 満たすために、起動直後に⽣成されるメインActivityと してそのクラスを指定 •  Cocos2d-xのライブラリ(libcocos2dcpp.so)をロード し、C++側のメモリ空間にAppDelegateとGLViewが ⽣成されたら、C++側からJavaのCocos2dxActivity継 承クラス側にメッセージを送り、既存アプリのActivity を起動して、既存アプリ起動プロセスを続⾏ •  既存アプリActivityの中からCocos2d-xのActivityを起 動する •  異種システム間でどのようにメッセージを送る? 組み込みCocos2d-x起動: Android
  • 38.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 38 •  Cocos2d-x側と既存アプリ側とのブリッジAPIの 仕様を考える •  iOS側はモノリシックな構造だがAndroid側は分 散・疎結合の構造。両⽅を抽象化し単⼀のAPIで 制御するためには制限が⼤きい⽅に合わせるべき •  Android側の、メモリ空間が別れた⾮同期通信 モデルを基準とする •  Cocos2d-xシーンが主体となり、離れた世界(既 存アプリ側)のリソースをC++コードで制御する ための、RPC(remote procedure call:遠隔関数 呼出)の仕組みが要る Cocos2d-x側と既存アプリの通信
  • 39.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 39 •  Android •  JNI(Java Native Interface)で通信 •  API呼び出し時にstd::function/ラムダ式のコール バックを、boost::uuidで⽣成したUUIDをキーとして マップへ登録。既存アプリ側は受け取っていたUUID を返事を返す際に添えて返し、Cocos2d-x側は対応 コールバックを実⾏ •  iOS •  Cocos2d-x -> 既存アプリ: Obj-C++のファイルにC の関数を定義し、externで参照し呼び出し •  既存アプリ -> Cocos2d-x: std::functionで渡された コールバック関数を直接実⾏ Cocos2d-x側から既存アプリへのRPC
  • 40.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 40 •  宣⾔: std::functionにコールバックとしてラムダ式を設定する Cocos2d-x側から既存アプリへのRPC •  実⾏: サーバーから返事が来るとラムダ式が実⾏される
  • 41.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 41 •  iOS •  同じメモリー空間でC/C++の型が共通で存在してい るのでデータ型の問題は存在しない •  Android •  C++とJavaの世界でデータを翻訳/交換するための合 意が必要 •  任意のデータをペイロードとしてラップし変換/交換 (marshalling)するための便利なバッグがあればよい •  今回使ったもの •  boost::variant using VariantValueType = boost::variant<int64_t, double, std::string>; •  JSON (rapidjson::Document) RPCとデータ型
  • 42.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 42 •  既存アプリ側から⽂字列でCocos2d-xシーンを指定したい •  まずは可変⻑テンプレート引数を取れるC++テンプレー ト(Variadic Templates)を使って、型リストの要素各々に 対してラムダ式を適⽤できるforEachを定義 ⽂字列とデータ型の関連付け
  • 43.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 43 •  登録しておいたシーンクラスのリストの要素に対し、RTTI のtypeidで取得した型名⽂字列をabi::__cxa_demangle でデマングルし、そのCocos2d-xシーンを作成する Scene::create関数のラムダ式と関連付け(ラムダ引数の autoはC++14) ⽂字列とデータ型の関連付け
  • 44.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 44 •  単にデータのやり取りをするだけでなく、 既存アプリ側の特定メソッドを実⾏するAPI が必要になった •  各プラットフォームのリフレクションの仕 組みが使える •  iOS •  NSInvocation#invoke •  Android •  Method#invoke ⽂字列とコードの関連付け
  • 45.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 45 1.  既存アプリ側からCocos2d-xを起動し指定した シーンを表⽰ 2.  Cocos2d-xから既存アプリ側のAndroid/iOSネイ ティブ機能をクロスプラットフォームの同じイン ターフェイスで利⽤するためのAPI •  これらの要素が最低限あればアプリ⾃体は Cocos2d-xを組み込んだ状態で動くように なっているが、実際にはそのアプリをビル ドするためのプロジェクトを整備しなけれ ばならない Cocos2d-x組み込みアプリのビルド
  • 46.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 46 •  iOS •  既存アプリのXcodeプロジェクトにCocos2d-xの Xcodeプロジェクトcocos2d_libs.xcodeprojを⼊れる •  ただしXcodeプロジェクトのマージが難しいので Cocos2d-xバージョンアップのたびに同じ作業が必要 •  Android •  既存アプリがモジュラーなgradleビルドシステムを採 ⽤していたので、Cocos2d-xのAndroid Studio向けプ ロジェクトをgradleモジュールとして差し込むことが できる •  ただしC++部分はcocosコマンドでビルドする必要が ある •  Android Studio 2のInstant Runとは相性が悪い Cocos2d-x組み込みアプリのビルド
  • 47.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 47 •  Cocos2d-xのビューを、全画⾯ではなく画⾯の1部に表⽰ •  矩形ではなく、丸みのある⾓など⾃由な形状に •  フレームバッファーをアルファ値を持てるフォーマット にする •  iOS •  CCEAGLViewでeaglLayer.opaque = NO、 pixelFormatをkEAGLColorFormatRGBA8に •  AndroidはそのままでOK •  Cocos2d-x側でそもそも⿊く塗りつぶしていたので透明 に替える •  FrameBufferで_clearColor(Color4F(0, 0, 0, 0))、 Rendererで_clearColor.a = 0.0f Cocos2d-xシーンのモーダルダイアログ表⽰
  • 48.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 48 •  Cocos2d-xのActivityを表⽰していると、背後に回った既 存アプリのActivityがOSによって制御できないタイミン グでkillされてしまう トラブルシューティング: Android Activity問題 •  AndroidManifestで @android:style/ Theme.Translucent.N oTitleBar.Fullscreenを 指定し背後の既存アプ リActivityが⾒えるよ うにしてやればkillされ ない(全画⾯表⽰でも)
  • 49.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 49 •  HTC J Butterfly(HTV31)上でのリリースビルドのみで、 OpenGL ESのコンテクストがおかしいことによるエラー が起こる(call to OpenGL ES API with no current context) •  Cocos2d-xのAPIを操作しOpenGL ESコンテクストを操 作する可能性のあるJNI呼び出しは、全て GLSurfaceView.queueEvent経由の呼び出しとして Cocos2d-x描画⽤スレッドで実⾏されるように •  逆に、Androidのビュー階層をJNIから操作する場合は Handler(Looper.getMainLooper())でUIスレッドにポス ト •  Cocos2d-x側では、AndroidからJNIで受けたものは performFunctionInCocosThreadで実⾏ トラブルシューティング: Androidスレッド問題
  • 50.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 50 •  アプリ起動時にAppDelegateのみ初期化しているものの、 Android版Cocos2d-xは元々バックグラウンドからの復帰 時にGLSurfaceViewを再⽣成するようになっておりその 処理がCocos2d-xビューを⽣成時にも必要なため、重い 初期化処理が⾛ることにより表⽰されるまで時間がか かっていた •  Cocos2d-xは内部で使っているシェーダープログラムを 全て起動時に初期化しており、parseUniforms()と glLinkProgramが特に重かった •  3D向けなど使わないシェーダーの初期化を省略 •  今後シェーダーの利⽤時に初期化されるようになるかも https://github.com/cocos2d/cocos2d-x/issues/15637 トラブルシューティング: Androidシェーダー問題
  • 51.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 51 •  Cocos2d-xビュー作成時は既存アプリGLビューのレンダ リングループを⽌める •  Cocos2d-xビュー終了時には、Director::endを呼ぶと次 のフレームで呼ばれるGLViewImpl::end内で、GCDで dispatch_asyncした先で、GLコンテクスト(今誰が描画 しているのか)を既存アプリのものに復帰 •  Cocos2d-xと既存アプリのGLコンテクストの競合は起 こっていないはずにもかかわらず、Cocos2d-xを起動し て閉じた後、既存アプリのテクスチャーが時々乱れた •  Cocos2d-xビュー作成前に開始されていた既存アプリの テクスチャー⾮同期ダウンロードジョブが、ダウンロー ド完了時(Cocos2d-x起動中)にglBindTextureなどGLの 関数を呼び出してしまっていたのでスキップするよう変 更 トラブルシューティング: iOSテクスチャー問題
  • 52.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 52 •  C++ラムダ式での変数キャプチャには注意 •  サーバー通信などをCocos2d-xシーンからブリッジAPIを 経由して⾏うと、時間が経ち結果が帰ってきた時には元 のシーンが消滅しており、コールバックのラムダ式内に キャプチャされたシーンのthisポインタが無効になってい る場合がある •  staticなSceneFactoryでシーン毎にUUIDを発⾏して 同⼀性を保証し、シーンが存在しない/そのシーンが 発⾏していないAPI実⾏の結果が来た時は弾く •  参照キャプチャ(&)を使うとスタック変数がキャプチャさ れてしまい、iOSではスレッドを分けない限り原則として 同⼀スタックフレーム上でブリッジAPIが最後まで実⾏さ れるので問題ないが、Androidではコールバックのスタッ クフレームが異なり無効なアドレスを参照して落ちる トラブルシューティング: シーンライフサイクル問題
  • 53.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 53 •  透明領域を少なくして描画負荷を抑えるために、 Cocos2d-xのGLビューのサイズを、Cocos2d-x 内部で⽣成するシーンのサイズと同じにして既存 アプリ側から⽣成する仕様とした •  つまり、GLビューのサイズは端末画⾯サイズ より多くの場合⼩さくなる •  この仕様により、Cocos2d-x側で全画⾯表⽰した 場合に⾏ってくれるスケーリングに頼れないこと になり、様々なAndroid/iOSデバイス向けのス ケーリングのコードを⾃前実装することになり、 かなり⼿間になった 失敗点: ⾃前スケーリングは⾯倒
  • 54.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 54 •  ここまでの⼿間を経て、ようやくCocos2d-x組み 込みは実⽤に耐える技術として確⽴する •  しかし、Cocos2d-x⾃体も⽇々変化しており、明 ⽇はまた異なるものになっているかもしれない •  Director::getInstance()- >getRunningScene()->getChildren().at(0)だ とCameraが取れてしまう(現在のシーンはat(1)) •  Cocos2d-xのSceneは、Node/Layerと異なり、 Camera、BaseLight、NavMesh、 Physics3DWorldを持つ •  Cocos2d-xは3D/VRゲームエンジンへと変容 を遂げつつある(Cocos2d-xからCocosへ) これからのCocos2d-x
  • 55.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 55 •  Cocos Studio開発終了 •  Cocos Creatorが主流に •  Electronベースでオープンソース。Unityライ クなビジュアル開発環境 •  Chukongは、コンソール版をキャンセルして でも開発環境の充実を第⼀⽬標に置いている •  (UnityがC#で開発するように)JavaScriptでの ダイナミックな開発を推奨、C++は重い処理 を書く場合以外は使われなくなる •  プロジェクト構成が従来と変わるので、新し くCocosプロジェクトを起こすならCocos Creatorベースとすべし これからのCocos2d-x
  • 56.
    Copyright © GREE,Inc. All Rights Reserved. Cocos2d-x組み込みによるクライアント統合 56 •  余計な⾎は流さない •  Cocos2d-xへのパッチは最⼩限に •  Cocos2d-x最新版への追随更新を妨 げない •  ゴールはあくまでアプリを活かすこと •  UnityにCocos2d-xを組み込むことも 不可能ではない… かもしれない •  ゲームエンジンの深層は学びの宝庫で ある 総括: 外科⼿術の⼼得
  • 57.
    Copyright © GREE,Inc. All Rights Reserved. Thank You