この投稿では、UnityのEditor拡張のコードを用いて、縦と横それぞれの分割数を指定して、一枚の画像をMultiple Spriteに分割する方法を紹介します。
画像を分割する箇所のコードは、kyusyukeigoさんがUnite Japan 2014ので発表されたMultiSpriteEditorWindowを参考にさせていただきました。
なにが嬉しいの?
GUIを使い、プロジェクトに取り込んだ画像をSpriteに設定し、Sprite ModeをMultipleにし、Sprite Editorを開いて、GridモードでSpriteを分割すること作業は若干煩雑です。そして、この若干煩雑なプロセスを複数枚にわたり、または何回も繰り返し手動で行うの非常に面倒です。
このような手順はEditor拡張のコードを用い、自動化もしくは適切なレベルまで半自動化してしまうべきでしょう。
ソースコード
縦横の分割数を指定し一枚の画像をMultiple Spriteに分割するEditor拡張コードを下記に示します。
DividSprite
メソッドの第1引数texturePath
が分割対象の画像のパス、第2引数horizontalCount
は水平方向の分割数、第3引数verticalCount
は垂直方向の分割数です。
using UnityEditor;
using UnityEngine;
using System.Linq;
public static class SpriteDivider
{
public static void DividSprite (string texturePath, int horizontalCount, int verticalCount)
{
TextureImporter importer = TextureImporter.GetAtPath (texturePath) as TextureImporter;
importer.textureType = TextureImporterType.Sprite;
importer.spriteImportMode = SpriteImportMode.Multiple;
importer.filterMode = FilterMode.Point;
EditorUtility.SetDirty (importer);
AssetDatabase.ImportAsset (texturePath, ImportAssetOptions.ForceUpdate);
Texture texture = AssetDatabase.LoadAssetAtPath (texturePath, typeof(Texture)) as Texture;
importer.spritePixelsPerUnit = Mathf.Max (texture.width / horizontalCount, texture.height / verticalCount);
importer.spritesheet = CreateSpriteMetaDataArray (texture, horizontalCount, verticalCount);
EditorUtility.SetDirty (importer);
AssetDatabase.ImportAsset (texturePath, ImportAssetOptions.ForceUpdate);
}
static SpriteMetaData[] CreateSpriteMetaDataArray (Texture texture, int horizontalCount, int verticalCount)
{
float spriteWidth = texture.width / horizontalCount;
float spriteHeight = texture.height / verticalCount;
return Enumerable
.Range (0, horizontalCount * verticalCount)
.Select (index => {
int x = index % horizontalCount;
int y = index / horizontalCount;
return new SpriteMetaData {
name = string.Format ("{0}_{1}", texture.name, index),
rect = new Rect (spriteWidth * x, texture.height - spriteHeight * (y + 1), spriteWidth, spriteHeight)
};
})
.ToArray ();
}
}
やっていること
メソッドの引数のtexturePath
が示す画像に対して以下のことを行います。
-
TextureType
をSprite
に設定 -
SpriteImportMode
をMultiple
に設定 -
FilterMode
をPoint
に設定 -
SpritePixelsPerUnit
を分割後のSprite
の長辺の長さに設定 - 引数に指定した縦横それぞれの分割数でSpriteに分割(順序はGUIから手動で分割した時と揃えている、後述)
ポイント
一度Spriteへの変更を反映させる
下記のコードは、一度画像をSpriteに変更後、その変更を反映させている部分を再掲した物です。
importer.textureType = TextureImporterType.Sprite;
importer.spriteImportMode = SpriteImportMode.Multiple;
importer.filterMode = FilterMode.Point;
EditorUtility.SetDirty (importer);
AssetDatabase.ImportAsset (texturePath, ImportAssetOptions.ForceUpdate);
こうしないと画像のサイズを正しく読み込めない場合があります。
GUIから手動で分割した時と同じSpriteの順序・名前に
下記のコードは、分割後のSpriteの設定を生成する箇所を再掲した物です。
int x = index % horizontalCount;
int y = index / horizontalCount;
return new SpriteMetaData {
name = string.Format ("{0}_{1}", texture.name, index),
rect = new Rect (spriteWidth * x, texture.height - spriteHeight * (y + 1), spriteWidth, spriteHeight)
};
GUIのGridモードでSpriteを分割した場合、左上が起点で、まずは水平方向に、0,1,2...と順序がふられていきます。これと同じ順序で分割するようにしています。
また名前もGUIで分割したものと同じになるようにしています。
利用例(呼び出すコード)
画像を分割するSpriteDivider.DivideSprite
メソッドを呼び出すための、Editor拡張のコードを下記に示します。
これを使えば、同じ分割設定の画像であれば、何枚でも一気にSpriteを分割することが可能です。煩雑な処理を何度もやる必要はありません。
分割の対象になるのは、Project Window中で選択しているTexutreが対象です。複数選択している場合、全てのTextureが分割されます。Texutureを選択した状態でメニューから、Assets -> Divide Textures
を選択してください。
ここでは横の分割数を3、縦の分割数を4にしています。
using UnityEngine;
using UnityEditor;
using System.Linq;
using System.Collections.Generic;
public static class SpriteDividerCaller
{
[MenuItem("Assets/Divide Textures")]
public static void DivideImages ()
{
int horizontalCount = 3;
int verticalCount = 4;
IEnumerable<Texture> targets = Selection.objects.OfType<Texture> ();
if (!targets.Any ()) {
Debug.LogWarning ("Please selecting textures.");
return;
}
foreach (Texture target in targets) {
SpriteDivider.DividSprite (AssetDatabase.GetAssetPath (target), horizontalCount, verticalCount);
}
}
}
ポイントはLINQを使っている分割対象を取得する次の箇所です。
IEnumerable<Texture> targets = Selection.objects.OfType<Texture> ();
Selection.objects
は現在選択しているものをUnityEngine.Object[]
で取得するプロパティです。この配列には、Texture
型以外の要素が存在する可能性があります。ここではOfType
メソッドを使って、Texture
型にキャスト可能な要素はキャストをして、キャスト不可能な要素は取り除いています。また、これまたLINQのAnyメソッドで分割対象の要素の存在を確認し、分割対象が存在しない場合はその旨を通知し、処理を終了しています。