当前位置:网站首页>Unity drawing plug-in = = [support the update of the original atlas]
Unity drawing plug-in = = [support the update of the original atlas]
2022-07-07 15:53:00 【Le_ Sam】
Preface :
Project needs ,1. It needs to be provided to the art collection tool ,2. Atlas update function , So that the subgraphs in the new atlas do not have to be dragged and positioned again
Solutions :
1.unity Call external TexturePacker The command line tool executes the composite ,unity according to TP The generated data cuts out multiple pieces of the atlas sprite
2. When dragging and positioning subgraphs in the atlas , Corresponding GUID And FileID. Therefore, the new atlas updates the corresponding GUID And FileID that will do , however API No corresponding interface found , So start with the resource itself txt Mode on , Force the replacement of the corresponding ID
Reference documents :
https://www.xuanyusong.com/archives/4207
effect :
Source code :
The following three files , Placed in the project Assets\Editor that will do
using System;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
using System.Text;
using System.Diagnostics;
using System.Linq;
using System.Xml;
using System.Collections;
using LuaFramework;
public class TexturePackerBuild : Editor
{
private const string BuildDir = "Assets/TexturePacker/ Package the atlas ";
/// <summary>
/// TexturePacker.exe ###https://www.codeandweb.com/texturepacker/documentation/texture-settings
/// </summary>
private const string Paramet = " --sheet {0}.png --data {1}.xml --format sparrow --trim-mode CropKeepPos --pack-mode Best --algorithm MaxRects --max-size 4096 --size-constraints POT --disable-rotation {2}";
/// <summary>
/// The output directory
/// </summary>
private const string OutPutDirRoot = "Assets/TPSpriteBuild/";
private static string tpDir = "";
private static string argument = "";
[MenuItem(BuildDir, false)]
public static void BuildOneTP()
{
if (Directory.Exists(OutPutDirRoot) == false)
{
Directory.CreateDirectory(OutPutDirRoot);
}
var assetPaths = Selection.assetGUIDs.Select(AssetDatabase.GUIDToAssetPath).ToList();
List<string> filePathList = new List<string>();
foreach (var assetPath in assetPaths)
{
if (AssetDatabase.IsValidFolder(assetPath))
{
string[] filesPath = Directory.GetFiles(assetPath);
foreach (var filePath in filesPath)
{
if (filePathList.Contains(filePath) == false)
{
filePathList.Add(filePath);
}
else
{
UnityEngine.Debug.LogErrorFormat(" Same file detected {0}", assetPath);
}
}
}
else
{
filePathList.Add(assetPath);
}
}
Dictionary<string, FileData> fileDic = new Dictionary<string, FileData>();
foreach (var path in filePathList)
{
var dir = Path.GetFileName(Path.GetDirectoryName(path));
var fileName = Path.GetFileName(path);
UnityEngine.Debug.LogFormat("_TP dirName {0} _TP fileName {1} _TP fullPath {2}", dir, fileName, path);
if (fileDic.ContainsKey(dir) == false)
{
FileData fileData = new FileData();
fileData.filesList = new List<string>();
fileDic[dir] = fileData;
fileDic[dir].dirName = dir;
}
fileDic[dir].filesList.Add(path);
}
foreach (var data in fileDic)
{
TexturePackerBuild tpBuild = new TexturePackerBuild();
tpBuild.Build(data.Value);
}
}
public void Build(FileData data)
{
StringBuilder sb = new StringBuilder("");
GetImageName(data.filesList, ref sb);
string sheetName = OutPutDirRoot + data.dirName;
argument = string.Format(Paramet, sheetName, sheetName, sb.ToString());
tpDir = PlayerPrefs.GetString("_TPInstallDir", "");
RunExternalApp(tpDir, argument);
}
private StringBuilder GetImageName(List<string> fileName, ref StringBuilder sb)
{
foreach (var file in fileName)
{
string extenstion = Path.GetExtension(file);
if (extenstion == ".png")
{
sb.Append(file);
sb.Append(" ");
}
}
return sb;
}
private void RunExternalApp(string command, string argument)
{
UnityEngine.Debug.Log("TPSprite Recover");
ClearOtherFiles();
ProcessStartInfo start = new ProcessStartInfo(command);
start.Arguments = argument;
start.CreateNoWindow = false;
start.ErrorDialog = true;
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.RedirectStandardInput = true;
start.StandardOutputEncoding = System.Text.UTF8Encoding.UTF8;
start.StandardErrorEncoding = System.Text.UTF8Encoding.UTF8;
try
{
Process p = Process.Start(start);
p.WaitForExit();
p.Close();
AssetDatabase.Refresh();
bool isNullFile; // Judge whether the file in the output directory is empty
string outPngPath;
BuildTexturePacker(out isNullFile,out outPngPath);
if (isNullFile == false)
{
tpDir = command;
PlayerPrefs.SetString("_TPInstallDir", command);
SelectAtlasUpdataWindow(outPngPath);
}
else
{
// The output file is empty , guess exe Incorrect use , Re import exe
OnError(" No pictures were detected in the output directory , Please re import ");
}
}
catch (Exception ex)
{
OnError(ex.Message);
}
}
/// <summary>
/// Clean up the original image under the output directory
/// </summary>
private void ClearOtherFiles()
{
string[] fileName = Directory.GetFiles(OutPutDirRoot);
if (fileName != null && fileName.Length > 0)
{
for (int i = 0; i < fileName.Length; i++)
{
string extenstion = Path.GetExtension(fileName[i]);
if (extenstion == ".png" || extenstion == ".xml")
{
File.Delete(fileName[i]);
}
}
}
}
/// <summary>
/// establish Texture
/// </summary>
/// <param name="isNull"></param>
/// <param name="outPngPath"></param>
public void BuildTexturePacker(out bool isNull, out string outPngPath)
{
isNull = true;
outPngPath = "";
string[] imagePath = Directory.GetFiles(OutPutDirRoot);
foreach (string path in imagePath)
{
if (Path.GetExtension(path) == ".png" || Path.GetExtension(path) == ".PNG")
{
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
string rootPath = OutPutDirRoot + texture.name;
string pngPath = rootPath + "/" + texture.name + "_" + DateTime.Now.ToString("hh_mm_ss") + ".png";
outPngPath = pngPath;
isNull = false;
if (Directory.Exists(rootPath) == false)
{
Directory.CreateDirectory(rootPath);
}
File.Copy(OutPutDirRoot + texture.name + ".png", pngPath);
AssetDatabase.Refresh();
FileStream fs = new FileStream(OutPutDirRoot + texture.name + ".xml", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string jText = sr.ReadToEnd();
fs.Close();
sr.Close();
WriteMeta(jText, pngPath);
}
}
ClearOtherFiles();
AssetDatabase.Refresh();
}
void SelectAtlasUpdataWindow(string pngPath)
{
TPSelectFileWindow win = new TPSelectFileWindow();
win.Popup(pngPath, UpdataAssetRes);
}
void UpdataAssetRes(string opPath, Texture pendingTex)
{
var srcObj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(opPath);
TPFindReplaceRes tpFindRep = new TPFindReplaceRes();
tpFindRep.OnTPReplaceAssetData(pendingTex, srcObj);
}
// Write a message to SpritesSheet in
void WriteMeta(string jText, string path)
{
UnityEngine.Debug.Log("WriteMeta " + path);
XmlDocument xml = new XmlDocument();
xml.LoadXml(jText);
XmlNodeList elemList = xml.GetElementsByTagName("SubTexture");
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
string impPath = AssetDatabase.GetAssetPath(texture);
TextureImporter asetImp = TextureImporter.GetAtPath(impPath) as TextureImporter;
SpriteMetaData[] metaData = new SpriteMetaData[elemList.Count];
for (int i = 0, size = elemList.Count; i < size; i++)
{
XmlElement node = (XmlElement)elemList.Item(i);
Rect rect = new Rect();
rect.x = int.Parse(node.GetAttribute("x"));
rect.y = texture.height - int.Parse(node.GetAttribute("y")) - int.Parse(node.GetAttribute("height"));
rect.width = int.Parse(node.GetAttribute("width"));
rect.height = int.Parse(node.GetAttribute("height"));
metaData[i].rect = rect;
metaData[i].pivot = new Vector2(0.5f, 0.5f);
metaData[i].name = node.GetAttribute("name");
}
asetImp.spritesheet = metaData;
asetImp.textureType = TextureImporterType.Sprite;
asetImp.spriteImportMode = SpriteImportMode.Multiple;
asetImp.mipmapEnabled = false;
asetImp.SaveAndReimport();
}
private string OpenTPEXE()
{
string path = EditorUtility.OpenFilePanel(" Please locate TexturePacker.exe Program , For subsequent operations ", "", "exe");
return path;
}
private void OnError(string err)
{
UnityEngine.Debug.LogError("TPBuild Err:" + err);
EditorUtility.DisplayDialog(" Please reposition TexturePacker.exe Program !", "Err:" + err, " determine ");
var path = OpenTPEXE();
if (path.Length != 0)
{
RunExternalApp(path, argument);
}
}
public class FileData
{
public string dirName;
public List<string> filesList;
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
/// <summary>
/// Editor main interface
/// </summary>
public class TPSelectFileWindow : EditorWindow {
private Action<string, Texture> _callBack;
private string _opPath;
private Texture _selectTex;
public void Popup(string opPath, Action<string, Texture> cb)
{
_callBack = cb;
_opPath = opPath;
var isSeek = EditorUtility.DisplayDialog(" Waiting for execution ...", " Whether to update the original atlas , Currently, only a single atlas can be updated ", " determine ", " Cancel ");
if (isSeek == true)
{
TPSelectFileWindow window = EditorWindow.GetWindow(typeof(TPSelectFileWindow), true, " Waiting for execution ...") as TPSelectFileWindow;
window.minSize = new Vector2(450, 300);
window.Show();
}
else
{
if (_callBack != null)
{
_callBack.Invoke(_opPath, _selectTex);
}
_callBack = null;
}
}
private void OnGUI()
{
ShowEditorGUI();
}
private void ShowEditorGUI()
{
_selectTex = EditorGUILayout.ObjectField(" Add the original bound Texture", _selectTex, typeof(Texture), true) as Texture;
if (_selectTex != null && string.IsNullOrEmpty(_selectTex.name) == false)
{
EditorGUILayout.TextField(AssetDatabase.GetAssetOrScenePath(_selectTex));
}
if (GUILayout.Button(" Close the window and continue "))
{
// close window
this.Close();
}
}
private void OnDestroy()
{
if (_callBack != null)
{
_callBack.Invoke(_opPath, _selectTex);
}
_callBack = null;
_selectTex = null;
}
}
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
using System.Collections;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
public class TPFindReplaceRes {
Dictionary<string, AssetData> assetDic;
string srcGUID;
string tarGUID;
/// <summary>
/// to update Asset data
/// </summary>
/// <param name="srcObj"> Retrieve the located OBJ, It can be discarded after operation </param>
/// <param name="tarObj"> Wait for the updated data to be clean OBJ</param>
public void OnTPReplaceAssetData(Object srcObj, Object tarObj) {
AssetDatabase.Refresh();
EditorSettings.serializationMode = SerializationMode.ForceText;
string srcPath = AssetDatabase.GetAssetPath(srcObj);
string tarPath = AssetDatabase.GetAssetPath(tarObj);
if (string.IsNullOrEmpty(tarPath) || string.IsNullOrEmpty(srcPath))
{
Debug.Log("srcObj = null || tarObj = null");
return;
}
Debug.LogFormat("srcPath:{0} , tarPath:{1}", srcPath, tarPath);
srcGUID = AssetDatabase.AssetPathToGUID(srcPath);
tarGUID = AssetDatabase.AssetPathToGUID(tarPath);
OnCreateMetaData(srcPath, tarPath);
var withoutExtensions = new List<string>() { ".prefab", ".unity", ".mat", ".asset" };
string[] files = Directory.GetFiles(Application.dataPath, "*.*", SearchOption.AllDirectories).Where(s => withoutExtensions.Contains(Path.GetExtension(s).ToLower())).ToArray();
int startIndex = 0;
EditorApplication.update = delegate () {
string file = files[startIndex];
bool isCancel = EditorUtility.DisplayCancelableProgressBar(" Matching resources ", file, (float)startIndex / (float)files.Length);
if (Regex.IsMatch(File.ReadAllText(file), srcGUID))
{
OnUpdateData(file);
var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(GetRelativeAssetsPath(file));
Debug.Log(" Replacement object " + file, obj);
}
startIndex++;
if (isCancel || startIndex >= files.Length)
{
EditorUtility.ClearProgressBar();
EditorApplication.update = null;
startIndex = 0;
Debug.Log(" End of data update ");
}
};
}
void OnCreateMetaData(string srcPath, string tarPath)
{
string srcMeta = AssetDatabase.GetTextMetaFilePathFromAssetPath(srcPath);
string tarMeta = AssetDatabase.GetTextMetaFilePathFromAssetPath(tarPath);
string[] srcFile = File.ReadAllLines(srcMeta);
string[] tarFile = File.ReadAllLines(tarMeta);
List<string> smList = new List<string>();
List<string> tempList = new List<string>();
TextureImporter srcImp = TextureImporter.GetAtPath(srcPath) as TextureImporter;
TextureImporter tarImp = TextureImporter.GetAtPath(tarPath) as TextureImporter;
foreach (var spMD in tarImp.spritesheet)
{
tempList.Add(spMD.name);
}
foreach (var spMD in srcImp.spritesheet)
{
if (tempList.Contains(spMD.name))
{
smList.Add(spMD.name);
//Debug.Log(" matching SpriteSheetMeta " + spMeta.name);
}
}
assetDic = new Dictionary<string, AssetData>();
foreach (var key in smList)
{
AssetData data = new AssetData();
data.name = key;
assetDic.Add(key, data);
foreach (var srcStr in srcFile)
{
if (srcStr.IndexOf(key) >= 0)
{
var str = srcStr.Trim();
var spMetaId = str.Substring(0, str.IndexOf(":"));
//Debug.LogFormat("src ==> {0} {1}", key, spMetaId);
if (string.IsNullOrEmpty(assetDic[key].src))
{
assetDic[key].src = spMetaId;
}
}
}
foreach (var tarStr in tarFile)
{
if (tarStr.IndexOf(key) >= 0)
{
var str = tarStr.Trim();
var spMetaId = str.Substring(0, str.IndexOf(":"));
//Debug.LogFormat("tar ==> {0} {1}", key, spMetaId);
if (string.IsNullOrEmpty(assetDic[key].tar))
{
assetDic[key].tar = spMetaId;
}
}
}
if (string.IsNullOrEmpty(assetDic[key].src) || string.IsNullOrEmpty(assetDic[key].tar))
{
assetDic.Remove(key);
}
}
//foreach (var meta in assetDic)
//{
// var data = meta.Value;
// Debug.LogFormat("meta ==> name:{0} src:{1} tar:{2}", data.name, data.src, data.tar);
//}
}
void OnUpdateData(string file)
{
var allInfo = File.ReadAllLines(file);
for (int i = 0; i < allInfo.Length; i++)
{
var str = allInfo[i];
if (str.IndexOf(srcGUID) >= 0)
{
if (str.IndexOf("guid") >= 0)
{
// Replace old GUID
str = str.Replace(srcGUID, tarGUID);
// Replace old fileID
if (str.IndexOf("fileID") >= 0)
{
foreach (var meta in assetDic)
{
if (str.IndexOf(meta.Value.src) >= 0)
{
str = str.Replace(meta.Value.src, meta.Value.tar);
}
}
}
}
allInfo[i] = str;
}
}
File.WriteAllLines(file, allInfo);
}
static string GetRelativeAssetsPath(string path) {
return "Assets" + Path.GetFullPath(path).Replace(Path.GetFullPath(Application.dataPath), "").Replace('\\', '/');
}
public class AssetData
{
public string name;
public string src;
public string tar;
}
}
边栏推荐
- How does geojson data merge the boundaries of regions?
- 强化实时数据管理,英方软件助力医保平台安全建设
- Iterator and for of.. loop
- Vite path alias @ configuration
- Detailed explanation of Cocos creator 2.4.0 rendering process
- LeetCode3_ Longest substring without duplicate characters
- C4D learning notes 2- animation - timeline and time function
- 一大波开源小抄来袭
- Use moviepy Editor clips videos and intercepts video clips in batches
- Cocos uses custom material to display problems
猜你喜欢
Async and await
Super signature principle (fully automated super signature) [Yun Xiaoduo]
[quick start of Digital IC Verification] 18. Basic grammar of SystemVerilog learning 5 (concurrent threads... Including practical exercises)
JS array foreach source code parsing
Cut ffmpeg as needed, and use emscripten to compile and run
Keil5 does not support online simulation of STM32 F0 series
[quick start of Digital IC Verification] 25. AHB sramc of SystemVerilog project practice (5) (AHB key review, key points refining)
webgl_ Enter the three-dimensional world (2)
航运船公司人工智能AI产品成熟化标准化规模应用,全球港航人工智能/集装箱人工智能领军者CIMC中集飞瞳,打造国际航运智能化标杆
unnamed prototyped parameters not allowed when body is present
随机推荐
Cocos creator collision and collision callback do not take effect
航運船公司人工智能AI產品成熟化標准化規模應用,全球港航人工智能/集裝箱人工智能領軍者CIMC中集飛瞳,打造國際航運智能化標杆
Getting started with webgl (2)
Detailed explanation of unity hot update knowledge points and introduction to common solution principles
TS as a general cache method
Getting started with webgl (4)
[Lanzhou University] information sharing of postgraduate entrance examination and re examination
Use moviepy Editor clips videos and intercepts video clips in batches
Spin animation of Cocos performance optimization
Webgl texture
TS typescript type declaration special declaration field number is handled when the key key
There are many ways to realize the pause function in JS
Limit of total fields [1000] in index has been exceeded
Clang compile link ffmpeg FAQ
Jacobo code coverage
XMIND frame drawing tool
It's different for rich people to buy a house
The rebound problem of using Scrollview in cocos Creator
Three. JS introductory learning notes 08:orbitcontrols JS plug-in - mouse control model rotation, zoom in, zoom out, translation, etc
Yunxiaoduo software internal test distribution test platform description document