cocos2d-JSではじめるブラウザゲーム開発

ゲームを作ったことがないwebプログラマが[cocos2d-xではじめるスマートフォンゲーム開発 [cocos2d-x Ver.3対応] for iOS/Android](http://amazon.jp/dp/4774170550?tag=0x1d-22)の4章を参考にブラウザゲームを作った記録．

[コミットログ](https://github.com/niku/KawazCatchJs/commits/master)を眺めると，調べものをしながらのんびりやってだいたい1ヶ月弱でできたみたい．

# できたもの

[KawazCatchJS](http://niku.github.io/KawazCatchJs/) で実際にゲームが遊べる

- 既知の問題
  - Firefox だと音が出ない
  - iOS7(WebGL未対応)だと動かない
  - twitter公式アプリのwebviewだと動かない

# ソースコード

https://github.com/niku/KawazCatchJs

# 動機

- ゲームを作ってみたいがどうしたらいいかわからない
- cocos2d-x の本を知り合いが書いたので買ってみた
- フレームワークの使い方だけではなく，ゲームの作り方についてよく書かれている本だった
- C++ は書いてみたことがないので，すぐには書ける気がしないな :/
- [cocos2d-js](http://www.cocos2d-x.org/wiki/Cocos2d-JS) では cocos2d-x の機能がほとんど同じように使えるようだ
- cocos2d-x で書かれている内容を cocos2d-js で書きかえながら実装してみよう

# 記録

## [4.1.1 ゲームプロジェクトを作成する](https://github.com/niku/KawazCatchJs/issues/1)

`cocos new -p org.kawaz.KawazCatch -l cpp -d ̃/ KawazCatch` となっているところを
`cocos new KawazCatchJs -l js` で作った

## [4.1.2 プロジェクトの初期構成](https://github.com/niku/KawazCatchJs/issues/2)

cocos2d-x だと以下のような編成になっている．

|クラス名|概要|
| ---- | ---- |
|AppDelegate.h/cpp|ゲーム全体を管理するクラスです。おもにゲーム起動時の初期化処理などを記述します|
|HelloWorldScene.h/cpp|初期状態でゲーム開始時に表示されるシーンです|

cocos2d-js の場合

`AppDelegate` は [main.js](https://github.com/niku/KawazCatchJs/blob/6c8f662dedf7dc0bd66bb143fcb63173f01d1bf3/main.js) と [project.json](https://github.com/niku/KawazCatchJs/blob/6c8f662dedf7dc0bd66bb143fcb63173f01d1bf3/project.json) に相当する．
`HelloWorldSchene` は [src/app.js](https://github.com/niku/KawazCatchJs/blob/6c8f662dedf7dc0bd66bb143fcb63173f01d1bf3/src/app.js) の中に [HelloWorldScene](https://github.com/niku/KawazCatchJs/blob/6c8f662dedf7dc0bd66bb143fcb63173f01d1bf3/src/app.js#L71-L77) がある．

## [4.1.3 新しいシーンを追加する](https://github.com/niku/KawazCatchJs/issues/3)

[差分](https://github.com/niku/KawazCatchJs/commit/aea51f33004bc43e332cce52f967d6d67411eec3)

XCode や Eclipse で cocos2d-x を用いて開発している場合だと，
ファイル名を入れるだけで自動的に所定の場所にファイルを置いてくれたり，設定が必要だったりする．

cocos2d-js でも同じように project.json へ記述が必要なようだ．

javascript のファイル名はどういうものが一般的なのだろう．
今回は [What is the javascript filename naming convention?](http://stackoverflow.com/questions/7273316/what-is-the-javascript-filename-naming-convention) を参考に

1. 全て小文字で書く(OS によっては大文字小文字を区別しないのでトラブルの原因になる)
2. 空白を入れない
3. 語句を区切りたくなったら `-` を使う

という方針でのぞむことにする．
つまり `MainScene.cpp` に相当するのは `main-scene.js` になる．

## [4.1.4 メインシーンを実装する](https://github.com/niku/KawazCatchJs/issues/4)

[差分](https://github.com/niku/KawazCatchJs/commit/7223123eb68911ac4bd7614741da2df769556095)

### ヘッダファイルは使わない

cocos2d-x は C++ で，cocos2d-js は JavaScript で書く．

cocos2d-js で利用する JavaScript は， C++ とは異なりコンパイルを行わないため，ヘッダファイル(.h)を持たない．そこで本の `MainScene.h` に書いてあるような内容は使わない．

### クラスを定義する

cocos2d-x でクラスを定義するには

```
class MainScene :public cocos2d::Layer
```

のように継承を利用する．

一方 cocos2d-js でクラスを定義するには

```
var MainSceneLayer = cc.Layer.extend({
```

のように，`extend` メソッドを利用する．

cocos2d-x の `cocos2d::Layer` に対応する名前は
cocos2d-js の `cc.Layer` になる．

### クラスからオブジェクトを生成する

cocos2d-x でオブジェクトを生成するには，`create` というメソッドを利用して `MainScene::create()` などとする．
オブジェクトの初期化処理は `init` というメソッドに書いておくと呼び出される．

cocos2d-js でオブジェクトを生成するには，JavaScript の `new` を普段通りに利用して，`new MainScene()` などとする．
オブジェクトの初期化処理は `ctor` というメソッドに書いておく．
[ctor のリファレンス](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.Node.html#ctor)にも書いてある通り，ctor の中では *必ず* `this._super()` を呼び出さなければならない．

cocos2d v2.x 時代には `MainScene.create` というメソッドを利用していたが，[非推奨(Deprecated)になった](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.Node.html#.create)．
cocos2d の create が非推奨になった訳や，ctor については公式wikiの[Object construction and class inheritance in Cocos2d-JS v3.0](http://cocos2d-x.org/docs/manual/framework/html5/v3/inheritance/en)に書いてあった．

**マイルール**
また `ctor` とは別に `init` というメソッドもあるが，こちらも cocos2d-js では利用しないことにする．
例えば Layer の [`init` メソッド](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.Layer.html#init)には

> please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer 

などとあり，どのクラスなら `init` を使ってよいのか覚える手間を省くためである．
都度 API を眺めたり，覚えられるなら使ってもかまわない．

#### まとめ

cocos2d-js v3.x 系では 

```javascript
var MainScheneLayer = cc.Layer.extend({
    ctor:function () {
        this._super();
        // 独自の処理をここに書く

        // init メソッドとは異なり
        // 最後は別に return を書かなくてよい
    }
}
````

という書きかたでクラスの拡張や初期化を行う．

### cocos2d-x本とこのコードで異なる点

- cocos2d-x 本では MainScene で cocos2d::Layer を継承していたが，このコードでは MainScene は Scene を継承することにした
- cocos2d-x 本では MainScene を create して画面を表示しているが，このコードでは MainScene の onEnter から始めることにした

どちらも[始めから用意されているサンプルコード](https://github.com/niku/KawazCatchJs/blob/6c8f662dedf7dc0bd66bb143fcb63173f01d1bf3/src/app.js)がそうなっていたという消極的な理由からである．
初心者なのでなるべく思わぬ事故を避けて進めたいと考えている．

## [4.1.5 デバッグ表示を削除する](https://github.com/niku/KawazCatchJs/issues/5)

[差分](https://github.com/niku/KawazCatchJs/commit/aca8fcdf8b954ea3ac6a4cbef3e8132a4743776a)

cocos2d-x だと AppDelegate.cpp に書いてあるデバッグ表示設定は
cocos2d-js だと project.json にある．

project.json の各設定内容は公式 wiki の [project.json](http://cocos2d-x.org/docs/manual/framework/html5/v3/project-json/en) に書いてある

## [4.2.1 デバイスと画面サイズ](https://github.com/niku/KawazCatchJs/issues/6)

[差分](https://github.com/niku/KawazCatchJs/commit/c646cdaf1a7d3757ab50d4e6eb23ed2641eceb43)

cocos2d-x で AppDelegate.cpp に書く画面サイズの設定は
cocos2d-js では [main.js のなか](https://github.com/niku/KawazCatchJs/blob/aca8fcdf8b954ea3ac6a4cbef3e8132a4743776a/main.js#L52)にある．

設定の内容自体は変わらないようだ．

## [4.2.2 画像の追加](https://github.com/niku/KawazCatchJs/issues/7)

> cocos2d-x では、画像や効果音、そのほかゲーム中で利用されるリソースは、すべて
Resourcesというフォルダに配置します。

とある．

cocos2d-js であらかじめ作られたディレクトリ構成を眺めると [res](https://github.com/niku/KawazCatchJs/tree/016dfbc7f1025c8d5f3567f569e3a1979fe2ccc9/res) 以下に配置するようだ．

ライセンスを守れば [cocos2d-xではじめるスマートフォンゲーム開発のサポートページ](http://gihyo.jp/book/2015/978-4-7741-7055-8/support#supportDownload) から素材をダウンロードして利用させていただけるので res 以下に展開する．

ただし，画像素材を格納しているフォルダが zip だと image，本だと images になっていたので，
本にあわせて，zip から解凍した画像のフォルダ名 image を images へとリネームしておいた．

## [4.2.3 リソースの参照方法とファイルシステム](https://github.com/niku/KawazCatchJs/issues/8)

[差分](https://github.com/niku/KawazCatchJs/commit/7d0f6516e14f68cada28a1891f50093c776155a7)

cocos2d-x だと

> 複数のパスを登録しておき、それらを順に探索して使用してくれる、searchPathという仕組みが備わっています

だが，cocos2d-js では少し異なり，web 経由でのアクセスでゲームをするには，読み込む対象のファイルを直接記述しておかなければならない．
初期に用意された雛形では [src/resource.js](https://github.com/niku/KawazCatchJs/blob/ed52351785d0215ef494c6e1b9bbc3bc77f63ab8/src/resource.js) に記述しているようだ．

### cocos2d-js の振舞いが cocos2d-x と異なる理由の推察

cocos2d-js で作ったゲームを web 経由で遊ぶときに，検索対象ディレクトリを指定するのではなく，検索対象ファイルを直接指定しなければならない理由は，軽く探した限りだとどこにも書いてはいなかったが，以下のような理由であろうと推察される．

web 経由でのアクセス ( http 経由でのアクセス ) の場合，手元にあるファイルを読み込むときのように，ファイルを素早く探して読み込むことができない．
そのため，基本的にはゲーム内で使う画像/音声/効果音などは全てゲーム起動直前にブラウザ/デバイスに読み込ませておかなくてはならない．
そうしないとゲーム内で必要になったときにすぐに使うことができないからだ．

ディレクトリがあいまいなファイル名があると，ブラウザ/デバイスとサーバーとのやりとりが増えてその分プログラムが複雑になってしまう．それを避けるために，検索ディレクトリを指定する機能を用意しなかった．

cocos2d-js では cocos2d-x と同じようにiOSやAndroid用のアプリを作ることもできる．
cocos2d-js でアプリを作る場合には [Assets Manager Extension](http://cocos2d-x.org/docs/manual/framework/html5/v3/assets-manager/en) という，素材を読み込むための仕組を利用することができ，その中では searchPath を利用することもできるようだ．

### まとめ

cocos2d-js で作ったゲームを web 経由で遊んでもらおうと思っているなら，素材ファイルの場所は全てディレクトリ名から指定する．
cocos2d-js で作ったゲームをアプリ化して遊んでもらおうと思っているなら，cocos2d-x と同じように searchPath を指定して，ディレクトリ名を含まない，ファイル名だけでの場所指定にも対応している．(ようだ)

## [4.2.4 Spriteの設置](https://github.com/niku/KawazCatchJs/issues/9)

[差分](https://github.com/niku/KawazCatchJs/commit/7d0f6516e14f68cada28a1891f50093c776155a7)

cocos2d-x と対比するとそれなりに書くことがある．

### Director の取得

> Directorクラスはシングルトンクラスになっているため、Director::getInstance()で取り出して使います

cocos2d-js でどうやるとよいかは [Director](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.Director.html#constructor) の説明に書いてある．

cocos2d-js では最初から director オブジェクトへアクセスする．そのときのアクセスは `cc.director` になる．

### Sptirte の生成

例によって `Sprite.create()` ではなく `new Sprite()` を利用する．
引数には画像として利用するファイル名を指定する．

cocos2d-js では読み込まれていないリソースを利用するのを防止するため，
スプライトにファイル名を直接指定せず，
resource.js で指定したオブジェクト res.xxx を経由してファイル名を取得するのが行儀がよさそうだ．

サンプルでもそのようになっていた．

### cocos2d-x の Vec2 相当の cc.Point

cocos2d-x では座標の指定に Vec2 を使っている．
cocos2d-x 本の「3.4.4 ノードの位置の移動」に詳しい．
本にも記述があるとおり，Vec2 の別名は Point となっている．
これら 2 つは同じものを指している．

cocos2d-js では Vec2 はなく `cc.Point` オブジェクトがそれに相当する．
Point オブジェクトを作るときは `new Point` ではなく `cc.p` を使うこと．
[Point オブジェクトの API リファレンス](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.Point.html#constructor)に
> please do not use its constructor to create points, use cc.p() alias function instead. 
と書いてある

### 画面の向きの指定

cocos2d-js を用いて web で表示すると，初期状態でも特に問題なく表示された．

## [4.3.1 プレイヤーをメンバ変数として所持する](https://github.com/niku/KawazCatchJs/issues/10)

[差分](https://github.com/niku/KawazCatchJs/commit/0459adf703efdd694b63a6e5760bf290f2dad9b6)

> メンバ変数としてシーンクラスに保持

- メンバ変数は cocos2d-js では extend に渡すオブジェクトのプロパティとして設定する
- cocos2d-js でのコーディングスタイルは [Google Javascript Style Guide](https://github.com/cocos2d/cocos2d-js/blob/Cocos2d-JS-v3.3-final/docs/JavaScriptStyleGuide.html) であるそうなので，それに従って，クラス内部でのみ利用する変数には末尾に `_` を付与する
- 初期化するなら ctor のなかで `this.xxx` で記述する

> デストラクタ

cocos2d-js では GC されるので不要(なはず)だ！ :tada: 

## [4.3.2 タッチを取得する](https://github.com/niku/KawazCatchJs/issues/11)

[差分](https://github.com/niku/KawazCatchJs/commit/0687f6aff049fe55907049fbb9950d572efb3eb3)

### cocos2d-js でのイベント定義

cocos2d-js v3 からは Event の処理を以下のような形で書くことができる．

```javascript
cc.eventManager.addListener({
    event: cc.EventListener.TOUCH_ONE_BY_ONE,
    onTouchBegan: function(touch, event) {
        return true;
    },
    onTouchMoved: function(touch, event) {
        cc.log("Touch at (%f, %f)", touch.getLocationX(), touch.getLocationY());
    }
}, this);
```

cocos2d-x と同じように EventLister オブジェクトを生成してそれを add するスタイルでも書ける．
しかし引数に設定を書いた json を渡す方が javascript では馴染みがあるので，json を渡すスタイルを使っていくことにする．
ちなみにコードを読むと json を解釈するときに [cc.EventListener.create](https://github.com/cocos2d/cocos2d-html5/blob/Cocos2d-html5-v3.3/cocos2d/core/event-manager/CCEventListener.js#L446-L494) で EventLisner を生成していたので，単なる構文の違いと言ってもいいだろう．

色々調べてみたところ公式 wiki の [EventManager Mechanism](http://cocos2d-x.org/docs/manual/framework/html5/v3/eventManager/en) が一番よくまとまっていた．

`event:` のところに指定できるものは公式 wiki の [Create three sprites with images for the buttons](http://cocos2d-x.org/docs/manual/framework/html5/v3/eventManager/en#create-three-sprites-with-images-for-the-buttons) の下のほうに書いてある，

> Event type list:
> 
>    cc.EventListener.TOUCH_ONE_BY_ONE
>    cc.EventListener.TOUCH_ALL_AT_ONCE
>    cc.EventListener.KEYBOARD
>    cc.EventListener.MOUSE
>    cc.EventListener.ACCELERATION
>    cc.EventListener.CUSTOM

となる．

その下の onXxx のコールバックは event の種類毎に異なっている．
公式 wiki の[properties-and-functions-list](http://cocos2d-x.org/docs/manual/framework/html5/v3/eventManager/en#properties-and-functions-list) に各 event 別に指定可能なコールバックが書いてある．

最後の this はイベントの優先順位を表している．
Node オブジェクトのときは `SceneGraphPriority` で登録される．
ここが数値だった場合は `FixedPriority` で登録される．
[Add event listener to event dispatcher](http://cocos2d-x.org/docs/manual/framework/html5/v3/eventManager/en#add-event-listener-to-event-dispatcher) に書いてある．

### ログ出力

`cc.log` を使うとできる．ドキュメントのどこからも見つけられなかった……
ソースでは [CCDebugger.js](https://github.com/cocos2d/cocos2d-html5/blob/Cocos2d-html5-v3.3/CCDebugger.js#L330-L332) で定義している．
ブラウザの console に出力される．ブラウザで良くやる console.log と同じ．

![2015-02-16 8 12 27](https://cloud.githubusercontent.com/assets/10890/6205511/a4639202-b5b3-11e4-8987-b06b1673b3d6.png)

## [4.3.3 タッチに合わせてキャラクターを動かす](https://github.com/niku/KawazCatchJs/issues/12)

[差分](https://github.com/niku/KawazCatchJs/commit/c9aa0bf2d6abfe3dec701abf160798390493f9ad)

### Position に関連した処理

cocos2d-js の場合 [Position オブジェクト](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.Point.html) にはメソッドがない．
そもそも Position オブジェクトの説明に `new cc.Position` (コンストラクタ) を使わずに `cc.p` メソッドを使ってと書いてあったことに気づかなかった．今までのコードも直す．

Position を足すには [`cc.pAdd`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.html#.pAdd) を使い，
最小/最大を制限した Position を得るには[`cc.pClamp`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.html#.pClamp) を使う．

### コールバックの中での this

コールバックの中での this は，そのままだと直感的に考えているような this にならない．
例えば今回の場合でいうと onTouchMoved の this がMainSceneLayer を指していると考えてしまうだろう．しかし，そうはならない．
JavaScript でよくあるハマりどころである．

これを回避するために関数に `.bind(this)` を追加して(この場合の this は MainSceneLayer を指している)
コールバックの中での this も MainSceneLayer を指すようにする．
イディオム(慣用表現)として，コールバックには全て `.bind` をつけてしまってかまわない．

## [4.3.4 キャラクターが画面から飛び出してしまうのを防ぐ](https://github.com/niku/KawazCatchJs/issues/13)

[差分](https://github.com/niku/KawazCatchJs/commit/118bb4738ac5085c221feb5dada15d594959d8d9)

特筆すべきことなし

## [4.4.1 フルーツ用の配列を作成する](https://github.com/niku/KawazCatchJs/issues/14)

[差分](https://github.com/niku/KawazCatchJs/commit/4c775c2addb06b1918220dd847ba20713d9faacb)

cocos2d-x でいうところの `Vector` と `Map` は
[cocos2d-js のリファレンスマニュアル](http://www.cocos2d-x.org/reference/html5-js/V3.2/index.html)を見る限りではそのものずばりのクラスがないようだった．

JavaScript だと通常は `Array` と `Object` に相当するだろう．
html5 のところではそれで全く問題ないのだけど，
c++ オブジェクトに変換するときもそれで大丈夫なんだろうか？

cocos2d-js に grep をかけてみつけた js_manual_conversions.h にある

- [jsval_to_ccvaluevector](https://github.com/cocos2d/cocos2d-js/blob/b888d476bbff9b12dbc32bcc31de6415d2c08e2b/frameworks/js-bindings/bindings/manual/js_manual_conversions.cpp#L1167-L1185)

というメソッドを見る限りでは

- JavaScript の `Array` は cocos2d の `Vector` に
- JavaScript の `Object` は cocos2d の `Map` に

変換されるようだ．
つまり大丈夫そうだ．

## [4.4.2 フルーツを出現させるメソッドを作成する](https://github.com/niku/KawazCatchJs/issues/15)

[差分](https://github.com/niku/KawazCatchJs/commit/a81fa208fb009f605625069c3923ef09161ee9a1)

> FruitTypeを宣言しました。(中略) enum構文を用いて

JavaScript には enum という概念はないので Array で代用する．

> シーン内でのみ使うのでprivate 宣言

JavaScript には private 関数という概念はないのでスコープを気にしないことにする．

JavaScript の組み込みでは `format` 関数がないので [`cc.formatStr`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.html#.formatStr) を利用する．

## ブラウザからのデバッグ

`addFruit` を実装してみたものの，実際に動くかどうかわからない．
そこでブラウザの console からこの関数を呼び出してみて，期待通りになるかチェックする．

`MainScene` は `cc.director.getRunningScene()` で取得できる．
`MainSceneLayer` はその中の唯一の子なので `cc.director.getRunningScene().getChildren()[0]` で取得できる．
`addFruit` は `MainSceneLayer` の関数なので

```javascript
var layer =  cc.director.getRunningScene().getChildren()[0];
layer.addFruit();
```

という形で呼び出せる．

何回か `addFruit` を実行してみると画像のようになったので，意図通りに動きそうだ．

![2015-02-28 9 08 27](https://cloud.githubusercontent.com/assets/10890/6423521/c3d7d6c2-bf2a-11e4-845e-036dc5dd0741.png)

## [4.4.3 作成したフルーツを削除するメソッドを実装する](https://github.com/niku/KawazCatchJs/issues/16)

[差分](https://github.com/niku/KawazCatchJs/commit/58fe73e4d013ade76d50a6c10910c6390de94965)

`removeFruit` の動作もブラウザのコンソールから確認してみる．

- フルーツを追加
- フルーツを追加 ( <- このフルーツを消してみる )
- 配列に登録されているフルーツの確認
- レイヤーに登録されている子ノードの確認
- フルーツを削除
- 配列に登録されているフルーツの確認 ( 減っている )
- レイヤーに登録されている子ノードの確認 ( 減っている )

```javascript
var layer =  cc.director.getRunningScene().getChildren()[0];
layer.addFruit();
var fruit = layer.addFruit();
layer.fruits_;
layer.children;
layer.removeFruit(fruit);
layer.fruits_;
layer.children;
```

![2015-02-28 9 34 03](https://cloud.githubusercontent.com/assets/10890/6423684/1aaad6d2-bf2d-11e4-9b19-576aaf30c036.png)

## [4.4.4 フルーツを出現させる](https://github.com/niku/KawazCatchJs/issues/17)

[差分](https://github.com/niku/KawazCatchJs/commit/bee621ef9ccd5e4772f5e7180893771ff23b80c3)

特筆すべきことなし

## [4.4.5 フルーツにアニメーションを付ける](https://github.com/niku/KawazCatchJs/issues/18)

[差分](https://github.com/niku/KawazCatchJs/commit/0f55969098f389912151d76885ce9640606171cd)

`MoveTo::create` は [`cc.moveTo`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.html#.moveTo)
`CallFuncN::create` は [`cc.callFunc`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.html#.callFunc)
を使うようだ．

callFunc の第二引数は `removeFruit` の中の `this` が何を示すかを表すんだろう．
(JavaScript のいつものやつだ)

`Sequence::create` は [`cc.sequence`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.html#.sequence) を使うようだ．

cocos2d-x の場合

> 最後の1つが必ずNULLになる

と書いてあったが，cocos2d-js の場合はそうしなくてもかまわないようだ．

## [4.4.6 アクションとイージング](https://github.com/niku/KawazCatchJs/issues/19)

cocos2d-x の `EaseSineIn::create` は
cocos2d-js の [`cc.easeSineIn`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.html#.easeSineIn) に相当するのだろう．

他のイージングも [CCActionEase.js](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/src/_Users_panda_StudyWork_Cocos_cocos2d-js_frameworks_cocos2d-html5_cocos2d_actions_CCActionEase.js.html) を見ると大体ありそう．

## [4.5.1 フルーツとキャラクターの当たり判定を行う](https://github.com/niku/KawazCatchJs/issues/20)

[差分](https://github.com/niku/KawazCatchJs/commit/9fb4bd5fa44d35b3e30464df6c2242af15aa32d8)

cocos2d-x での Rect の containsPoint は
cocos2d-js では [`cc.rectContainsPoint(rect, position)`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.html#.rectContainsPoint) になるようだ．

## [4.6.1 ラベルを表示する](https://github.com/niku/KawazCatchJs/issues/21)

[差分](https://github.com/niku/KawazCatchJs/commit/c1580ec0345fde07be8f7b46fd03d05a75b2db12)

cocos2d-x では

> 3.0からはシステムフォントやTrueTypeフォント、ビットマップフォントなど、どのような種類の文字であっても統一的なクラスとして扱えるようになりました

と書いてある．

cocos2d-js (cocos2d-html5)を grep して調べてみると，v3.3 時点ではまだ統一されたインターフェースがなくバラバラみたい．

- [LabelTTF](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.LabelTTF.html)
- [LabelBMFont](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.LabelBMFont.html)
- [LabelAtlas](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.LabelAtlas.html)

をみつけられた．今回は一般的であろうと思われる TrueType フォントを使うため，LabelTTF を利用する．

[LabelTTF](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.LabelTTF.html#constructor) の説明には

> cc.LabelTTF objects are slow for js-binding on mobile devices.Consider using cc.LabelAtlas or cc.LabelBMFont instead.

と書いてあるから速度が大事なところでは他のラベルを利用した方がよさそうだ．

LabelTTF の第一引数に数字の `0` を渡すと何も表示されず，文字の `'0'` を渡すと意図通り表示できた．
ハマりそうなので注意すること．

## [4.6.2 ラベルの見た目を改善する](https://github.com/niku/KawazCatchJs/issues/22)

[差分](https://github.com/niku/KawazCatchJs/commit/d1addc83d765415649a30f7805935c2ce9104a51)

cocos2d-x の `Color4B::BLACK` に相当するのは
cocos2d-js の `cc.color.BLACK` のようだ．

他に使える色は [cocos2d/core/platform/CCTypesPropertyDefine.js](https://github.com/cocos2d/cocos2d-html5/blob/Cocos2d-html5-v3.3/cocos2d/core/platform/CCTypesPropertyDefine.js#L110-L136) に書いてある以下のものだと思う．

- WHITE
- YELLOW
- BLUE
- GREEN
- RED
- MAGENTA
- BLACK
- ORANGE
- GRAY

cocos2d-x の `Size` に相当するのは
cocos2d-js の [`Size`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.Size.html) のようだ．
例によって `new cc.Size` ではなく `cc.size` を使ってねと書いてあるので，`cc.size` を利用する．

[cc.LabelTTF](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.LabelTTF.html) からは outLine を利用することができなさそうだったので，実装しない．

## [4.7.1 残り時間のラベルを追加する](https://github.com/niku/KawazCatchJs/issues/23)

[差分](https://github.com/niku/KawazCatchJs/commit/8fd778e4e79a7ce6fa28d30a07957bd805b0c84c)

残り秒数 `second_` は，定数の記述との兼ね合いで，
宣言時に指定することができなかったので，初期化時に指定した．

## [4.7.2 残り秒数を減らす](https://github.com/niku/KawazCatchJs/issues/24)

[差分](https://github.com/niku/KawazCatchJs/commit/755a701d5e7d88935751b34a24b3f77e9fb78e25)

JavaScript で小数点の整数部のみ利用するのに一番速い方法はビット演算を使う ( | 0 をつける ) こと
http://stackoverflow.com/questions/596467/how-do-i-convert-a-float-to-a-whole-number-in-javascript

`Math.floor(0.1) // => -1` となってしまう．
今回は -0.1 は 0 になってほしいので `var second = this.second_ | 0;` というように利用した．

## [4.7.3 残り時間に応じてゲームの状態を管理する](https://github.com/niku/KawazCatchJs/issues/25)

[差分](https://github.com/niku/KawazCatchJs/commit/eb055d1a2f7ca806b4a3b3e460ec8dbdb2e96574)

例によって JavaScript に Enum はないので object で代用する．
他には書くことないなあ．

## [4.8.1 リプレイボタンを表示する](https://github.com/niku/KawazCatchJs/issues/26)

[差分](https://github.com/niku/KawazCatchJs/commit/03d3c2ead0d6924fd35ea9970144f870dc671c84)

cocos2d-x での `MenuItemImage::create` は
cocos2d-js では [`new cc.MenuItemImage`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.MenuItemImage.html#constructor) に対応している．

cocos2d-x では `Director` オブジェクトが持っている `replaceScene` というメソッドは
cocos2d-js のソースコードを検索してみたところでは存在しないようだった．
[`runScene`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.Director.html#runScene) に

>  Run a scene. Replaces the running scene with a new one or enter the first scene. 

と書いてあった．新規のときのみならず，置き換える場合もこれを利用すればよさそうだ．

cocos2d-x の `Menu::create` は
cocos2d-js では [`new cc.Menu`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.Menu.html) に対応している．
ドキュメントを読む限り，cocos2d-x とは異なり，最後に `NULL` を設定しなくてもよいようだ．

## [4.8.2 シーン遷移にトランジションを追加する](https://github.com/niku/KawazCatchJs/issues/27)

[差分](https://github.com/niku/KawazCatchJs/commit/b9026fef57e056012b0cb23e0e749b8f21e9515f)

cocos2d-x の `TransitionFade::create` は
cocos2d-js の [`cc.TransitionFade`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.TransitionFade.html) に対応する．

## [4.9.1 音声ファイルを用意する](https://github.com/niku/KawazCatchJs/issues/28)

各ブラウザの音声形式対応状況については MDN の [Media formats supported by the HTML audio and video elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats#Browser_compatibility) がまとまっているし，情報が新しいようだった．
ひとまず MP3 でも大丈夫そうだ．

## [4.9.2 BGMを鳴らす](https://github.com/niku/KawazCatchJs/issues/29)

[差分](https://github.com/niku/KawazCatchJs/commit/8d2cb3439fc1ea8c1833b30d7cd0226e691ad61e)

cocos2d-x の `CocosDenshion::SimpleAudioEngine::getInstance()` に対応するのは
cocos2d-js では [`cc.audioEngine`](http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.audioEngine.html) である．

cocos2d-x だと `playBackgroundMusic` という名前でBGMを再生しているところ
cocos2d-js では `[playMusic]`(http://www.cocos2d-x.org/reference/html5-js/V3.2/symbols/cc.audioEngine.html#.playMusic) に相当するようだ．

> ゲームを一時停止したときにBGMを止める処理

ブラウザ版 (cocos2d-html5) には含まれていないようだった．
確かに実際に html で表示しているときはブラウザやタブの選択状態で音が出たり止まったりするので，BGM の一時停止の処理を明示的に書く必要がないのだろう．

ちなみに iOS 実機で試したところ

- Safari では他のアプリを開いたとき(ブラウザがアクティブではなくなったとき)に音が止まった
- Chrome では音が鳴り続けた

という違いがあった．

----

アプリとしてビルドしたとき(cocos2d-js) にどうなるか気になるので少し調べた．
`cocos2d-js/frameworks/js-bindings/cocos2d-x/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxRenderer.java` というパスを辿ると
`handleOnPause` や `handleOnResume` というメソッドがあり，その中で音の停止や再生を行っているようだった．

つまり Cocos2dxRenderer.java が cocos2d-js で実際に呼ばれて使われているなら，
プログラマが明示的に記述しなくても cocos2d-js でうまく扱ってくれるのだろう．
(たぶん)

## [4.9.3 効果音を鳴らす](https://github.com/niku/KawazCatchJs/issues/30)

[差分](https://github.com/niku/KawazCatchJs/commit/2aa684e7fd6aaea377e00306ad7c57c75915165c)

特筆すべきことなし

## [4.10.1 追加フルーツの仕様を決める](https://github.com/niku/KawazCatchJs/issues/31)

[差分](https://github.com/niku/KawazCatchJs/commit/dd02ffa45849094802a8f625160f2bdac29ef8e4)

cocos2d-x本と異なり，
JavaScript実装の都合上，まずは黄金のフルーツだけ追加する．
そうすると爆弾を実装する前でも黄金のフルーツだけ追加した時点で動きを試せる．

## [4.10.2 黄金のフルーツを実装する](https://github.com/niku/KawazCatchJs/issues/32)

[差分](https://github.com/niku/KawazCatchJs/commit/f8edff24a3104f65882d4f43ca00f913d4109f3c)

cocos2d-x だと enum で処理しているところについて．

JavaScript には enum がないが，switch 文に文字列が使えるので
文字列 `"GOLDEN"` との比較にしている．

## [4.10.3 爆弾を実装する](https://github.com/niku/KawazCatchJs/issues/33)

[差分](https://github.com/niku/KawazCatchJs/commit/c49cea7b790190f8a66eb701dd2cecc75302211d)

cocos2d-x のVector は cocos2d-js での Array に相当するので frame は Array で実装している．

cocos2d-x の `SpriteFrame::create` は
cocos2d-js の [`new cc.SpriteFrame`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.SpriteFrame.html#constructor) で

cocos2d-x の `Animation::createWithSpriteFrames` は
cocos2d-js の [`new cc.Animation`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.Animation.html#constructor) で実装する．

## [4.11.1 TitleSceneクラスを作る](https://github.com/niku/KawazCatchJs/issues/34)

[差分](https://github.com/niku/KawazCatchJs/commit/0d4f6ae2a74d8c3db617c9a5bf51c5b13b45ab16)

cocos2d-x の `FadeTo::create` は
cocos2d-js では [`cc.fadeTo`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.fadeTo) で表す．

cocos2d-x の `RepeatForever::create` は
cocos2d-js では [`cc.repeatForever`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.repeatForever) で表す．

cocos2d-x の `DelayTime::create` は
cocos2d-js では [`cc.delayTime`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.delayTime) で表す．

cocos2d-x の `TransitionPageTurn::create` は
cocos2d-js では [`new cc.TransitionPageTurn`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.TransitionPageTurn.html#constructor) で表す．

二度押し防止のためにリスナーを無効化する実装は
cocos2d-x では `getEventDispatcher()->removeAllEventListeners()` となっている．
cocos2d-js には該当する関数がないようだったので「対象の listener を消す」という処理にした．

## [4.11.2 「タイトルへ戻る」ボタンを実装する](https://github.com/niku/KawazCatchJs/issues/35)

[差分](https://github.com/niku/KawazCatchJs/commit/cfc8c42d361477d7652accdf330ff90e1afacad1)

特筆すべきことなし

## [4.12.1 ゲーム開始、終了演出を追加する](https://github.com/niku/KawazCatchJs/issues/36)

[差分](https://github.com/niku/KawazCatchJs/commit/5a86e6637abcc76c8d5ab63db6b09688a81af30b)

- [`cc.spawn`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.spawn)
- [`cc.easeIn`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.easeIn)
- [`cc.scaleTo`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.scaleTo)
- [`cc.fadeOut`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.fadeOut)
- [`cc.removeSelf`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.removeSelf)
- [`cc.delayTyme`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.delayTime)
- [`cc.easeExponentialIn`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.easeExponentialIn)

イージングの書き方は `cc.easeIn` のドキュメントを参考にすると `action.easing(cc.easeIn(3));` という感じのようだ．
cocos2d-x と同じように `cc.easeIn(action, 0.5)` という形で書くと，cocos2d-js ではエラーになった．
注意すること．

## [4.12.2 フルーツの描画を改善する](https://github.com/niku/KawazCatchJs/issues/37)

[差分](https://github.com/niku/KawazCatchJs/commit/c0d6f72f63459f63c0993a4f2125f760b1d64509)

cocos2d-x の `SpriteBatchNode::create` は
cocos2d-js の [`new cc.SpriteBatchNode`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.SpriteBatchNode.html#constructor) に相当する．

Sprite への幅指定が `fruitWidth` だと，右端に縦長の線が入ってしまった．
右隣りの画像が1ピクセルだけ含まれてしまっているのかもしれない．
そこで幅を1ピクセルだけ小さくすると問題が解消した．
(場当たり的な対応なので後で直しかたを調べる)

## [4.12.3 フルーツ出現時のアニメーションを強化する](https://github.com/niku/KawazCatchJs/issues/38)

[差分](https://github.com/niku/KawazCatchJs/commit/f1823006fc3b049b66c3a04ef1e4f7b402f70ee0)

- [`cc.repeat`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.repeat)
- [`cc.rotateTo`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.html#.rotateTo)

## [4.12.4 ハイスコアを追加する](https://github.com/niku/KawazCatchJs/issues/39)

`UserDefault` を grep で探したが cocos2d-html5 (つまりブラウザ版) には見つからなかった．

公式フォーラムを探すと [There’s no UserDefault into the binding?](http://discuss.cocos2d-x.org/t/theres-no-userdefault-into-the-binding/6970) というスレッドで

> Plz use sys.LocalStorage instead.

と書いてあり [`cc.sys.LocalStrage`](http://www.cocos2d-x.org/reference/html5-js/V3.3/symbols/cc.sys.html#.localStorage) というものがあることを知った．

https://github.com/cocos2d/cocos2d-js/blob/b888d476bbff9b12dbc32bcc31de6415d2c08e2b/frameworks/js-bindings/bindings/manual/localstorage/js_bindings_system_registration.cpp にC++のバインディングもあるようなので html5 でだけしか使えないということでもなさそうだ．

試しに Google Chrome の console から使ってみると

![2015-03-17 4 22 40](https://cloud.githubusercontent.com/assets/10890/6674539/cbb191e0-cc5d-11e4-9acc-4dc6221c1bb9.png)

```
cc.sys.localStorage.setItem("highscorekey", 200)
cc.sys.localStorage.getItem("highscorekey")
```

で設定，取得できた．

リロードした後でも取得できるかを試すと

![2015-03-17 4 23 11](https://cloud.githubusercontent.com/assets/10890/6674581/134c0396-cc5e-11e4-8c42-749c39daa83b.png)

できた．これを利用すればハイスコアのブラウザへの記録ができそうだ．

## [4.13.1 乱数の質を改善する](https://github.com/niku/KawazCatchJs/issues/40)

JavaScript の Math.random の疑似乱数の質については調べていないので省略する．

疑似乱数の統計をとって等確率性と無規則性を調べるのによさそうなページがあった．
http://www.geocities.jp/m_hiroi/light/pystat04.html
実装がPythonでなされているところをJavaScriptで書けば同じように試せそう．

## [4.13.2 爆弾や黄金のフルーツの出現率を変更する](https://github.com/niku/KawazCatchJs/issues/41)

[差分](https://github.com/niku/KawazCatchJs/commit/e5d61680f173548f50a3674529e5f7d3010749b8)

特筆すべきことなし

## [4.13.3 フルーツの出現確率を調整する](https://github.com/niku/KawazCatchJs/issues/42)

[差分](https://github.com/niku/KawazCatchJs/commit/1b622945ed19d4ab69dcbb0659d5554541cf685c)

C++ の `powf` (べき乗) に相当するのは
JavaScript では [`Math.pow`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/pow) のようだ