Google+ もご覧ください
ユーザーアイコン

cocos2d javascript bindingsでマルチプラットフォーム開発

第八回 解像度に合わせた画像を利用するには

Seasons

第八回 解像度に合わせた画像を利用するには

前回(第七回)はiPhone 5、iPod touch 5th gen以降に搭載された4inchディスプレイの対応方法について解説しました。しかし、まだ完全ではありません。

前回も解説した通り、cocos2d-xで生成するJSBの新規プロジェクトは、iPhoneのRetina Display上における適切な画像の扱いに対応していません。 今回はその方法について解説していきます。

cocos2d-x と マルチプラットフォーム

cocos2d-iphoneではRetina Displayやそれ以外の解像度に対して内部で識別し、ある程度適切に対応してくれます。

一方cocos2d-xでは、実際に試してみたようにRetina Displayかどうかの識別は行っておらず、解像度にあわせた画像を用意しても同じ画像を利用します。そのため高解像度のRetina Displayでは画像がどうしても小さく表示されてしまいます。

大きな理由として推測されるのは、cocos2d-xはマルチプラットフォームを前提にした設計なので1つのソース内でプラットフォームの違いを吸収しなくてはいけません。開発者がどのプラットフォームを対象に制作をするかは、cocos2d-x開発サイドでは知る術がないために利用サイドに実装をゆだねていると筆者は考えています。

解像度に合わせたファイル管理

Xcodeにおけるファイル管理とバンドル

前述の通り、cocos2d-xではマルチプラットフォーム対応がベースになっているため、iPhone版のcocos2dとはファイルの管理方法が少々ことなります。 iOSでは特に気にして制作しない限り、最終的に.appにバンドルされるリソースは、フラットに格納されます。

フラット
フラット

つまり、Xcode上でいくらグループなどを作りフォルダ構造を管理しても、そのまま格納されるわけではありません。これはすなわち、解像度ごとに同じファイル名で用意してしまうと、cocos2d側が解像度にあわせてどの画像を読み込んでよいか分からなくなってしまいます1

そのため、iOSでは@2xというSuffixをファイル名に付けることでRetina Display用のファイル。-ipadでiPad用のファイルなどというようにファイル名で管理していました。cocos2d-xでは一般的にそのような管理方法ではなく、解像度ごとのフォルダを用意し、実行時に参照するパスを設定して読み込みます。そのため画像名は同じである必要があります。

解像度ごとのフォルダ作成
解像度ごとのフォルダ作成

フォルダ構造のままXcodeへの登録する

Xcodeでは最終的にバンドルされる時にフォルダ構造がばらされてフラットに並ぶと説明しましたが、これはあくまで特に気にせず作っていた場合であり、Xcodeにはフォルダ構造を保ったままバンドルする方法があります。

1. 作成したフォルダごとXcodeにドラッグ&ドロップする際に出てくるダイアログにて、赤枠で囲った方を選択します。**

Xcodeでのファイル指定
Xcodeでのファイル指定

2. 登録後された後のフォルダの色が青になっていることを確認してください。**

フォルダの色を確認
フォルダの色を確認

この状態でビルドすると画像はフォルダ構造を保ったまま.appにバンドルされます。また、新規に画像を追加する場合、Xcodeは常にこのフォルダ内を監視しているため、Xcodeにドラッグ&ドロップして追加する必要はなくなります。フォルダにファイルを追加した時点で自動的にXcodeに登録されます。

これは楽な反面、その中に含まれているファイル全てが登録されるので不要なファイルは含めておかないように注意が必要です。

解像度にあわせたファイルの読み込み処理を追加する

次に解像度にあわせて、参照するパスを決定するプログラムを追加します。

Classes/AppDelegate.cpp/hを開いて以下のコードを追加してください。

# AppDelegate.h

class  AppDelegate : private cocos2d::CCApplication
{
public:
    AppDelegate();
    virtual ~AppDelegate();

    /* 省略 */

    // 追加
    void setupMultiResolution();

};

#endif // _APP_DELEGATE_H_

# AppDelegate.cpp

