版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
Unity编辑器拓展之二十八:Sprite Border自动设置工具
1.0 功能介绍
自动计算出九宫格Sprite 的border数据并直接赋值保存的工具。【纯属偷懒,可能各位觉得没啥用吧,哈哈】
当需要为一个九宫格Sprite 设置Border数据时,需要打开Sprite Editor,然后输入Border数据。
工具会直接计算横向、纵向连续完全相同的列数、行数(当然连续区域取最大的),当计算出的九宫区域满足条件时(我设定的条件是连续列数或者行数有个最小值设定),就任务该图可以处理为九宫格Sprite。
以上九宫格Sprite,又称为 点九图【废话】。
2.0 源码
脚本放置在Editor文件夹下
using System.IO;
using UnityEditor;
using UnityEngine;
public class SpriteImporterTool : UnityEditor.Editor
{
public static int continuousColNum = 10; //continuousColNum:连续的列数,大于等于这个值判定为横向可以九宫处理
public static int continuousRowNum = 10; //continuousRowNum:连续的行数,大于等于这个值判定为纵向可以九宫处理
//自动计算Sprite Border数据
[MenuItem("Assets/SpriteBorder/AutoSetSpriteBorder", false, 500)]
public static void AutoSetSpriteBorder()
{
foreach (var spriteAsset in Selection.objects)
{
AutoSetSpriteBorder(AssetDatabase.GetAssetPath(spriteAsset));
}
}
//设置Sprite Border为Zero
[MenuItem("Assets/SpriteBorder/Reset Zero", false)]
public static void AutoSetSpriteBorderZero()
{
foreach (var spriteAsset in Selection.objects)
{
SetSpriteBorder(AssetDatabase.GetAssetPath(spriteAsset), Vector4.zero);
}
}
private static void AutoSetSpriteBorder(string spriteAssetPath)
{
TextureImporter textureImporter = AssetImporter.GetAtPath(spriteAssetPath) as TextureImporter;
if (textureImporter != null && textureImporter.textureType == TextureImporterType.Sprite)
{
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(spriteAssetPath);
Vector4 border = Vector4.zero;
GetBorderSliceInfo(sprite.texture, continuousColNum, continuousRowNum, ref border);
if (border != Vector4.zero)
{
textureImporter.spriteBorder = border;
EditorUtility.SetDirty(sprite);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
}
private static void SetSpriteBorder(string spriteAssetPath, Vector4 border)
{
TextureImporter textureImporter = AssetImporter.GetAtPath(spriteAssetPath) as TextureImporter;
if (textureImporter != null && textureImporter.textureType == TextureImporterType.Sprite)
{
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(spriteAssetPath);
textureImporter.spriteBorder = border;
EditorUtility.SetDirty(sprite);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
public static void GetBorderSliceInfo(Texture2D texture, int continuousColNum, int continuousRowNum,
ref Vector4 border)
{
int width = texture.width;
int height = texture.height;
//咳咳,这里的命名规则请忽略,从另一个python工具拷贝过来
int cur_begin_col_index = 0;
int cur_end_col_index = 0;
int slice_begin_col_index = 0;
int slice_end_col_index = 0;
Texture2D readTexture2D = GetReadTexture2D(texture);
for (int col = 0; col < width - 1; col++)
{
if (EqualColPixel(readTexture2D, col, col + 1) == false)
{
if ((cur_begin_col_index != cur_end_col_index) &&
(cur_end_col_index - cur_begin_col_index >= continuousColNum) &&
(cur_end_col_index - cur_begin_col_index > slice_end_col_index - slice_begin_col_index))
{
slice_begin_col_index = cur_begin_col_index;
slice_end_col_index = cur_end_col_index;
}
cur_begin_col_index = col + 1;
cur_end_col_index = col + 1;
}
else
{
cur_end_col_index = col + 1;
}
}
int cur_begin_row_index = 0;
int cur_end_row_index = 0;
int slice_begin_row_index = 0;
int slice_end_row_index = 0;
for (int row = 0; row < height - 1; row++)
{
if (EqualRowPixel(readTexture2D, row, row + 1) == false)
{
if ((cur_begin_row_index != cur_end_row_index) &&
(cur_end_row_index - cur_begin_row_index >= continuousRowNum) &&
(cur_end_row_index - cur_begin_row_index > slice_end_row_index - slice_begin_row_index))
{
slice_begin_row_index = cur_begin_row_index;
slice_end_row_index = cur_end_row_index;
}
cur_begin_row_index = row + 1;
cur_end_row_index = row + 1;
}
else
{
cur_end_row_index = row + 1;
}
}
if (slice_end_col_index - slice_begin_col_index < continuousColNum)
{
slice_begin_col_index = 0;
slice_end_col_index = width - 1;
}
if (slice_end_row_index - slice_begin_row_index < continuousRowNum)
{
slice_begin_row_index = 0;
slice_end_row_index = height - 1;
}
//LTRB
//row 是纵向的 T B
//col 是横向的 L R
border = new Vector4(slice_begin_col_index, slice_begin_row_index, width - slice_end_col_index - 1,
height - slice_end_row_index - 1);
}
public static string GetAssetFullPath(UnityEngine.Object asset)
{
return System.Environment.CurrentDirectory + Path.DirectorySeparatorChar +
AssetDatabase.GetAssetPath(asset);
}
public static Texture2D GetReadTexture2D(Texture texture)
{
string textureFilePath = GetAssetFullPath(texture);
FileStream fileStream = new FileStream(textureFilePath, FileMode.Open, FileAccess.Read);
fileStream.Seek(0, SeekOrigin.Begin);
byte[] bytes = new byte[fileStream.Length];
fileStream.Read(bytes, 0, (int) fileStream.Length);
fileStream.Close();
fileStream.Dispose();
Texture2D new_texture = new Texture2D(texture.width, texture.height);
new_texture.LoadImage(bytes);
return new_texture;
}
/// <summary>
/// 比较两行像素是否完全相等
/// </summary>
/// <param name="texture">isReadable为true,可读的texture</param>
/// <param name="row1"></param>
/// <param name="row2"></param>
/// <returns></returns>
public static bool EqualRowPixel(Texture2D texture, int row1, int row2)
{
Color[] row1Colors = texture.GetPixels(0, row1, texture.width, 1);
Color[] row2Colors = texture.GetPixels(0, row2, texture.width, 1);
for (int i = 0; i < row1Colors.Length; i++)
{
if (!row1Colors[i].Equals(row2Colors[i]))
{
return false;
}
}
return true;
}
/// <summary>
/// 比较两列像素是否完全相等
/// </summary>
/// <param name="texture">isReadable为true,可读的texture</param>
/// <param name="col1"></param>
/// <param name="col2"></param>
/// <returns></returns>
public static bool EqualColPixel(Texture2D texture, int col1, int col2)
{
Color[] col1Colors = texture.GetPixels(col1, 0, 1, texture.height);
Color[] col2Colors = texture.GetPixels(col2, 0, 1, texture.height);
for (int i = 0; i < col1Colors.Length; i++)
{
if (!col1Colors[i].Equals(col2Colors[i]))
{
return false;
}
}
return true;
}
}