この記事は思いつきを書いたものです。
普段TexturePackerなどでPackしたSpriteAtlasを読み込む時どうしてますか?
Resources.LoadAllだったりAssetBundle.LoadAllAssetsだったりで読んできて
Sprite[]から探して読んだりしていませんか?
そこで、今回思いついたのがSpriteをすべてScriptableObjectにして、
使う時はScriptableObjectを読み込むという方法です。
使用したアセット
今回Serialize可能なDictionaryであるSerializeDictionaryを利用しています。
https://github.com/neuecc/SerializableDictionary
こちらの絵素材を使用しています。
https://pipoya.net/sozai/terms-of-use-of-free-materials/
ScriptableObjectの作成
using System;
using System.Linq;
using SerializableCollections;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[Serializable]
public class StringSpriteDictionary : SerializableDictionary<string, Sprite>
{
}
[CustomPropertyDrawer(typeof(StringSpriteDictionary))]
public class ExtendedSerializableDictionaryPropertyDrawer : SerializableDictionaryPropertyDrawer
{
}
public class SpriteAtlasAsset : ScriptableObject
{
#if UNITY_EDITOR
[MenuItem("Tools/CreateSpriteAtlasAsset")]
static void CreateSpriteAtlasAssetInstance()
{
var spriteAtlas = CreateInstance<SpriteAtlasAsset>();
spriteAtlas.atlasCache = new StringSpriteDictionary();
foreach (var obj in Selection.objects)
{
var assetPath = AssetDatabase.GetAssetPath(obj);![SpriteAtlasInspector.PNG](https://qiita-image-store.s3.amazonaws.com/0/16088/daacc87f-3ef1-fb1c-7495-804062243688.png)
var sprites = AssetDatabase.LoadAllAssetsAtPath(assetPath).OfType<Sprite>().ToArray();
foreach (var sprite in sprites)
{
spriteAtlas.atlasCache.Add(sprite.name, sprite);
}
}
AssetDatabase.CreateAsset(spriteAtlas, "Assets/SpriteAtlas.asset");
AssetDatabase.Refresh();
}
#endif
[SerializeField] StringSpriteDictionary atlasCache = new StringSpriteDictionary();
public Sprite GetSprite(string spriteName)
{
return atlasCache[spriteName];
}
}
このコードを作成しmultipleなTextureを選択してToolsのCreateSpriteAtlasAssetを押すと
Assets直下にScriptableObjectが作成されます。
作られたSpriteAtlasのScriptableObjectのInspectorを見ると選択したTextureに含まれるSpriteが読まれます。
使用する時
using UnityEngine;
using UnityEngine.UI;
public class ScriptableTest : MonoBehaviour
{
[SerializeField] SpriteAtlasAsset spriteAtlas;
[SerializeField] Image image;
void Start()
{
image.sprite = spriteAtlas.GetSprite("majo_1");
}
}
上記のようなMonobehaviorを継承したクラスを作り、Inspectorで先程作成したScriptableObjectを貼ります。
実行後して確認してみると以下のようになりました。
結果
ScriptableObjectを作る手間は増えるが、ScriptableObjectをInspectorで直接設定可能で
はじめからDictionaryで保持することが可能だったりと便利になったのではないでしょうか?