Cocos2d-x超入門 そもそも何からはじめればいいの？

# 初めに

[CYBIRDエンジニア Advent Calendar 2015](http://qiita.com/advent-calendar/2015/cybird)
4日目担当の@kanachaです。
CYBIRDに2015年新卒で入社し、現在はアプリチームで新規タイトルのクライアントの開発をしております。
3日目は(@cy-kenta-takahashi)さんの[storyboardのあれやこれ](http://qiita.com/cy-kenta-takahashi/private/7f8f10a453c6bc47f22b)でした。彼は私と同期のエンジニアで、毎日新しいことに触れながら、お互い非常に恵まれた環境で勉強をさせていただいております。

# 内容について
今回は私がプロジェクトで利用しているCocos2d-xというゲーム開発用フレームワークについてお話しします。
実は私自身、CYBIRDに入社してから
Cocos2d-xに初めて触れ、Xcodeに初めて触れ(そもそもMacを扱うのが初めて)
さらにはC++言語は不慣れという状態だったので、ほぼゼロからのスタートになりました。
内容は初心者向けとなりますが、
Cocosでゲームを作りたい！ゲーム制作に興味がある！
だけど何をすればいいのかわからない！という方に読んで頂ければ幸いです。
※Mac環境での説明になります

# Cocos2d-xって？
Cocos2d-x は 2D/3D ゲーム開発用のゲームフレームワークです。
AppStore や GooglePlay などで販売されているスマホアプリには、
Cocos2d-x を使って開発したタイトルが数多くあります。
開発言語は、C++11 だけでなく JavaScript や LUA にも対応しております。

Cocos2d-x の特徴を以下にまとめてみました。

#### [ Cocos2d-x のメリット]
・全ての機能を無料で扱える
・軽量で快速
・ver3.7 からは web 系ネイティブも作れるようになった

#### [ Cocos2d-x の悩ましいところ]

・cocosStudio が...バグが多い
・サウンドまわりが弱い
・サードの SDK 導入が大変
・バージョンアップが激しい( 2.x 系と 3.x 系では大幅な変更が加わったため、移行が地獄)

2D表現の描画が早い(弾幕シューティングゲーム向き)ことや、
ゲームエンジンにお金がかからない(オープンソースかつ無料)等が Cocos の魅力的なところでしょうか。
悩ましい点として、バージョンアップでの仕様変更が激しく、プロジェクト移行の難易度が高いという問題があります。
特に ver2.x から ver3.x の変更では、メソッド名の変更など大規模な調整が加えられました。
(現在のバージョンは3.8)

# 開発環境を整えよう
Cocos2d-x でゲームを作るためには以下のものが必要です。

[Cocos2d-x 本体]
　最新 ver を公式サイトからダウンロード。
　任意のディレクトリに配置します。
[Xcode]
　App Store からダウンロード。
　Cocos プロジェクトのオープン、
　コーディング、ビルドに Xcode を使います。


ターミナルを開き、Cocos2d-x をインストールしたディレクトリへ移動して
以下のコマンドを入力する

```
./setup.py
```
これでターミナルで cocos コマンドが使えるようになりました。
(.bash_profile に、COCOS_CONSOLE_ROOT パスが追加されます)

# Cocosプロジェクトを作ろう

ターミナルを開き、以下の cocos コマンドを入力する

```
cocos new test -p com.cocos.test -l cpp -d ~/cocosTest
```
- cocos new testは test というアプリを作成するという意味
- -pはパッケージ名を指定するパラメータ(com.cocos.test)
- -lは使用言語を指定するパラメータ(cpp なので C++)
- -dはプロジェクトを作成するディレクトリを指定するパラメータ
(~/cocosTestは、/Users/ユーザー/cocosTestに test を作るという意味)

# Hello World起動！
プロジェクトが生成されたので、さっそく開いてビルドしてみましょう。
「proj.ios_mac」フォルダ内の「test.xcodeproj」を Xcode で開きます。
最初の状態では Hello World というサンプルプログラムが既に用意されています。
プロジェクトを Run すると iOS シミュレーターが立ち上がり、ゲームが起動します。

![hallo.png](https://qiita-image-store.s3.amazonaws.com/0/101551/0d5d8d70-261e-29bc-0c52-361484a0fd7f.png)

- 上の文字「Hello World」が Label
- 中央の画像が Sprite
- GL verts: は頂点数
- GL calls: は描画回数
- 左下の数値はフレームレート
- 右下はボタン UI (タップするとアプリが終了します)


## プロジェクトの初期構成
自動で生成された Hello World プロジェクトには Classes 以下にこのようなファイルが置かれています。

|クラス名|概要|
|:--|:--|
|AppDelegate.h/.cpp|ゲーム全体を管理するクラス。主にゲーム起動時の初期化処理などを記述
|HelloWorldScene.h/.cpp|初期状態でゲーム開始時に表示されるシーン(2D の描画が行われてるのはこっち)

# Nodeとは？
ここで Cocos2d-x でゲーム制作を行う上で、
重要な要素である Node について説明します。
![node.jpg](https://qiita-image-store.s3.amazonaws.com/0/101551/e63f3fbe-9ad5-af93-585a-6d34845781d0.jpeg)

Node(ノード)とは
- Cocos2d-x 上で描画されるオブジェクトのことです
  - 画面上に表示される画像(Sprite)
  - ボタンなどの UI (Menu)
  - 文字列(Label)
  - エフェクトなど(particleSystem)

Node は座標(position)や大きさ(size)、回転(rotation)、透明度といった情報を持っており、
Cocos2d-x のプログラミングでは既存のノードを組み合わせたり、自分でノードを設計しながら画面を構築します。
※このような構造を`『シーングラフ』`といいます。

![layer.jpg](https://qiita-image-store.s3.amazonaws.com/0/101551/583feff3-dc3f-bb9e-f36a-e6115e7dfab3.jpeg)

ノードは生成しただけでは描画されず、
生成した後、既に追加されているノードの子ノードとして追加することで初めて画面上に描画されます。

- Scene という大きなノードが一画面を構成
- その中に Layer、Sprite の順に並べてゲーム画面が構成される

# Hello Worldを眺めてみよう

## HelloWorldScene.h
HelloWorld は、cocos2d::Layer というクラスを継承して作られています。

- cocos2d::Scene* createScene();
- bool init();
- menuCloseCallback(cocos2d::Ref* pSender);
- CREATE_FUNC(HelloWorld);

Layer クラスは画面内に起こるアクションを捉えてくれるクラスです。 onTouchBegan() やkeyPressed() などタッチパネルやキー入力などをキャッチするようなメソッド（コールバック）が並んでいます。

## HelloWorldScene.cpp
- Scene* HelloWorld::createScene()
- bool HelloWorld::init()
- void HelloWorld::menuCloseCallback(Ref* pSender)

こちらがプログラムの実装部分です。
createScene () でシーンの生成を行い、
init() 内では初期化された時の処理(画像や文字の配置)などが記述されています。
menuCloseCallback (Ref* pSender) は右下のボタンUIを押した際の処理が記述されています。

# Directorクラスとは？
Hello World の init() 内に Director というものがあるかと思います。

- Director はゲーム全体の状態を管理しています(シングルトンクラス)
- シーンの処理、画面サイズ、時間(フレーム)などを情報を持っています

Directorクラスの各メソッドを呼ぶ方法

```cpp
Director::getInstance()->hoge()
// hoge は呼びたいメソッド名
```
画面サイズを Director から取得する。

```cpp
Size visibleSize = Director::getInstance()->getVisibleSize();
// Directorが持っているvisibleSizeを取得
```

# Hello Worldに画像(Node)を追加してみよう
## [準備] 画像素材の設定
- 使用する画像を Resources フォルダに入れる。

cocos2d-x で画像や音声などのリソースファイルを指定する時は、プログラム中では Resource フォルダ以下の相対パスで指定します。

```cpp
auto apple = Sprite::create("images/hoge.png");
// images フォルダ内の hoge.png を読み込む
```

また、searchPath という仕組みを利用するとフォルダ名を事前に探索し、ファイル名だけで指定できるようになります。

```cpp
// AppDelegate.cppの
// applicationDidFinishLaunching()メソッド内に記入
FileUtils::getInstance()->addSearchPath("images");

```
## [ノード操作その1] Spriteの作成

画像ファイルの Sprite を作成し、配置してみましょう。

```cpp
// ノード操作　
// 画像ファイルとを指定してスプライトを作成
Sprite* player = Sprite::create("character.png");

// 座標を設定
player->setPosition(Vec2(300,300));
    
// シーンにスプライトを追加
this->addChild(player);
```

- playerというSpriteを作成
- 座標を設定
- this(Scene)にSpriteを追加


## [ノード操作その2] 子ノードの取得

Nodeをさらに子Nodeとして扱うことで親子関係にすることができます。
Nodeにはタグを付けることができ、Nodeを指定して処理を行うこともできます。

```cpp
//ノード操作　子ノードの取得テスト
//親ノードを作る
Node* fruits = Node::create();
    
Sprite* apple = Sprite::create("fruit0.png");
Sprite* grape = Sprite::create("fruit1.png");
Sprite* orange = Sprite::create("fruit2.png");
    
//タグをつける
apple->setTag(1);
grape->setTag(2);
orange->setTag(3);
    
//それぞれをfruitsの子ノードにする
fruits->addChild(apple);
fruits->addChild(grape);
fruits->addChild(orange);
    
//appleを取り出す
Sprite *fruit01 = (Sprite*)fruits->getChildByTag(1);
Sprite *fruit02 = (Sprite*)fruits->getChildByTag(2);
Sprite *fruit03 = (Sprite*)fruits->getChildByTag(3);
    
fruit01->setPosition(Vec2(500,500));
fruit02->setPosition(Vec2(400,500));
fruit03->setPosition(Vec2(300,500));
    
// シーンにスプライトを追加
this->addChild(fruits);
```
- fruitsという親Nodeを作成
- 果物のSprite(apple, grape, orange)を作成
- 果物にタグをつける
- fruits(親)に果物を子として設定
- getByChildで取り出す(Node型になってしまうため、Sprite型に型変換する必要がある)
- それぞれにタグをつける
- this(Scene)にfruits(親)を追加

## [ノード操作その3] ボタンクリックでノードの座標を操作

Hello World の menuClose ボタンのメソッドを再利用して、ノードを瞬間移動させる処理を作ってみます。

```cpp
void HelloWorld::menuCloseCallback(Ref* pSender)
{
 // ~~~~~~略~~~~~~~~
 // Director::getInstance()->end();
 // ~~~~~~略~~~~~~~~
 // exit(0);
 // ~~~~~~略~~~~~~~~
}
```
この二つがアプリを終了させているメソッドのようなのでコメントアウト
<br>

```cpp
fruits->setTag(4649);
```
HelloWorld::init()内のfruits(親)にタグをつける

```cpp
 Node* fruits = this->getChildByTag(4649);
 fruits->setPosition(Vec2(100,100));
```
menuCloseCallback内に記入

- 4649タグでfruitsを取り出す
- setPositionで座標移動を設定
- 右下のボタンをクリックするとノードが座標移動

親ノードが動くと子ノードも同時に座標移動することが分かると思います。

# まとめ

- Cocos2d-xは2D表現を得意とする、ゲーム専用フレームワークである
- 処理速度が速く、無料で使える
- Nodeを組み合わせることでシーンの中身を構成しながら、ゲームを開発する。

# おわりに
今回はCocos2d-xのセットアップからNodeの仕組みまでを紹介させて頂きました。
ほんの最初の部分で、これだけではまだゲームを作ることはできませんが
この記事を読んでくれた人がゲーム制作や、Cocosを始めるきっかけになってくれればいいなと思います。
[CYBIRD エンジニア Advent Calendar] (http://qiita.com/advent-calendar/2015/cybird) 明日は、（@megadreams14）さんの
「開発の見える化に取り組んでみた」です。