hyoromoのブログ

最近はVRSNS向けに作ったものについて書いています

CocosBuilderでマルチ解像度対応

今回はCocos2d向けUI作成ツール「CocosBuilder」を使ってマルチ解像度対応したUIを作っちゃおう!な内容を書きます。Cocos2d-xのセットアップが未だな場合は前回エントリーを参照ください。

実施環境

  • CocosBuilder 3.0 α5
  • Cocos2d-x 2.1.4

今回の目標

CocosBuilderを使ってiOS/Android向けにマルチ解像度に対応したUIを作成する。

CocosBuilderをインストール

CocosBuilderページからどうぞ。利用しているCocos2d-xのバージョンと対になるCocosBuilderのバージョンが存在する為、よくバージョン番号を確認してからダウンロードしてください。

CocosBuilder上でUI専用プロジェクトを新規作成

  1. CocosBuilderを起動
  2. メニュー上の「File > New > Project」を選択
  3. 新規プロジェクト名を設定してCocos2d-xで作成したプロジェクト内に作成*1
  4. 新規作成したプロジェクト内の「Resources」フォルダ内にはテンプレUIがありますが、邪魔になるので全て削除
  5. Cocos2d-xで作成したプロジェクト直下にある「Resources」ディレクトリを削除

UI専用プロジェクトの設定変更

  1. メニュー上の「File > Publish Settings」を選択
  2. HTML5のチェックを外し、Androidにチェックを入れる*2

UIファイルを新規作成

今回は横向きの画面を作成します。

  1. メニュー上の「File > New > Interface File」を選択
  2. 「Create a new Document」ダイアログが表示され、CocosBuilder上での表示解像度を選ばされます。今回は「iPhone Landscape」にチェックが付いている状態のまま「Create」ボタンを押下
  3. 初回起動させるUIファイル名は「MainScene」と付けます。他の名前を設定したい場合は「メニュー > Project Settings」を選択して「Start ccb-file name」の設定を変更する必要があります
  4. UIプロジェクトの「Resources」ディレクトリ内にファイル作成*3
表示解像度の変更/切り替え

「Create a new Document」ダイアログ上で設定した表示解像度は、CocosBuilderのメニューにある「Document > Edit Resolutions」から編集できます。表示解像度の種類を増やすとメニューにある「Document > Resolutions」から表示解像度毎の見た目に切り替えて確認できます。

UI作成

  1. 画像をUI上に配置する場合「UIプロジェクト > Resources」直下に「resources-auto」ディレクトリを作成し、このディレクトリ内に画像を追加していきます。なお、追加する画像はUIファイル作成時に設定したスケールがベースサイズ(scale 4.0)となる
  2. 適当に作成。今回は分かりやすいように上下左右中央にCCSpriteを配置
  3. メニュー上の「File > Save」を選択してUIファイルを保存
  4. メニュー上の「File > Publish」を選択してCocos2d向けのファイルを生成

UI読み込み

Cocos2dxで作成したプロジェクト内の「Classes > AppDelegate.cpp」を開いて「AppDelegate::applicationDidFinishLaunching」メソッド内に以下のコードを追加します。なお、今回は横向きを想定しての数値設定な為、もし縦向き対応させる場合は縦横の設定値を全て逆にする必要がある

bool AppDelegate::applicationDidFinishLaunching()
{
    // initialize director
    CCDirector *pDirector = CCDirector::sharedDirector();
    pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());
    
    /* ここから追加コード */
    
    CCSize designSize = CCSizeMake(480, 320); // ベースサイズ
    CCSize resourceSize;
    CCSize screenSize = CCEGLView::sharedOpenGLView()->getFrameSize();
    
    std::vector<std::string> searchPaths;
    std::vector<std::string> resDirOrders;
    
    TargetPlatform platform = CCApplication::sharedApplication()->getTargetPlatform();
    if (platform == kTargetIphone || platform == kTargetIpad) {
        searchPaths.push_back("Published-iOS");
        CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
        
        if (screenSize.height > 768) {
            resourceSize = CCSizeMake(2048, 1536);
            resDirOrders.push_back("resources-ipadhd");
        } else if (screenSize.height > 640) {
            resourceSize = CCSizeMake(1536, 768);
            resDirOrders.push_back("resources-ipad");
        } else if (screenSize.height > 480) {
            if (screenSize.width < 1536) {
                // 4インチ
                resourceSize = CCSizeMake(1136, 640);
            } else {
                // 3.5インチ
                resourceSize = CCSizeMake(960, 640);
                }
            resDirOrders.push_back("resources-iphonehd");
        } else {
            resourceSize = CCSizeMake(480, 320);
            resDirOrders.push_back("resources-iphone");
        }
        
        CCFileUtils::sharedFileUtils()->setSearchResolutionsOrder(resDirOrders);
    } else if (platform == kTargetAndroid) {
        if (screenSize.height > 1200) {
            resourceSize = CCSizeMake(1200, 800);
            resDirOrders.push_back("resources-xlarge");
        } else if (screenSize.height > 960) {
            resourceSize = CCSizeMake(960, 640);
            resDirOrders.push_back("resources-large");
        } else if (screenSize.height > 480) {
            resourceSize = CCSizeMake(720, 480);
            resDirOrders.push_back("resources-medium");
        } else {
            resourceSize = CCSizeMake(568, 320);
            resDirOrders.push_back("resources-small");
        }
        
        CCFileUtils::sharedFileUtils()->setSearchResolutionsOrder(resDirOrders);
    }

    pDirector->setContentScaleFactor(resourceSize.width / designSize.width);
    CCEGLView::sharedOpenGLView()->setDesignResolutionSize(designSize.width, designSize.height, kResolutionFixedHeight);

    /* ここまでが追加コード */

    // turn on display FPS
    pDirector->setDisplayStats(true);
    
    // set FPS. the default value is 1.0/60 if you don't call this
    pDirector->setAnimationInterval(1.0 / 60);

    ScriptingCore* sc = ScriptingCore::getInstance();
    sc->addRegisterCallback(register_all_cocos2dx);
    sc->addRegisterCallback(register_all_cocos2dx_extension);
    sc->addRegisterCallback(register_all_cocos2dx_extension_manual);
    sc->addRegisterCallback(register_cocos2dx_js_extensions);
    sc->addRegisterCallback(register_CCBuilderReader);
    sc->addRegisterCallback(jsb_register_chipmunk);
    sc->addRegisterCallback(jsb_register_system);
    sc->addRegisterCallback(JSB_register_opengl);
    sc->addRegisterCallback(MinXmlHttpRequest::_js_register);
    sc->addRegisterCallback(register_jsb_websocket);
    
    sc->start();
    
    CCScriptEngineProtocol *pEngine = ScriptingCore::getInstance();
    CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
    ScriptingCore::getInstance()->runScript("main.js");
    
    return true;
}

