【背景】
Unityで制作しているゲームで、リソースをAssetBundleダウンロードで都度読み込む仕組みで制作を進めています。
キャラクターのSpriteなどをIDを指定して動的に取得するということはできましたが、
イベントシーンもAssetBundleで読み込んでうまく動かせるのか?ということを試しました。
元々はTimeline配下に動かすオブジェクトプレハブを配置していたのですが、
AssetBundleからダウンロードしてインスタンス化してみると、
バインドが消えていたりSpriteの参照が外れていたりと思うように動いてくれませんでした。
動かすオブジェクトの方は別のAssetBundleに入っているSpriteを参照していたせいだと思い、
AssetBundleは別々でUnity上で組み立てるという方法にしました。
依存関係も一緒にまとめてくれるはずなのですが…、
AssetBundle内のアセット一覧を見るとSpriteが入っていないようでした。
最終的に苦肉の策という形になりましたが、実現できた方法を残します。
【実現した方法】
概要としては、以下の処理順で実現できました。
1.Timelineで使用するオブジェクトを先にシーン上にインスタンス化
2.GameObject.Findで探してきて、PlayableDirector#SetGenericBinding
3.PlayableDirector#Playで再生
【前提】
Timelineである程度のルールが守られていることが前提になる方法です。
-
シーン上に先にGameObjectが生成されている
-
シーン上に同じ名前のGameObjectが存在しない
1. Timelineで使用するオブジェクトを先にシーン上にインスタンス化
1.Timelineで動かすオブジェクトは、おおよそキャラクターSpriteだったり、カメラだったりになる想定です。
キャラクターのオブジェクトはSpriteをシーン上に配置してプレハブ化しています。
これは別途AssetBundleを作成しています。一応、AssetBundleは一度ダウンロードしたら静的なリストに入れておいて、ダウンロード済み確認をして重複を避けるという方法を考えています。
別途必要なAssetBundleを何らかの方法でTimelineに必要なAssetBundleリストを取得し、
Timelineのインスタンス化の前にシーン上に生成します。
自分の場合、アセットバンドルファイルの情報をDBの保持しており、WebAPIでキャラクターIDやイベントIDに紐づくファイル名を取ってくるようにしています。
AssetBundleファイルIDもキーにしているので、イベントIDとAssetBundleファイルIDで紐づけ構成可能かもしれません。
2.GameObject.Findで探してきて、PlayableDirector#SetGenericBinding
TimelineをAssetBundleから取得した後、インスタンス化する前にバインド処理を行います。
やっていることは単純で、Timelineの持つトラック名と一致するオブジェクトをシーン上から取得して、取得できていればSetGenericBindingしています。
Animation Trackとセリフ回し用のPlayabelAssetしか入っていないTimelineなので、ここではAnimation Trackのみ動的バインドしています。
// Assetのロード
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr);
var assetPrefab = bundle.LoadAssetAsync<GameObject>("EventTimeline");
yield return assetPrefab;
GameObject prefab = (GameObject)assetPrefab.asset;
PlayableDirector playableDirector = prefab.GetComponent<PlayableDirector>();
//playableDirector内のトラック(バインド先)を取得
foreach(var bindingTarget in playableDirector.playableAsset.outputs){
//トラック名称の一致するオブジェクトをシーンから取得してバインド
var bindObjectName = GameObject.Find(bindingTarget.streamName);
if (bindObjectName) {
playableDirector.SetGenericBinding(bindingTarget.sourceObject, bindObjectName.GetComponent<Animator>());
}
}
3.PlayableDirector#Playで再生
バインドループを抜けたらインスタンス化するかPlayでいざ再生
GameObject instanse = Instantiate((GameObject)assetPrefab.asset);
//または、playableDirector.Play();
カメラもオブジェクトも、うまくバインドできて動いてくれました。
今度はセリフ用のUIも別AssetBundleにするかシーン内の共通UIとして
動的にPlayableAssetのクリップにバインドできるとよいかもしれません。
Spriteの依存関係や動的なTimelineのバインド方法についてはもう少し
正当な方法を探してみようと思います。
参考


