Cocos StudioでのResourceパスに関するバグについて

木内智史之介(シャッチョー)
ミンカさんけっこんしてくださいおねがいします(ズザー SEGAさん、DIVAの筐体ください(ズザー

みなさん、Cocos Studio使っていますか?

最近、似たようなツールで「Cocos Creator」などを出してきたcocos2d-x勢ですが、 UI構築ツールとして、どちらを伸ばしていくつもりなんでしょうか?

このあたり、しっかり一つに絞って、「実用に耐えうるプロダクト」をどちらにしても世に送り出してほしいものです。

そんなCocos Studioの奇々怪々なバグに関して、今回紹介したいと思います。

画像が読み込めないよ!

「さて、ひとまず、背景だけ置いた適当なシーンをサクッと作成してみるか」
と意気揚々と作業を始めたんですよ。
けど、シーンをプレビューしてみても、ウンともスンとも言わない訳です。

画像を1枚、シーンに配置するだけの簡単な内容なものですから、

うわ~ヤダなァ~、気持ち悪いなァ~

なんて思うわけです。

まさか、ここから長い旅が始まるとは夢にも思わなかったんですね…。

画像が読み込めなかった構成

画像が読み込めなかった構成はこんな感じです。

RootSceneに画像を一枚置いているだけの構成で、なんも難しい事はしていません。
それでも、画像が表示されないんです。

問題が起きない構成

ちなみに、こんな構成なら問題は起きませんでした。

ちょwそしたらシーンやレイヤーファイルは全部rootに配置しろってことですか?

オラ、そんなCocos Studioいやだァ〜!

というわけで、なんとかこの画像の参照問題を解決したいと思います。

どうして画像が読み込めないのか?

どうして、root直下以外にシーンファイルを配置すると、パブリッシュした際に画像の参照関係が崩れるのでしょうか?
それを把握するためには、まず、パブリッシュされるシーンのjsonファイルを確認する必要性があります。

Scene/Root/RootScene.json

{ </div></div>
</span>"ID": "af253853-3fe7-4be2-8d9a-b5615a70596a", </div></div>
</span>"Version": "3.10.0.0", </div></div>
</span>"Name": "RootScene", </div></div>
</span>"Content": { </div></div>
</span>"Content": { </div></div>
</span>"ObjectData": { </div></div>
</span>"Children": [ </div></div>
</span>{ </div></div>
</span>"FileData": { </div></div>
</span>"Type": "Normal", </div></div>
</span>"Path": "Scene/Root/image/UI_Board_backguound.png", </div></div>
</span>"Plist": "" </div></div>
</span>}, </div></div>
</span>"Name": "UI_Board_backguound_1", </div></div>
</span>"ctype": "SpriteObjectData" </div></div>
</span>} </div></div>
</span>], </div></div>
</span>"Name": "Scene", </div></div>
</span>"ctype": "SingleNodeObjectData" </div></div>
</span>}, </div></div>
</span>"UsedResources": [ </div></div>
</span>"image/UI_Board_backguound.png" </div></div>
</span>], </div></div>
</span>} </div></div>
</span>}, </div></div>
</span>"Type": "Scene"
}
</pre></div></figure> ※今回のバグと直接関係のない項目は取り除いて記載しています うん、内容は、過不足なく必要な情報が揃っているように見えます。 **じゃあ、このjsonデータを元に、使用リソースなどを読み込んだりするパーサ周りに関するバグだろう**と目星を付けます。 ### パーサの確認 シーンファイルの解釈を行うパーサは ``timelineParser-2.x.js`` で、 実際パースを行うメソッドは、その中の ``parse`` メソッドです。 その中でパス関係の重要な決定をしている箇所のコードがこんな感じになっていました。
if(path !== undefined)
resourcePath = path;
else
// fileはjsonファイルのパスが渡ってきます
// res/Scene/Root/RootScene.json
resourcePath = this._dirname(file);
ここで決定される ``resourcePath`` に、先ほどのjsonデータの中の ``FileData.Path`` を繋げたパスが、参照リソースのURLとなります。 #### 以上の情報を整理するとこんな変数内容になる - **file**: res/Scene/Root/RootScene.json - **resourcePath**: res/Scene/Root - **依存リソースのpath(FileData.Path)**: Scene/Root/image/UI_Board_backguound.png - **読み込むリソースのパス**: res/Scene/Root/Scene/Root/image/UI_Board_backguound.png おぉう??! 明らかに「読み込むリソースのパス」がおかしな事になってるじゃないか! つまり、これって、 - **シーン.jsonでは、プロジェクトルートからのパスで記載しているのに** - **読み込む時にはシーンファイルからのパスで読み込もうとしている** という事ですよね? こりゃ、読み込めない訳だ… ### どうしてこんな事になっちゃうの? けど、どうしてこんな事になってるんでしょう? 素直に、プロジェクトルートからのパスとして解釈するように統一すればいいのに、と...。 原因は、これです。
// file = res/Scene/Root/RootScene.json
// resourcePath = res/Scene/Root
resourcePath = this._dirname(file);
ここで「res」という、cocos studioプロジェクトが直接把握できないパスを含んでいるため、そうせざるを得ない、という状況がありそうです。 つまり、手元にあるパス情報の中で、どこからがプロジェクト内のパスで、どこまでがプロジェクト外のパスなのか、判別不能、と。 せめて、Scene.jsonでシーン自身のプロジェクト内でのパス情報さえあれば、``file``との差分で割り出しもできるのに、含んでいないんですよね…。 ## このバグの直し方 というわけで、自分がおこなった修正はこんな感じです。 #### project.json
{ </div></div>
</span>"resourceDir": "res",
}
</pre></div></figure> project.jsonに、上記のように、パブリッシュ先のディレクトリを追加します。 #### timelineParser-2.x.js (parseメソッド内の一部)
var resourcePath;
if(path !== undefined)
{
resourcePath = path;
}
else if (cc.game.config && cc.game.config.resourceDir)
{
var dirs = (typeof cc.game.config.resourceDir == "string") ? [cc.game.config.resourceDir] : cc.game.config.resourceDir;
for (var i = 0; i < dirs.length; i++) {
var dir = dirs[i];
if (file.indexOf(dir) > -1) {
resourcePath = dir;
break;
}
}
if (! resourcePath) this._dirname(file);
}
else
{
resourcePath = this._dirname(file);
}
if (resourcePath.substr(-1) != "/") resourcePath = resourcePath + "/";
これで、シーンファイルをプロジェクトツリーのどこに配置しても、画像を正常にロードできるようになりました! ではではノシ