AddressableでMultiSpriteを使用する方法についてです。
Unity 2019.1 Addressable 0.8.4 preview
追記:1.1.4で問題なく使えるようになりました
async void Start() { var sprites = await Addressables.LoadAssetAsync<IList<Sprite>>("sprites").Task; foreach (var sprite in sprites) { Debug.Log(sprite.name); } }
マルチスプライト
Unityで2Dゲームを作るとき、2Dスプライトをパッキングすることがあります。 このとき、SpriteAtlasを使うか、パッキングしたテクスチャをSpriteEditorでスライスするかを選択出来ます。
今回はSpriteをSpriteEditorでパッキングした場合の、Addressable対応についてです。
AddressableはSubAssetを直接ロード出来ない
結論から言えば、パッキングしたスプライトをロードすることは出来ません。
正確に言えば、SubAssetというカテゴリに当たるファイルを、直接指定してロードすることが出来ません。
これはTextureからSprite一覧を取り出したり、FBXからAnimationClipを抽出したり等です。
厄介な事にFastModeでは動いてしまうので一見問題が無いように見えますが、Packed Modeにすると動かない事が確認出来ます。例えば下のコードはPackedだと動きません。
public class LoadSprite : MonoBehaviour { [SerializeField] int id; async void Start() { var sprites = await Addressables.LoadAssetAsync<Sprite[]>("sprite").Task; // packed だとエラー GetComponent<SpriteRenderer>().sprite = sprites[id]; } }
これはSpriteAnimationといった「アセットを使用しているだけ」のケースでは問題無いのですが、キャラクターアイコン等の「スプライトをケースバイケースで差し替える」といった場合に問題になるかもしれませn
解決方法
解決方法は、SubAssetでなくす事です。アプローチは幾つかあります。
アイディア1: スプライトを取り出す
テクスチャからSpriteを取り出します。例えばCtrl + Dで複製する等。実際にはエディター拡張でやるべきですが、まぁそれはそれ。
Spriteは「メッシュ&UV&テクスチャへの 参照 」の情報なので、複製して通常のアセットにしてやれば、普通にロードが可能です。
アイディア2:SpriteAtlasに格納する
SpriteAtlasに格納する方法もあります。
SpriteAtlasにスプライトを設定すると、スプライトは再パッキングされます。そのかわり spriteAtlas.GetSprite(str)
でスプライトを取得出来ます。
UVが既存のテクスチャから変化する点に注意です。またパック元になるテクスチャは必ず無圧縮にします。
アイディア3:適当なScriptableObjectに参照させておく
UV等の情報を維持したままスプライトをロードしたい場合、適当なScriptableObjectから参照しておき、それをロードさせるというアイディアもあります。
例えば下のようなScriptableObjectを用意しておき、スプライトをすべて登録しておきます。
using UnityEngine; [CreateAssetMenu(menuName ="SpriteRefs")] public class Sprites : ScriptableObject { public Sprite[] value; }
あとは普通にScriptableObjectをロードすれば、そのScriptableObjectが参照するSpriteを取得出来ます。
public class LoadSprite : MonoBehaviour { [SerializeField] int id; async void Start() { var sprites = await Addressables.LoadAssetAsync<Sprites>("sprites").Task; GetComponent<SpriteRenderer>().sprite = sprites.value[id]; } }
感想
SubAssetがロード出来ないという問題があるので少々面倒ですが、一応回避方法はあるという事で。