最近、Unity4で作成したプロジェクトをUnity5に移行する作業をしているのですが、Unityのバージョンが進めば進むほどUnity4で動作していたものが動かなくなっていくケースが増えています。
標題の件は、既に非推奨となったBuildpipline.AssetBundleで作成したAssetBundleをUnity5.3.3p1以降のUnityでロードした際に発生しました。
非推奨とは言ってもまだBuildpipline.AssetBundleを使用すればアセットバンドルの作成は可能なので(Unity5.3.4p3までは動作していることを確認)、今のところBuildpipline.AssetBundlesに置き換えていません(修正規模が大きいため)。
http://docs.unity3d.com/ja/current/ScriptReference/BuildPipeline.BuildAssetBundle.html
そのためか、Uniyu5.3.3f1まではUnity4と変わりなかったAssetBundleの読み込みでおかしな現象が発生するようになりました。
具体的にはAssetBundleのmainassetの取得が、サーバからロードした直後の1回は取得できるのですが、2回以上取得すると以降nullが返ってくるのです。
既にロード済でローカルに有るAssetBundleから取得すると、最初からnullです。
プロジェクトに何の変更も加えず、作業するUnityのバージョンを5.3.3f1に戻すだけでmainassetは取り放題になるため、ここで何らかの手が入ったようです(リリースノートからは読み取れず…)
mainassetがnullではまともに動作しないプログラム設計になっているので、これを取れるようにしました。
参考:
http://answers.unity3d.com/questions/951531/no-assetbundlemainasset-with-buildingassetbundles.html
assetBundle.LoadAsset(assetBundle.GetAllAssetNames()[0]);
これで取れたかのように見えました。
…がしかし、あるprefabをAssetBundle化したら、GetAllAssetNames()[0]にシェーダなどが入っていたりする場合があり、mainassetとの動きの違いが出てしまいました。
そこで書いたのが以下のコード。
public static T Mainasset<T> (this AssetBundle assetBundle) where T : Object
{
T bundleGo = null;
foreach( var assets in assetBundle.GetAllAssetNames() )
{
if (assets != null) {
bundleGo = assetBundle.LoadAsset<T> (assets);
if (bundleGo != null) {
break;
}
}
}
return bundleGo;
}
ただこれ欠点があり、GetAllAssetNames()した際に、指定した型と同じ型のassetが、出て欲しいassetよりも上の方に有ると読めない…
もっとスマートな解決方法が有ると思いますが、とりあえずはこんな感じで乗り切ってます。
…え?「全てUnity5で書き直せばこんな変なことで悩まないだろう」って?
そうですねぇ…(白目)