- Home /
Editor script to slice sprites
I'm trying to create an editor tool that will take a bunch of images (each a sprite sheet), slice them up, create animations from them, and create a controller override from a given template with all the right animations in all the right slots.
The idea is to quickly create animations for new characters without having to use the editor's horrible pipeline (slice manually, drag and drop each group, setup the controllers, etc)
Right now I'm stuck in trying to slice the sprite from the editor script. Any ideas how to access the sprite editor or something similar from script?
Did you end up completing the whole sequence like you wanted? That sounds exactly like what I am trying to do.
Can you please tell me how u implement this given solution?
Answer by Dorque · Apr 18, 2015 at 08:38 PM
I'm in a similar situation where I want to name a large sprite sheet through code. I started with this script here. In order to use these editor scripts you need to put them in a Editor folder. When you restart Unity you should see a Sprites menu at the top with "Rename Sprites" in the dropdown.
I modified it to slice the texture by a 16x16 grid, set the pivot, and then rename the sprites according to their index in the sprite sheet. The top left sprite is (0,0).
I hope this helps.
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
public class NameSpritesAutomatically : MonoBehaviour {
[MenuItem("Sprites/Rename Sprites")]
static void SetSpriteNames()
{
Texture2D myTexture = (Texture2D)Resources.LoadAssetAtPath<Texture2D>("Assets/Sprites/MyTexture.png");
string path = AssetDatabase.GetAssetPath(myTexture);
TextureImporter ti = AssetImporter.GetAtPath(path) as TextureImporter;
ti.isReadable = true;
List<SpriteMetaData> newData = new List<SpriteMetaData>();
int SliceWidth = 16;
int SliceHeight = 16;
for (int i = 0; i < myTexture.width; i += SliceWidth)
{
for(int j = myTexture.height; j > 0; j -= SliceHeight)
{
SpriteMetaData smd = new SpriteMetaData();
smd.pivot = new Vector2(0.5f, 0.5f);
smd.alignment = 9;
smd.name = (myTexture.height - j)/SliceHeight + ", " + i/SliceWidth;
smd.rect = new Rect(i, j-SliceHeight, SliceWidth, SliceHeight);
newData.Add(smd);
}
}
ti.spritesheet = newData.ToArray();
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
}
}
Hmm, I tried setting spritesheet
parameter but it had no effect on the imported sprite... I'll try this script and let you know. Thanks for answering.
You know, sometimes I have to run this script twice to see any changes made. I'm not sure why this is.
This is very weird... I can swear I tried the exact same thing (setting the spritesheet to something I created) and it did nothing. Now it works perfectly.
Oh well, thanks for the answer.
Ok, I figured out why it didn't work when I first tried. Apparently when the sprite is already sliced, the code does nothing... weird unity bug?
Anyway, here is the workaround:
if (ti.spriteImport$$anonymous$$ode == SpriteImport$$anonymous$$ode.$$anonymous$$ultiple) {
// Bug? Need to convert to single then back to multiple in order to make changes when it's already sliced
ti.spriteImport$$anonymous$$ode = SpriteImport$$anonymous$$ode.Single;
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
}
Also, there's a bug with the pivot in the code above. Pivot should be set 0 to 1, so in the example above it should be (0.5,0.5). Also the pivot parameter is useless unless you set the alignment to custom. So add these lines ins$$anonymous$$d of the "smd.pivot=...":
smd.pivot = new Vector2(0.5f, 0.5f);
smd.alignment = 9;
Please update your answer with these parts so other people reading this will know.
Thank you for this, still useful in 2020! I would like to add one correction though... The issue is that if you are using very large textures that go above the max size you have set (for example, max size is 8192, and my texture was 14400). This is unlikely, but on the off chance you cant just change the max size to fit your need, you will need the true size to slice it properly.
Solution: see this function and add it to your code: https://forum.unity.com/threads/getting-original-size-of-texture-asset-in-pixels.165295/
instead of tex.width and tex.height, replace it with what the code gives you to get the true size of the texture.
example:
int texWidth;
int texHeight;
if (GetImageSize(tex, out texWidth, out texHeight)) { }
else
{
Debug.LogError($"Unable to get texture '{tex}' size.");
return;
}
Answer by acfung · May 12, 2018 at 09:15 PM
Try this script
https://gist.github.com/shadesbelow/8a6ddc54db795241f3cff539db6ea487,
This will give you a hotkey to automatically slice sprites just like using Sprite Editor > Slice > Automatic
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
// This is only useful for spritesheets that need to be automatically sliced (Sprite Editor > Slice > Automatic)
public class AutoSpriteSlicer
{
[MenuItem("Tools/Slice Spritesheets %&s")]
public static void Slice()
{
var textures = Selection.GetFiltered<Texture2D>(SelectionMode.Assets);
foreach (var texture in textures)
{
ProcessTexture(texture);
}
}
static void ProcessTexture(Texture2D texture)
{
string path = AssetDatabase.GetAssetPath(texture);
var importer = AssetImporter.GetAtPath(path) as TextureImporter;
//importer.isReadable = true;
importer.textureType = TextureImporterType.Sprite;
importer.spriteImportMode = SpriteImportMode.Multiple;
importer.mipmapEnabled = false;
importer.filterMode = FilterMode.Point;
importer.spritePivot = Vector2.down;
importer.textureCompression = TextureImporterCompression.Uncompressed;
var textureSettings = new TextureImporterSettings(); // need this stupid class because spriteExtrude and spriteMeshType aren't exposed on TextureImporter
importer.ReadTextureSettings(textureSettings);
textureSettings.spriteMeshType = SpriteMeshType.Tight;
textureSettings.spriteExtrude = 0;
importer.SetTextureSettings(textureSettings);
int minimumSpriteSize = 16;
int extrudeSize = 0;
Rect[] rects = InternalSpriteUtility.GenerateAutomaticSpriteRectangles(texture, minimumSpriteSize, extrudeSize);
var rectsList = new List<Rect>(rects);
rectsList = SortRects(rectsList, texture.width);
string filenameNoExtension = Path.GetFileNameWithoutExtension(path);
var metas = new List<SpriteMetaData>();
int rectNum = 0;
foreach (Rect rect in rectsList)
{
var meta = new SpriteMetaData();
meta.pivot = Vector2.down;
meta.alignment = (int)SpriteAlignment.BottomCenter;
meta.rect = rect;
meta.name = filenameNoExtension + "_" + rectNum++;
metas.Add(meta);
}
importer.spritesheet = metas.ToArray();
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
}
static List<Rect> SortRects(List<Rect> rects, float textureWidth)
{
List<Rect> list = new List<Rect>();
while (rects.Count > 0)
{
Rect rect = rects[rects.Count - 1];
Rect sweepRect = new Rect(0f, rect.yMin, textureWidth, rect.height);
List<Rect> list2 = RectSweep(rects, sweepRect);
if (list2.Count <= 0)
{
list.AddRange(rects);
break;
}
list.AddRange(list2);
}
return list;
}
static List<Rect> RectSweep(List<Rect> rects, Rect sweepRect)
{
List<Rect> result;
if (rects == null || rects.Count == 0)
{
result = new List<Rect>();
}
else
{
List<Rect> list = new List<Rect>();
foreach (Rect current in rects)
{
if (current.Overlaps(sweepRect))
{
list.Add(current);
}
}
foreach (Rect current2 in list)
{
rects.Remove(current2);
}
list.Sort((a, b) => a.x.CompareTo(b.x));
result = list;
}
return result;
}
}
Answer by dmitry_veshchikov · Jan 27 at 11:12 PM
Add this line:
ti.spriteImportMode = SpriteImportMode.Multiple;
Before:
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
It will set the image asset automatically to be multiple sprites, saving you time setting it manually from "Single" to "Multiple" in the editor, and preventing a headache where you don't know why the script isn't working.,Add this line:
ti.spriteImportMode = SpriteImportMode.Multiple;
Before:
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
It will set the image asset automatically to be multiple sprites, saving you time setting it manually to multiple in the editor, and preventing a headache where you don't know why the script isn't working.