コードはCocosBuilderのメニュー上の「Help > CocosBuilder User Guide」の「4c」とほぼ同じです。リソースの読み込み先を指定し、端末解像度に合わせてUIをスケールさせてます。

スケール方法

CCEGLView::sharedOpenGLView()->setDesignResolutionSize は最後の引数に設定する値はスケール方法となっており以下の値が設定可能です

意味
kResolutionExactFit 画面比率を無視して、端末解像度に合わせて設定する。はみ出しや余白が生じない
kResolutionNoBorder 画面比率を維持して、端末解像度いっぱいに設定する。縦横のどちらかがはみ出る
kResolutionShowAll 画面比率を維持して、端末解像度に合わせて設定する。縦横のどちらかに余白が生じる
kResolutionFixedHeight 画面比率を維持して、端末解像度の高さに合わせて設定する。横がはみ出しや余白が生じる
kResolutionFixedWidth 画面比率を維持して、端末解像度の幅に合わせて設定する。縦がはみ出しや余白が生じる
別のUIファイル読み込み方法

上記サンプルコードは「main.js」を読み込む事で「MainScene.ccbi」を読み込んでいます。jsを介さなくても以下のようにcpp側からccbiファイルを直接読み込むことが出来ます。

cocos2d::extension::CCNodeLoaderLibrary *lib = cocos2d::extension::CCNodeLoaderLibrary::newDefaultCCNodeLoaderLibrary();
cocos2d::extension::CCBReader *reader = new cocos2d::extension::CCBReader(lib);
CCScene *scene = reader->createSceneWithNodeGraphFromFile("MainScene.ccbi");
pDirector->runWithScene(scene);

Xcodeで実行

  1. Cocos2d-xで作成したプロジェクトをXcodeで起動
  2. プロジェクト上から「Resources」を削除
  3. UIプロジェクト内の「Published-iOS」フォルダを追加。フォルダ追加の際に「Folders」項目を「Create folder references for any added folders」に設定しておくと楽できます*4
  4. Buildして端末上で確認

Androidで実行

assetsへ必要ファイルをコピーさせる

Cocos2dxで作成したプロジェクト内の「proj.android > build_native.sh」をテキストエディタで開き、以下のように置き換えます。

# 以下の2行を
# copy Resources/* into assets' root
cp -rf "$APP_ROOT"/Resources/* "$APP_ANDROID_ROOT"/assets

# 以下の2行に置き換え
# copy CocosBuilder//Published-Android/* into assets' root
cp -rf "$APP_ROOT"/(UI専用プロジェクト名)/Published-Android/* "$APP_ANDROID_ROOT"/assets
実行
  1. Cocos2d-xで作成したプロジェクトをAndroidで起動
  2. Buildして端末上で確認

まとめ

iOSはシミュレータでだいたい大丈夫そうなのが分かりましたが、Androidはそんなに確認してないので今回の方法だと問題あるかも...

*1:今回は「CocosBuilder」という名前でプロジェクト直下に作成しています

*2:xsmallはもう対応しなくても良いと思うのでチェックを外していますが、別に付けたままでも良いと思います

*3:Layerを複数作成する場合、Layer専用ディレクトリを用意した方が整理出来て良いです

*4:groupとして追加すると、ファイルが増える度にイチイチ追加する必要がある為