だらだら〜自由自在〜

インディーゲーム制作チーム GAME GABURI でプログラム担当してます

Unity2017 SpriteAtlas

個人的に製作中のゲームで、Unity2017から追加になったというSpriteAtlasの新しい仕組みを使ってみています。
tsubakit1.hateblo.jp

こちらの機能ですね。

Packing(Atlasing)された個別のSpriteにアクセスしたいという要望は普通にありえると思います。
例えば所持中アイテムのリストUIを作っているとして、リスト中のアイテムアイコン画像はプログラム上でセットするしかないのでここでPackingされたアイコンSpriteを取り出す要件がでてきます。

5.6系とか以前のSpriteには(たぶん)そのための仕組がなかったので自前で作るしかありませんでした。
シーン中のオブジェクトのSerializedPropertyで参照を保持しておくとか、専用のScriptableObjectに同様に参照を保持するためのPropertyを追加しておいてそれを実行時にロードするとか。
自分も後者のやりかたで運用していました。
別に難しい実装でも無いですし別にこれでもOKなんですが、いまいちな点としてSpriteが追加されたときに自動でこの参照も追加してやる、ということができないんですね。・・・がんばって作らない限りは。

作ろうと思えばAssetPostProcessorとかでSpriteのImportをHookすればできるのかなぁって気はするのですが、面倒だし、実装してないので分からないですがそこそこ重い処理なのかなーって気がするのでUnityビルトインの機能を使ってみようと思ったわけです。


普通に使う分には、普通に使えます。「SpriteAtlas Unity2017」とかでググれば導入の解説をしているサイトがHITするのでそういうのはそちらを参照していただくとして。
SpriteAtlasアセットをスクリプトから作成する方法と、使ってみてわかったメモリリーク(では無いんだけど)的な挙動を書き残しておこうと思います。

SpriteAtlasアセットをスクリプトから作成する方法

自分の使い方の要件としてSpriteAtlasアセットをスクリプトから作成して、同時にPacking検索対象のフォルダとかもスクリプトから設定したいなーというのがありました。
でもReferenceとか見てもそういうのが見当たらなかったんですね。だから下記のほうほうでやりました。もし公式にやりかたあったら教えていただけるとうれしいです。

gist.github.com


まず普通にUnityEditor上で手作業でSpriteAtlasアセットをつくって、その中身をテンプレートにしてFileをつくってImportしているだけです。

これで一応できたはできたんですが、ちょっとうまく行かなかったところがあって
ModifyFilterMode(), ModifyEnableTightPacking()
といったメソッドがあるんですが、当初は↓のような感じで使おうとしてました、が

const string path = "path/to/asset.spriteatlas";
SpriteAtlasScriptIF.CreateSpriteAtlas(path, ...);
SpriteAtlasScriptIF.ModifyFilterMode(path, FileMode.Point);
SpriteAtlasScriptIF.ModifyEnableTightPacking(path, false);

これだとModifyFilterModeでLoadAssetするときにnullが帰ってきちゃいました。
アセット作成後のImportAssetをSynchronizedにしたりAssetDatabase.Refreshをしてみたりしたんですが改善せず。結局テンプレートでfilterModeを置換してやるやりかたにしました。

SpriteAtlas.GetSpriteするとObjectがふえちゃう件

まぁ関数ドキュメントにもGetSpriteするとCloneを返しますよと書いてあるんですが…。
んー・・・なんでCloneするんだろう。
気付かず毎Frame GetSpriteしてしまっていてProfilerでみたらTotal Object Countが増え続けていました。
スマホの実機でしばらくすると落ちる不具合を調査していて気づいたんですが。