cocos creatorでHelloWorld(&cocos2d-xの解析について)

こんにちはeeic2017erの @totem です
この記事は[eeic advent calender](http://qiita.com/advent-calendar/2016/eeic)の24日目の記事です
* * *

最近はUnityが話題ですね！
学科の先輩であるムヒョペさんが[はじめてのUnity：3Dゲーム（RPG/アクション）の土台を作るまで
](http://qiita.com/satewn/items/47e0e18bbb1442bf688c)という神記事を書いてくださっていたり、学科で勉強会があったりと、学科民にも段々ユーザーが増えてきているかもしれません。
実際とても使い易いですしアセットストアも充実してますし情報も多くて最高ですよね。

また、最近はUnreal Engine4という、無料のゲームエンジンが流行りはじめていたりします。
こちらも素敵なエンジンがあってC++で書けてよさみが深いです。

今は次第に下火になってきていますが、少し前までUnityと並んでいた、マルチプラットフォームなゲーム開発フレームワークとしてcocos2d-xというものがあります。
これは主に2Dゲームに用いるフレームワークで、DisneyツムツムやFinal Fantasy Record Keeper等、有名ゲームにも用いられています。

そんなcocos2d-xもUnity5やUE4に対抗し、今年の3月に統合開発環境であるcocos creatorを公開しています。
今回はそのcocos creatorを紹介します。
~~cocos creatorのハックを紹介しようと思ってたのですが、間に合いませんでした...~~


# cocos creator
cocos creatorはcocos2d-xを内包している、Electronで作られている統合開発環境です
[http://cocos2d-x.org/creator](http://cocos2d-x.org/creator)
このページからcocos creatorをダウンロードすることができます。
残念ながらLinux版はありません....

オープンソースなのでエンジンのソースも公開されています。
[https://github.com/cocos-creator/engine](https://github.com/cocos-creator/engine)

まだ結構使いづらいところが多いのですが、頑張れば使えます(~~ならUnityを使えば?~~)
他のゲームエンジン同様、メモリを結構食うので気をつけてください。

## Hello World!
Hello Worldをしてみましょう。
ダウンロードしたcocos creatorを動かすと以下のような画面で雛形を選択することができます。
今回はHello Worldを選択してみます。
<img width="1013" alt="スクリーンショット 2016-12-24 23.35.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/ce54a5f5-b7bc-2a72-9819-54fdd645c5d1.png">

プロジェクトのパスを入力してCreateボタンを押すと以下のようなエディタ画面が出ます。
<img width="1440" alt="スクリーンショット 2016-12-24 23.43.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/f17620d9-5ad4-e220-e408-d5d666774256.png">

Unityを使ったことがあれば、結構すんなり使えると思います。
説明をしておくと、

* 左上・・・ Node Treeウィンドウです。編集中のシーンに配置されているオブジェクトが表示されます。
* 左下・・・ Assetsウィンドウです。プロジェクトのファイルが表示されます。
* 中央左・・・ Sceneウィンドウです。Unity同様、直感的にオブジェクトを配置して編集することができます。
* 中央右・・・ Node Libraryウィンドウです。配置できるオブジェクトの一覧が表示されます。ここからドラッグ&ドロップでSceneウィンドウにオブジェクトを配置できます。
* 右・・・ Propertyウィンドウです。UnityにおけるInspectorウィンドウで、オブジェクトの詳細が表示されます。
* 下・・・ Console,TimeLineウィンドウです。Consoleウィンドウではデバッグ情報が出力できます。TimeLineウィンドウではアニメーションの編集などを行うことができます。

もちろん

Assetsウィンドウからスクリプトファイルをクリックすると、(~~のっぺりした~~)エディタが開きます。
ここでファイルを編集することができます。
<img width="801" alt="スクリーンショット 2016-12-25 0.01.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/75ea4476-4de3-73dc-1507-81e31baa2073.png">

Unityを使ったことがあればわかりやすいと思いますが、
onLoadではUnityでのStart関数同様(?)、ロード時に行う処理を記述します。
updateではUnityでのUpdate関数同様(?)、毎フレームごとに呼ばれる処理を記述します。

このスクリプトでは実行時にHelloWorldと表示します。

## タッチイベントを受け付ける
マルチプラットフォーム環境を想定して、タッチイベントを受け付けるスクリプトを書いてみます。
PC環境ではマウスのドラッグやクリックをタッチとして受け付けます。


```js:HelloWorld.js
cc.Class({
    extends: cc.Component,

    properties: {
        canvas: cc.Node,
        follower: {
            default: null,
            type: cc.Node
        },
        followSpeed: 200
    },

    // use this for initialization
    onLoad: function () {
        var self = this;
        self.moveToPos = cc.p(0, 0);
        self.isMoving = false;
        self.canvas.on(cc.Node.EventType.TOUCH_START, function (event) {
            var touches = event.getTouches();
            var touchLoc = touches[0].getLocation();
            self.isMoving = true;
            self.moveToPos = self.follower.parent.convertToNodeSpaceAR(touchLoc);
        }, self.node);
        self.canvas.on(cc.Node.EventType.TOUCH_MOVE, function (event) {
            var touches = event.getTouches();
            var touchLoc = touches[0].getLocation();
            self.moveToPos = self.follower.parent.convertToNodeSpaceAR(touchLoc);
        }, self.node);
        self.canvas.on(cc.Node.EventType.TOUCH_END, function (event) {
            self.isMoving = false; // when touch ended, stop moving
        }, self.node);
    },

    // called every frame
    update: function (dt) {
        if (!this.isMoving) return;
        var oldPos = this.follower.position;
        // get move direction
        var direction = cc.pNormalize(cc.pSub(this.moveToPos, oldPos));
        // multiply direction with distance to get new position
        var newPos = cc.pAdd(oldPos, cc.pMult(direction, this.followSpeed * dt));
        // set new position
        this.follower.setPosition(newPos);
    }
});
```

このような記述でタッチイベントを取得することができます。(サンプルコードのコピペです)
タッチしている地点に向かってスプライト画像が移動します。
なお、シーン画面からpropertiesに対してオブジェクトを指定してやる必要があります。
<img width="344" alt="スクリーンショット 2016-12-25 1.02.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/c1b1a2b8-bcd4-c322-4b8a-6e70011d6da0.png">


<blockquote class="twitter-video" data-lang="ja"><p lang="und" dir="ltr"><a href="https://twitter.com/devnull">@devnull</a> <a href="https://t.co/uSsLT1EBOq">pic.twitter.com/uSsLT1EBOq</a></p>&mdash; totem@進捗ダメです (@bbottait) <a href="https://twitter.com/bbottait/status/812688016460234752">2016年12月24日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

他にもゲームに求められる記述は簡単に行うことができます。
[http://cocos2d-x.org/docs/editors_and_tools/creator/](http://cocos2d-x.org/docs/editors_and_tools/creator/)
[http://cocos2d-x.org/docs/api-ref/creator/v1.3/](http://cocos2d-x.org/docs/api-ref/creator/v1.3/)
といったページを参照することで簡単にゲームを作っていくことができます。

## cocosアプリの解析
※以下はゲーム制作には一切必要のない話です。また初心者向けでもないです💦
Unityで作られたアプリケーションはil2cppを使用してビルドしている場合は、アセンブラを読むという方法で、使用していない場合はAssenbly-CSharp.dllをデコンパイルしてC#のソースコードに戻すことで見ていくという形で解析していくことになります。(Unityについては深く突っ込まないので興味があればtwitterとかで聞いてください、[LINEの愛甲さんの記事](http://developers.linecorp.com/blog/ja/?p=3999)が詳しいです)


cocosではどういった形で解析が行えるのでしょうか？
<img width="1027" alt="スクリーンショット 2016-12-25 1.16.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/1ebd7e61-da4c-1c99-3fa9-dc3f5a3e5888.png">

cocos creatorで作ったアプリはこのようなファイル構成をしています
今回はmacOS向けのビルドですが、基本的にどのターゲットへのビルドでも似たようなファイル構成になります
基本的にユーザーが記述したコードはResources/srcの中に配置されます。
srcフォルダ中にあるproject.jscというファイルがユーザーの記述したコードの本体です。
cocos creatorに限らずcocos-2dxのjsbindingはいずれもこのような形になります。
<img width="521" alt="スクリーンショット 2016-12-25 1.33.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/eee964c4-1fdd-8483-4f95-41e912a38fb1.png">
このファイルをfileコマンドでどんなファイルか判定してみるとdataと判定されます。
このままのファイル形式では人は読めません。

cocos-2dxのソースコードを読んでファイルをデコードすることを考えます。
cocos-2dxの中でjavascriptファイルのコンパイルを行っている部分を探します。
<img width="996" alt="スクリーンショット 2016-12-25 1.38.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/147125/b8604b26-2e46-2e0f-02fc-0467a6efde67.png">

見てみると[Google Closure Comlier](https://developers.google.com/closure/compiler/)を利用してjsファイルの圧縮を行い、その後jsbccというコンパイラでjavascriptをコンパイルしていることがわかります。

jsbccの中のコードを読むと内部で[SpiderMonkey](https://developer.mozilla.org/ja/docs/SpiderMonkey)を利用して、jsファイルをバイトコードに変換していることがわかります。
[https://developer.mozilla.org/ja/docs/Mozilla/Projects/SpiderMonkey/Internals/Bytecode](https://developer.mozilla.org/ja/docs/Mozilla/Projects/SpiderMonkey/Internals/Bytecode)にSpiderMonkeyで使用されるバイトコードについての記述があります。
SpiderMonkeyのAPIには[JS_DecompileScript](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference/JS_DecompileScript)というAPIがあります。
これはSpiderMonkeyでコンパイルしたコードをデコンパイルできるというものです。
[こんな議論](http://discuss.cocos2d-x.org/t/compiled-javascript-jsc-file-is-it-secure-enough-and-cannot-be-decompiled/8493)もあるのでわかりませんが、少なくともバイトコードについて記述がある以上、ある程度の解析は可能である可能性が高いです。
このAPIを用いて、ある程度解析を行おうと思っていましたが時間が足りませんでした、すみません。。。
またSpiderMonkeyでコンパイルを行う前のGoogle Clojure Compilerによる圧縮では、特に変数名の除去といった処理を行っていません。
解析の可能性を考えると難読化処理を自前で行ったほうがいいかもしれません。

#まとめ
cocos creatorはお手軽に2Dゲームを制作することが出来ます。
たまにはUnityから離れて使ってみると視野が広がるかもしれません。

解析の話が単体で記事になるほど間に合わず、入門者向けのHelloWorldと、入門者には向かない解析の話が混在する意味のわからない記事になってしまいすみません。
誤り等ありましたら指摘していただけると幸いです。