void AppDelegate::setupMultiResolution( void ) {

    CCDirector *pDirector = CCDirector::sharedDirector();

    std::vector<std::string> searchPaths;
    std::vector<std::string> resDirOrders;

    CCSize screenSize = CCEGLView::sharedOpenGLView()->getFrameSize();
    CCSize designSize = CCSizeMake(320, 480);
    CCSize resourceSize = CCSizeMake(320, 480);

    TargetPlatform platform = CCApplication::sharedApplication()->getTargetPlatform();

    // iPhone, iPad上で実行時
    if (platform == kTargetIphone || platform == kTargetIpad)
    {
        CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);

        if (screenSize.height > 480)
        {
            if (screenSize.height > 960) {
                // iphone 5,5s, ipod touch 5th gen
                resourceSize = CCSizeMake(640, 1136);
                designSize = CCSizeMake(320, 1136/2);
            } else {
                resourceSize = CCSizeMake(640, 960);
            }
            resDirOrders.push_back("resources-iphone-hd");
        }
        else
        {
            resDirOrders.push_back("resources-iphone");
        }

        CCFileUtils::sharedFileUtils()->setSearchResolutionsOrder(resDirOrders);
    }

    pDirector->setContentScaleFactor(resourceSize.width/designSize.width);

    CCEGLView::sharedOpenGLView()->setDesignResolutionSize(designSize.width, designSize.height, kResolutionShowAll);
}

applicationDidFinishLaunchingの関数内に setupMultiResolutionの呼び出しを追加します。

bool AppDelegate::applicationDidFinishLaunching()
{
    // initialize director
    CCDirector *pDirector = CCDirector::sharedDirector();

    pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());

    // マルチ解像度用の画像参照用パス(<=これを追加)
    this->setupMultiResolution();

    /* 省略 */

今回追加したsetupMultiResolutionによって、実行時に画面解像度を取得、そのサイズに応じて、cc.Spriteなどで参照する画像の場所を指定します。

指定した後、setContentScaleFactor()を設定します。これにより特にiOSでは、ポイント -> ピクセルの変換を正しくすることが出来ます。

最後にsetDesignResolutionSize()を呼び出し、最終的に確定した解像度をOpenGL側に伝えておきます。

テストプログラムで動作確認をする

さて、このプログラムが正しく動作するかどうか hello.jsにプログラムを追加してテストしてみます。 hello.jsを以下のように書き換えてください。

require("jsb.js");

try {

    director = cc.Director.getInstance();
    winSize = director.getWinSize();
    centerPos = cc.p(winSize.width / 2, winSize.height / 2);

    var GameLayer = cc.Layer.extend({

        ctor: function() {
            this._super();

            var iconSize = cc.size(57, 57);
            var num = Math.floor(winSize.width / iconSize.width);

            for (var i = 0; i < num; i++) {
                // Sprite
                var sprite = cc.Sprite.create("Icon.png");
                var size = sprite.getTextureRect();
                sprite.setPosition(cc.p(
                    size.width / 2 + i * iconSize.width,
                    size.height / 2));
                this.addChild(sprite);
            };

            // Label
            var label = cc.LabelTTF.create("Hello cocos2d-x", "Arial", 20);
            label.setPosition(cc.p(winSize.width / 2, winSize.height / 2));
            this.addChild(label);
        }

    });

    var game = new GameLayer();

    __jsc__.garbageCollect();

    // LOADING PLAY SCENE UNTILL CCBREADER IS FIXED

    director.runWithScene(game);

} catch (e) {
    log(e);
}

実行結果が以下のようにスクリーン左下にアイコンが5つ表示されれば正解です。

仮に setupMultiResolution()を呼び出さずに実行した場合は、これよりも沢山の小さいアイコンが表示されるはずです。同時にラベルも小さくなっています。

実行結果
実行結果

うまくいかない場合は、XcodeでCleanを実行してからビルドし直すなどを試してみてください。

次回予告

さて、これまで第1〜8回までを通して、cocos2d-x JSBにおける環境のセットアップやお作法などを学んできました。これでcocos2d-x JSBを使ったプログラミングを始めることが出来ますがよりコーディングを快適にするためのTipsや作業環境についてについて次回は紹介したいと思います。

今回のサンプルプロジェクトは、こちらからダウンロードできます。


  1. 同名ファイルを.appにバンドルしようとする場合、Xcodeで警告として表示されます。 

Cocos2d jsb
タグ:

記事をリクエストする

関連記事

コメント