一.plist導出unity sprite圖集
texturepack有開源的工具可以導出json文件,然后倒入sprite。但是很多游戲使用的是plist打包,比如cocos2d。我們做demo可能需要這些資源來用用。所以有此需求。
首先是解析plist。自己xml解析是在麻煩,網上找到個,使用c#的XDocument類,解析成自己的plist類型。代碼基本沒變,因為plist的<!DOCTYPE>那行總是解析出錯,所以在外面載入好字符串,然后去掉這一行。
public void LoadText(string text)
{
Clear();
XDocument doc = XDocument.Parse(text);
XElement plist = doc.Element("plist");
XElement dict = plist.Element("dict");
var dictElements = dict.Elements();
Parse(this, dictElements);
}
然后讀取數據載入到自己的TPAtlas類里面(本來想通過這個類,直接緩存讀取),然后是寫入到textureImporter.spritesheet里,再AssetDatabase.ImportAsset就OK。這里有個問題,就設置sheet后,要重寫textureType和spriteImportMode后面ImportAsset才有效,不然內存是改了,但是不會保存到meta文件,下次打開就沒了,可能是unity的bug
[MenuItem("Assets/Texture/PLisToSprites(SelectPList)")] static void ConvertSprite() { //EditorUtility.DisplayDialog("MyTool", "Do It in C# !", "OK", ""); Object selobj = Selection.activeObject; string selectionPath = AssetDatabase.GetAssetPath(Selection.activeObject); if (!selectionPath.EndsWith(".plist")) { EditorUtility.DisplayDialog("Error", "Please select a plist file!", "OK", ""); return; } Debug.LogWarning("#PLisToSprites start:" + selectionPath); string fileContent = string.Empty; using (FileStream file = new FileStream(selectionPath, FileMode.Open)) { byte[] str = new byte[(int)file.Length]; file.Read(str, 0, str.Length); fileContent = GetUTF8String(str); Debug.Log(fileContent); file.Close(); file.Dispose(); } //去掉<!DOCTYPE>,不然異常 int delStart = fileContent.IndexOf("<!DOCTYPE"); int delEnd = fileContent.IndexOf("\n", delStart); fileContent = fileContent.Remove(delStart, delEnd - delStart); Debug.Log(fileContent); //解析文件 PList plist = new PList(); plist.LoadText(fileContent);//Load(selectionPath); TPAtlas at = new TPAtlas(); at.LoadX(plist); //重寫meta string texPath = Path.GetDirectoryName(selectionPath) + "/" + at.realTextureFileName; Texture2D selTex = AssetDatabase.LoadAssetAtPath(texPath, typeof(Texture2D)) as Texture2D; Debug.Log("texture:" + texPath); Debug.Log("write texture:" + selTex.name+ " size:"+selTex.texelSize); TextureImporter textureImporter = AssetImporter.GetAtPath(texPath) as TextureImporter; if (textureImporter.textureType != TextureImporterType.Sprite && textureImporter.textureType != TextureImporterType.Advanced) { EditorUtility.DisplayDialog("Error", "Texture'type must be sprite or Advanced!", "OK", ""); return; } if (textureImporter.spriteImportMode!=SpriteImportMode.Multiple) { EditorUtility.DisplayDialog("Error", "spriteImportMode must be Multiple!", "OK", ""); return; } SpriteMetaData[] sheetMetas = new SpriteMetaData[at.sheets.Count]; for (int i = 0; i < at.sheets.Count; i++) { var frameData = at.sheets[i]; sheetMetas[i].alignment = 0; sheetMetas[i].border = new Vector4(0, 0, 0, 0); sheetMetas[i].name = frameData.name; sheetMetas[i].pivot = new Vector2(0.5f, 0.5f); sheetMetas[i].rect = new Rect(frameData.frame.x, at.size.y - frameData.frame.y -frameData.frame.height, frameData.frame.width,frameData.frame.height);//這里原點在左下角,y相反 //Debug.Log("do sprite:" + frameData.name); } //textureImporter.spriteImportMode = SpriteImportMode.Multiple; textureImporter.spritesheet = sheetMetas; //save textureImporter.textureType = TextureImporterType.Sprite; //bug? textureImporter.spriteImportMode = SpriteImportMode.Multiple; //不加這兩句會導致無法保存meta AssetDatabase.ImportAsset(texPath, ImportAssetOptions.ForceUpdate); Debug.LogWarning("#PLisToSprites end:" + texPath); }
二.unity sprite圖集拆分小圖
有些圖是ui用unity的sprite做ui目前不太靠譜,所以我們還是使用ngui等插件自己打圖,所以要拆分。
還是使用萬能的TextureImporter類,拿到sheet然后,每個sheet寫入到新圖片。
[MenuItem("Assets/Texture/Output Sprites(SelectTexture)")]
static void OutputSprite()
{
string selectionPath = AssetDatabase.GetAssetPath(Selection.activeObject);
Texture2D selTex = Selection.activeObject as Texture2D;
string rootPath = Path.GetDirectoryName(selectionPath) +"/"+ Selection.activeObject.name;
TextureImporter textureImporter = AssetImporter.GetAtPath(selectionPath) as TextureImporter;
//textureImporter.textureType = TextureImporterType.Advanced;
//textureImporter.isReadable = true;
Object[] selected = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
if (!Directory.Exists(rootPath))
Directory.CreateDirectory(rootPath);
Debug.Log("output dir :" + rootPath);
//foreach (var item in selected)
//{
// Sprite sprite = item as Sprite;
// if (sprite == null)
// return;
// string path = rootPath + "/" + sprite.name + ".png";
// Debug.Log("output :" + path);
// SaveSpriteToPNG(sprite, path);
//}
foreach (var spmeta in textureImporter.spritesheet)
{
string path = rootPath + "/" + spmeta.name + ".png";
string subDir = Path.GetDirectoryName(path);
if (!Directory.Exists(subDir))
{
Directory.CreateDirectory(subDir);
}
Debug.Log("output :" + path);
SavePriteToPNG_Meta(selTex, spmeta, path);
}
AssetDatabase.Refresh();
}
static bool SaveSpriteToPNG(Sprite sprite, string outPath)
{
// 創建單獨的紋理
Texture2D tex = new Texture2D((int)sprite.rect.width, (int)sprite.rect.height, sprite.texture.format, false);
tex.SetPixels(sprite.texture.GetPixels((int)sprite.rect.xMin, (int)sprite.rect.yMin,
(int)sprite.rect.width, (int)sprite.rect.height));
tex.Apply();
// 寫入成PNG文件
File.WriteAllBytes(outPath, tex.EncodeToPNG());
return true;
}
static bool SavePriteToPNG_Meta(Texture2D sourceImg,SpriteMetaData metaData, string outPath)
{
Texture2D myimage = new Texture2D((int)metaData.rect.width, (int)metaData.rect.height, sourceImg.format,false);
Color[] pixs = sourceImg.GetPixels((int)metaData.rect.x, (int)metaData.rect.y,(int)metaData.rect.width, (int)metaData.rect.height);
myimage.SetPixels(pixs);
myimage.Apply();
//AssetDatabase.CreateAsset(myimage, rootPath + "/" + image.name + "/" + metaData.name + ".PNG");
File.WriteAllBytes(outPath, myimage.EncodeToPNG());
return true;
}
代碼工程:http://pan.baidu.com/s/1hLqYM
使用注意事項:
plist轉sprite要選中plist文件右擊操作。元圖要改成sprite的multi格式。里面數據名字可能有區別,主要看texture的名字和每個子圖的rect,我兼容了兩種版本,有其他格式自己改代碼吧。還有plist要改成utf8格式,utf8+有時候無效。
拆小圖要選中png圖右擊操作。格式要改成rgba32,不壓縮的,類型advanced ,勾上read/write enable。還有size不能小於元圖大小。