Cocos Studio2を触ってみた

[CYBIRDエンジニア Advent Calendar 2015](http://qiita.com/advent-calendar/2015/cybird) 17日目の@doidoidonです。

今年は暖冬のうちにいつの間にかもうすぐクリスマスですねー。昨年も色々開発プロジェクトでもがきながら、Advent Calender2014の記事を投稿したのを思い出しました。最近はあまりコードを書くこともなく会議三昧の毎日なので、久々にエンジニアっぽい記事を書くことに少し気持ちが高揚してます。
昨日はサイバードのデータ分析基盤を支えるカリスマリードエンジニア@yuichi_komatsuさんの[EmbulkとBigQueryが黄金コンビすぎる話](http://qiita.com/yuichi_komatsu/items/3aae65c362b2a57f6fbf)でした。なかなかつぼを押さえた検証と考察の中に、データ分析アーキテクチャーをキャプテン翼くんの登場キャラクターで例えるという、ひときわ光るたとえ話を織り交ぜ、他の追随を許さないテイストに仕上がってましたねー

## 本日の内容

最近社内で参加者の持ち回り講師の形でCocos2d-xの勉強会を行ってまして、Cocosアプリなど作ったことのない自分はありがたくもCocos Studioの使い方について講義することを拝命しましたので、ちょこちょこ勉強した内容をここにこっそり発表したいと思います。

## Cocos Studioとは

Cocos Studioとは、公式で提供されているUIエディターです。

![CocoStudioLogo.png](https://qiita-image-store.s3.amazonaws.com/0/60925/c164d0a1-7968-7b17-f95d-dca015aef707.png)

GUI操作でレイアウトを組み立て、調整することができる便利なツールなので、仕様書見ながらエンジニアがミリミリ各オブジェクトのサイズや座標調整をやる必要がなくなります。思えば昨年担当していたゲーム開発プロジェクトでは、まさにエンジニアがミリミリレイアウト調整をやりビルドに時間がかかって開発工数を圧迫してました。。。。入れておけばよかったと後悔してます。。。

## 何はともあれ環境構築

#### Cocos2d-xのインストール

当たり前ですがCocos2d-xをインストールし、Cocos Studioで組んだレイアウトを組み込むCocos2d-xのプロジェクトを作っておきます

_参考にしたサイト_
_[[Cocos2d-x ver3.4] MacOSXインストール手順](http://qiita.com/y1row/items/c8f0b0225ec05fbc8c8e)_

#### Cocos Studioのインストール

Cocos（+CocosStudio）をインストールし、プロジェクトを作成します
今回はCocos2d-xの作業とCocosStudioの作業を両方自分がやるので、CocosStudioのプロジェクトファイルをCocos2d-xのプロジェクトファイル内に移しておきます
こうしておくとCocosStudioでPublishしたcsbファイルをすぐCocos2d-x側でビルド組み込みできるので少し楽、というだけです（本来は作業者が分かれると思うので、ここを一緒にする必要はないと思います）

_参考にしたサイト：_
_[2015/11現在のCocos2d-X(とCocosStudio)インストール方法最新版](http://qiita.com/kohashi/items/85ba68e4e472a8ef4387)_
_[[Cocos2d-x] Cocos Studio2 を使ってみる (基本編)](http://studio.cretia.net/blog/387)_

とりあえず、作業環境が準備できました

## まずはレイアウトを作成してみよう

#### 作業手順
- Nodeの作成
- 画像の追加とNodeへ配置
- シミュレーターで確認
- Publishしてcsbファイルをビルド

#### Nodeの作成

Resourcesのプロジェクト下にNewFileでNodeを追加します

![cocosstudio_newfile.png](https://qiita-image-store.s3.amazonaws.com/0/60925/09214601-f71e-8411-824c-46e936b0bc75.png)

NewFileダイアログでNodeを選択して、File Nameを設定してNewボタンを押下します

![cocosstudio_nodenew.png](https://qiita-image-store.s3.amazonaws.com/0/60925/83ab288b-894b-32d0-d593-88402e13929e.png)

Nodeが追加されました（何もないように見えるがプロジェクトの下にNodeが追加されてます）

![cocosstudio_startnode.png](https://qiita-image-store.s3.amazonaws.com/0/60925/b198b500-099b-5793-e00f-847dc5f4169a.png)

#### 画像の追加とNodeへ配置

レイアウトで使う画像をCocos StudioのResourcesにドラッグ＆ドロップで追加します

![cocosstudio_imgadd.png](https://qiita-image-store.s3.amazonaws.com/0/60925/465b46a4-5f8f-4d33-dc70-267909b961ae.png)

追加した画像をステージにドラッグ＆ドロップで追加し、レイアウトを作成します

![cocosstudio_imgdrag.png](https://qiita-image-store.s3.amazonaws.com/0/60925/ebda1755-8770-78d6-8780-4dcd2f86ce83.png)

#### シミュレーターで確認

ヘッダメニューにある矢印を押してシミュレーターで表示してみます

![cocosstudio_previewheader.png](https://qiita-image-store.s3.amazonaws.com/0/60925/de60d120-0d7c-b501-5b60-68fa64a3c42f.png)

![cocosstudio_preview.png](https://qiita-image-store.s3.amazonaws.com/0/60925/9d640d09-32d5-912c-c55f-20c740b9f501.png)

この時点でプロジェクトファイル内のcocosstudioフォルダにcsdファイルが生成されています

![cocosstudio_csd.png](https://qiita-image-store.s3.amazonaws.com/0/60925/975f25e8-6faa-2621-4b69-ecc7a2ca0ed3.png)

試しに定義ファイル（csdファイル）の中身を見るとXMLでこんな感じで定義されてます

~~~xml:sample.csd
<GameFile>
  <PropertyGroup Name="startNode" Type="Node" ID="8b6553db-9070-4403-ac8f-61aef56b56b0" Version="2.3.3.0" />
  <Content ctype="GameProjectContent">
    <Content>
      <Animation Duration="0" Speed="1.0000" />
      <ObjectData Name="Node" Tag="8" ctype="GameNodeObjectData" />
    </Content>
  </Content>
</GameFile>
~~~

#### Publishしてcsbファイルをビルド

csdファイルをそのままCocos2d-xに組み込むこともできるようですが、今回はビルドしたcsbファイルの方を組み込んでみます
ヘッダメニューよりPublishを選択します

![cocosstudio_publish.png](https://qiita-image-store.s3.amazonaws.com/0/60925/68b125c6-45ac-1937-8d10-3a9448ccd196.png)

設定ダイアログが表示されるので、Publish Resourceを選択してPublishします（これでcsbファイルがビルドされます）

![cocosstudio_publishdialog.png](https://qiita-image-store.s3.amazonaws.com/0/60925/bf8e4038-bcca-91ce-2309-ba621eaec0b3.png)

## 作成したバイナリをCocos2d-xでロードして画面に表示

#### 作成手順
- TOPページ用レイアウトを作成してPublish
- Topページ用のTopSceneクラスを作成
- csbファイルを読み込んでノード追加
- シミュレーターで確認

#### TOPページ用レイアウトを作成してPublish

まずTopページ用のレイアウトにするためにCocos Studioでタイトルロゴとスタートボタンを追加してPublishし直します
スタートボタンは画像ではなくボタンオブジェクトで追加します

![cocosstudio_buttonadd.png](https://qiita-image-store.s3.amazonaws.com/0/60925/cb5a079e-6c43-0b1a-5876-76dd9b1a514f.png)

ボタンオブジェクトのFeature - Backgroundプロパティにボタン画像をドラッグ＆ドロップします。また、Nameプロパティは後々Cocos2d-x側でボタンタップ時の制御を追加するときにこのNameを元にオブジェクトを特定しますので、意味のある名前をつけます。今回は「btn_start」としました

![cocosstudio_buttonimg.png](https://qiita-image-store.s3.amazonaws.com/0/60925/c8364a9e-f15c-61d2-3779-26609c1de23d.png)

プレビューするとこんな感じです

![cocosstudio_toppage.png](https://qiita-image-store.s3.amazonaws.com/0/60925/f6793d62-6286-5872-32ee-f8dc7a58ceb3.png)

Publishしてcsbファイルを作成します
これでCocos Studioのレイアウト作成は完了しました

#### Topページ用のTopSceneクラスを作成

Cocos2d-xでTopページ用のTopSceneクラスを作成します
まずヘッダファイルに以下の2つをincludeします

~~~cpp:TopScene.hpp
// ...省略

#include "cocostudio/CocoStudio.h"
#include "cocosGUI.h"

// ...省略
~~~

あとは通常のSceneクラスの要領で作成します
自分はこんな感じにしてみました

~~~cpp:TopScene.hpp
#include "cocos2d.h"
#include "cocostudio/CocoStudio.h"
#include "cocosGUI.h"

class TopScene : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();
    virtual bool init();
    CREATE_FUNC(TopScene);
    static void pushBtnCallback(Ref *object);
};
~~~

#### csbファイルを読み込んでノード追加

csbファイルの読み込みはcppファイルのinitメソッド内にこんな感じで組み込みます
CSLoader::getInstance()->createNodeメソッドでcsbファイルをロードし、表示位置を調整した上でthis->addChildメソッドで追加してます

~~~cpp:TopScene.cpp
bool TopScene::init()
{
    // ...省略

    // Directorを取り出す
    auto director = Director::getInstance();
    // 画面サイズを取り出す
    auto size = director->getWinSize();
    // TopSceneのCocosStudioバイナリを読み込む
    auto node = CSLoader::getInstance()->createNode("startNode.csb");
    // スプライトの表示位置を設定する
    node->setPosition(Vec2(size.width / 2.0, size.height / 2.0));
    this->addChild(node);

    // ...省略

    return true;
}
~~~

Cocos2d-xのシミュレーターで見てみます

![cocos2dx_Toppage.png](https://qiita-image-store.s3.amazonaws.com/0/60925/03c29ad8-75b8-a157-42e1-27498bed2ba0.png)

。。。なんとなく収まってない。。。

今回は解像度を手持ちの画像サイズの関係で640x960で試しているんですが、Cocos Studioではうまく表示していたのがCocos2d-xに組み込むとうまくいってないですね。すみません
実はcsbファイルを組み込む過程で、Appdelegateの中で使っているsetContentScaleFactorメソッドがうまく動かずレイアウトを壊してしまうので、一旦以下のようにコメントアウトしてます。。。

~~~cpp:AppDelegate.cpp
    // ...省略
    // Set the design resolution
    glview->setDesignResolutionSize(mediumResolutionSize.width, mediumResolutionSize.height, ResolutionPolicy::NO_BORDER);
    
/*  Cocos Studioのレイアウトを読み込む場合うまく表示できないのでコメントアウト
    Size frameSize = glview->getFrameSize();
    // if the frame's height is larger than the height of medium size.
    if (frameSize.height > mediumResolutionSize.height)
    {
        director->setContentScaleFactor(MIN(largeResolutionSize.height/designResolutionSize.height, largeResolutionSize.width/designResolutionSize.width));
    }
    // if the frame's height is larger than the height of small size.
    else if (frameSize.height > smallResolutionSize.height)
    {
        director->setContentScaleFactor(MIN(mediumResolutionSize.height/designResolutionSize.height, mediumResolutionSize.width/designResolutionSize.width));
    }
    // if the frame's height is smaller than the height of medium size.
    else
    {
        director->setContentScaleFactor(MIN(smallResolutionSize.height/designResolutionSize.height, smallResolutionSize.width/designResolutionSize.width));
    }
*/
    register_all_packages();
    // ...省略
~~~

これ何ででしょうね。。。このあたりもう少し色々調べる必要があるのですが、一旦先に行ってしまいます

## ボタン処理を組み込む

#### 作業手順
- 遷移先ページのレイアウト作成
- 遷移先ページのクラスを作成
- Topページのスタートボタンにタッチイベントと遷移処理を追加

#### 遷移先ページのレイアウト作成

まず遷移先であるPlayerページのレイアウトをCocos Studioで作成します
一旦はただの背景しかないこんなページを作成してPublishします

![cocosstudio_playerpage.png](https://qiita-image-store.s3.amazonaws.com/0/60925/64f61755-9403-edf6-2030-903cbfcdd536.png)

#### 遷移先ページのクラスを作成

Cocos2d-xでPlayerSceneクラスを作成します
先ほどのシンプルなページを表示するだけなので、普通にSceneクラスを作成して、TopSceneと同じように以下の記述を追加します

~~~cpp:PlayerScene.hpp
// ...省略

#include "cocostudio/CocoStudio.h"
#include "cocosGUI.h"

// ...省略
~~~

~~~cpp:PlayerScene.cpp
bool PlayerScene::init()
{
    // ...省略

    // Directorを取り出す
    auto director = Director::getInstance();
    // 画面サイズを取り出す
    auto size = director->getWinSize();
    // PlayerSceneのCocosStudioバイナリを読み込む
    auto node = CSLoader::getInstance()->createNode("playerNode.csb");
    // スプライトの表示位置を設定する
    node->setPosition(Vec2(size.width / 2.0, size.height / 2.0));
    this->addChild(node);

    // ...省略

    return true;
}
~~~

#### Topページのスタートボタンにタッチイベントと遷移処理を追加

TopページのスタートボタンにaddTouchEventListenerメソッドを使ってタッチイベントを追加するんですが、Cocos StudioでNameプロパティに設定したボタンオブジェクトの名前キーに、getChildByNameメソッドを使ってスタートボタンを特定します
タッチイベント発火時には、今回追加したPlaerSceneへ遷移するように処理を追加してます

~~~cpp:PlayerScene.cpp
bool TopScene::init()
{
    // ...省略
    // ボタンノードを取得
    auto startBtn = node->getChildByName<ui::Button*>("bt_start");
    // タッチイベント追加
    startBtn->addTouchEventListener([this](Ref* sender, ui::Widget::TouchEventType type) {
        // タッチが終わった後に実行
        if (type == ui::Widget::TouchEventType::ENDED || type == ui::Widget::TouchEventType::CANCELED) {
            TopScene::pushBtnCallback(sender);
        }
    });
    return true;
}

void TopScene::pushBtnCallback(Ref *object){
    
    CCLOG("スタートボタンが押された");
    
    auto scene = PlayerScene::createScene();
    
    // 0.5秒かけてホワイトアウトしてTopSceneに遷移させる
    TransitionFade* fade = TransitionFade::create(0.5f, scene, Color3B::WHITE);
    
    //Splashを破棄してPlaeyrSceneに遷移する
    Director::getInstance()->replaceScene(fade);
}
~~~

あらかじめボタンのNameプロパティの値を決めておくことで、Cocos Studioでのレイアウト制作作業とCocos2d-xのエンジニアコーディング作業を並行で進めていくことができますので、そのあたりCocos Studioを使う上でのメリットになっている気がします

## スプライトシートで画像を切り替える

#### 作業手順
- スプライトシートの作成
- スプライトシートの組み込みと画像の切り替え

#### スプライトシートの作成

Cocos Studioで複数の画像を合成したスプライトシートを作成できるようなので使ってみます
まずは複数画像を放り込むフォルダを作成します

![cocosstudio_newfolder.png](https://qiita-image-store.s3.amazonaws.com/0/60925/877bb8ad-4ad9-df04-7bb9-faf9f124b05d.png)

合成する画像を全て放り込みます

![cocosstudio_importimg.png](https://qiita-image-store.s3.amazonaws.com/0/60925/09f1e045-4510-e7f4-ff94-f1c1115ef137.png)

スプライトシートを作成します

![cocosstudio_plistdialog.png](https://qiita-image-store.s3.amazonaws.com/0/60925/ea7073e0-6428-0596-5a74-95bc7af4684f.png)

合成する画像をドラッグ＆ドロップでスプライトシートに追加します

![cocosstudio_plistimg.png](https://qiita-image-store.s3.amazonaws.com/0/60925/aeb7f36b-fb4d-bd4b-423e-e805679048d2.png)

Publishするとビルドされ、plistファイルが作成されます

![cocosstudio_plist.png](https://qiita-image-store.s3.amazonaws.com/0/60925/772a2001-c5a8-8a5e-555b-cafdcec0da81.png)

ちなみにplistファイルの出力内容はこんな感じで、keyに出力されている「parts/fruit0.png」を使って画像を取り出すことになります

~~~xml:FruitsPlist.plist
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
	<dict>
		<key>frames</key>
		<dict>
			<key>parts/fruit0.png</key>
			<dict>
				<key>frame</key>
				<string>{{0,0},{32,32}}</string>
				<key>offset</key>
				<string>{0,0}</string>
				<key>rotated</key>
				<false />
				<key>sourceSize</key>
				<string>{32,32}</string>
			</dict>
			<key>parts/fruit1.png</key>
			<dict>
				<key>frame</key>
				<string>{{0,32},{32,32}}</string>
				<key>offset</key>
				<string>{0,0}</string>
				<key>rotated</key>
				<false />
				<key>sourceSize</key>
				<string>{32,32}</string>
			</dict>
<!-- ...省略 -->
	</dict>
</plist>
~~~

#### スプライトシートの組み込みと画像の切り替え

組み込み方は、まずSceneクラスのinitメソッドでplistの追加を行います

~~~cpp:PlayerScene.cpp
bool PlayerScene::init()
{
    // ...省略

    SpriteFrameCache::getInstance()->addSpriteFramesWithFile("parts/FruitsPlist.plist");

    // ...省略
    return true;
}
~~~

そして画像を取り出したいところでcreateWithSpriteFrameNameメソッドを使って取り出します

~~~cpp:PlayerScene.cpp
    // ...省略

    auto fruit = Sprite::createWithSpriteFrameName(filename);

    // ...省略
~~~

シミュレーターで実行するとこんな感じです
フルーツ画像をランダムに取り出して下に落としてます

![cocos2dx_plist.png](https://qiita-image-store.s3.amazonaws.com/0/60925/bfe8c6e1-36ea-4302-5c37-cd3a5a51b70e.png)

_今回使った素材は自分が最初に購入したCocos2d-xの書籍の付属素材です。詳細は[こちら](http://giginet.hateblo.jp/entry/2014/11/26/185855)をご確認ください_

## 最後に

ほとんどスマートフォンアプリの開発経験のない自分としては、この程度のお試しをやるだけでかなり時間がかかってしまいました。。。でも自分のやったことのない技術に触るのはとても楽しいですねー。今回はCocos Studioとはどんなもんぞ、という感じでほんの触りだけやってみましたが、サイバードは今後Cocos2d-xでいけてるゲームを作るにあたって、このUIエディターを使いこなせるかどうかは開発効率とプロセス改善にかなりの差が出ると認識してまして、今後も色々取り組んでいきたいです、ハイ。
[CYBIRDエンジニア Advent Calendar 2015](http://qiita.com/advent-calendar/2015/cybird) 明日は前日の@yuichi_komatsuさんと同じくサイバードのデータ分析エンジニアである@cy-hiroshi-chibaさんが、Google Chartsについてのあれこれをお伝えするようですよ。お楽しみに〜