优化查询效率,完善文档

This commit is contained in:
biaosong 2024-12-17 11:07:00 +08:00
parent 0c235c839a
commit 55c07e95af
19 changed files with 440 additions and 103 deletions

View File

@ -107,6 +107,13 @@ function s2t(t) { return stringIDToTypeID(t) }
return;
}
// 判断文件名是否有中文
if (Util.haveChinese(app.activeDocument.name))
{
alert("\"" + app.activeDocument.name + "\" 名字不合法,出现中文")
return;
}
this.documentName = app.activeDocument.name.slice(0, -4);
var i, j, k, len, ref1, removeFiles;
@ -445,12 +452,6 @@ function s2t(t) { return stringIDToTypeID(t) }
return true
}
function isChinese(temp) {
var re = /[^\u4E00-\u9FA5]/;
if (re.test(temp)) return false;
return true;
}
function isNumber(val) {
var regPos = /^\d+(\.\d+)?$/; //非负浮点数
var regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; //负浮点数
@ -1221,6 +1222,12 @@ function s2t(t) { return stringIDToTypeID(t) }
return imageName + layer.name.split("@")[0].replace('_', '').replace(' ', '-').toLowerCase();
};
Util.haveChinese = function (temp) {
var re = /[\u4E00-\u9FA5]/;
if (re.test(temp)) return true;
return false;
}
Util.getLastSnapshotID = function (doc) {
var hsLength, hsObj, i, j, ref1;
hsObj = doc.historyStates;

View File

@ -1,2 +1,2 @@
cd /d %~dp0
start step2.exe -src C:\Users\biaosong\Desktop\c2main_panel -dst C:\Users\biaosong\Desktop\c2main_panel_output
start step2.exe -src C:\Users\biaosong\Desktop\shijiezhishi -dst C:\Users\biaosong\Desktop\shijiezhishi_output

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 529 KiB

After

Width:  |  Height:  |  Size: 274 KiB

BIN
.res/创建预制体.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 KiB

After

Width:  |  Height:  |  Size: 667 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 KiB

BIN
.res/展示.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 KiB

View File

@ -2,6 +2,7 @@
using Sirenix.OdinInspector;
using System;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
@ -44,19 +45,27 @@ namespace UguiToolkit.Editor
public virtual void ApplyTransformByParent(Transform parentTf, Transform tf)
{
var position = lastMoveMatrix.GetColumn(3); // 提取位置
var rotation = Quaternion.LookRotation(lastMoveMatrix.GetColumn(2), lastMoveMatrix.GetColumn(1)); // 提取旋转
Debug.Log($"[I] ApplyTransformByParent {position}, {rotation.eulerAngles}");
parentTf.position += new Vector3(position.x, position.y, position.z);
parentTf.rotation *= rotation;
Undo.RecordObject(parentTf, "ApplyTransformByParent");
var resultMatrix = lastMoveMatrix * parentTf.localToWorldMatrix;
parentTf.position = resultMatrix.GetColumn(3);
parentTf.rotation = Quaternion.LookRotation(resultMatrix.GetColumn(2), resultMatrix.GetColumn(1));
parentTf.localScale = new Vector3(
resultMatrix.GetColumn(0).magnitude,
resultMatrix.GetColumn(1).magnitude,
resultMatrix.GetColumn(2).magnitude
);
if (tf)
{
var lastTransformMatrixInverse = lastMoveMatrix.inverse;
position = lastTransformMatrixInverse.GetColumn(3); // 提取位置
rotation = Quaternion.LookRotation(lastTransformMatrixInverse.GetColumn(2), lastTransformMatrixInverse.GetColumn(1)); // 提取旋转
tf.position += new Vector3(position.x, position.y, position.z);
tf.rotation *= rotation;
Undo.RecordObject(tf, "ApplyTransformByParent");
resultMatrix = lastMoveMatrix.inverse * tf.localToWorldMatrix;
tf.position = resultMatrix.GetColumn(3);
tf.rotation = Quaternion.LookRotation(resultMatrix.GetColumn(2), resultMatrix.GetColumn(1));
tf.localScale = new Vector3(
resultMatrix.GetColumn(0).magnitude,
resultMatrix.GetColumn(1).magnitude,
resultMatrix.GetColumn(2).magnitude
);
}
}
@ -72,8 +81,9 @@ namespace UguiToolkit.Editor
public void ApplyTransform(Transform tf)
{
Debug.Log($"[I] ApplyTransform {tf.name}");
Undo.RecordObject(tf, "ApplyTransform");
OnApplyTransform(tf);
Matrix4x4 newTransformMatrix = Matrix4x4.TRS(tf.position, tf.rotation, tf.localScale);
lastMoveMatrix = newTransformMatrix * oldTransformMatrix.inverse;
}
@ -94,6 +104,7 @@ namespace UguiToolkit.Editor
public void ApplyData<T>(T ui) where T : Component
{
Undo.RecordObject(ui, "ApplyData");
OnApplyData(ui as T1);
}

View File

@ -69,6 +69,7 @@ namespace UguiToolkit.Editor
if (!TryGetComponent<Image>(out m_previewImage))
{
m_previewImage = gameObject.AddComponent<Image>();
m_previewImage.type = Image.Type.Simple;
}
LoadImageFromFile(ElementInfo.imgPath);
@ -83,13 +84,11 @@ namespace UguiToolkit.Editor
{
var pos = ElementInfo.Position;
var worldPos = StageManager.Instance.PrefabContentsRoot.transform.TransformPoint(new Vector3(pos.x, pos.y, 0));
var anchorMin = rt.anchorMin;
var anchorMax = rt.anchorMax;
var oldPiovt = rt.pivot;
rt.pivot = new Vector2(0.5f, 0.5f);
Vector2 size = new Vector2(ElementInfo.w, ElementInfo.h); ;
Vector2 size = new Vector2(ElementInfo.w, ElementInfo.h);
Quaternion rotation = Quaternion.identity;
if (!similarityCalc)
@ -106,12 +105,8 @@ namespace UguiToolkit.Editor
}
// 调整大小
rt.anchorMin = rt.pivot;
rt.anchorMax = rt.pivot;
var oldSizeDelta = rt.sizeDelta;
rt.sizeDelta = new Vector2(size.x, size.y);
rt.anchorMin = anchorMin;
rt.anchorMax = anchorMax;
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x);
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y);
// 设置世界坐标
rt.position = worldPos;
@ -119,7 +114,9 @@ namespace UguiToolkit.Editor
//修正中心点
var oldRect = rt.rect;
var oldLocalPosition = rt.localPosition;
rt.pivot = oldPiovt;
rt.localPosition = oldLocalPosition;
var offsetRectPos = oldRect.position - rt.rect.position;
rt.Translate(offsetRectPos);
}

View File

@ -16,23 +16,28 @@ namespace UguiToolkit.Editor
protected override void OnApplyTransform(Transform tf)
{
var rt = tf as RectTransform;
var pos = ElementInfo.Position;
Vector2 size = new Vector2(ElementInfo.w, ElementInfo.h);
var worldPos = StageManager.Instance.PrefabContentsRoot.transform.TransformPoint(new Vector3(pos.x, pos.y, 0));
Quaternion rotation = Quaternion.identity;
var oldPiovt = rt.pivot;
rt.pivot = new Vector2(0.5f, 0.5f);
// 调整大小
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x);
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y);
// 设置世界坐标
rt.position = worldPos;
rt.rotation = rotation;
//修正中心点
var oldRect = rt.rect;
var oldLocalPosition = rt.localPosition;
rt.pivot = oldPiovt;
rt.localPosition = oldLocalPosition;
var offsetRectPos = oldRect.position - rt.rect.position;
rt.Translate(offsetRectPos);
}
protected override void OnApplyData(TextMeshProUGUI ui)
@ -47,22 +52,45 @@ namespace UguiToolkit.Editor
if (!TryGetComponent<TextMeshProUGUI>(out m_previewText))
{
m_previewText = gameObject.AddComponent<TextMeshProUGUI>();
m_previewText.alignment = TextAlignmentOptions.Center;
}
OnApplyData(m_previewText);
ApplyTransform(transform);
}
// 在保证文本坐标不变的情况下设置 对齐方式
private static void SetAlignment(TextMeshProUGUI textMeshPro, TextAlignmentOptions newAlignment)
{
textMeshPro.ForceMeshUpdate();
// 获取当前文本的边界框
Bounds originalBounds = textMeshPro.textBounds;
// 设置新的对齐方式
textMeshPro.alignment = newAlignment;
// 更新布局
textMeshPro.ForceMeshUpdate();
// 获取新的边界框
Bounds newBounds = textMeshPro.textBounds;
// 计算偏移量
Vector3 offset = originalBounds.center - newBounds.center;
// 调整TextMeshPro的位置
textMeshPro.transform.position += offset;
}
private static void SetTMPByTextInfo(TextMeshProUGUI ui, LayoutInfo.TextInfo textInfo)
{
// TODO: 自行扩展
// 保存当前的对齐方式
TextAlignmentOptions originalAlignment = ui.alignment;
float2 sizeOffset = float2.zero;
ui.alignment = TextAlignmentOptions.Center;
if (!ui.hasStringID) ui.text = textInfo.text;
ui.fontSize = (int)textInfo.size;
ui.color = textInfo.color;
ui.alignment = TextAlignmentOptions.Center;
if (GetTextFontPreset(textInfo, out var textFontPreset))
{
@ -86,21 +114,15 @@ namespace UguiToolkit.Editor
sizeOffset = textFontPreset.sizeOffset;
}
var rt = ui.rectTransform;
var anchorMin = rt.anchorMin;
var anchorMax = rt.anchorMax;
// µ÷Õû´óС
rt.anchorMin = new Vector2(0.5f, 0.5f);
rt.anchorMax = anchorMin;
rt.sizeDelta = new Vector2(textInfo.w + sizeOffset.x, textInfo.h + sizeOffset.y);
rt.anchorMin = anchorMin;
rt.anchorMax = anchorMax;
// 调整margins
ui.margin = Vector4.zero;
// 设置字间距
ui.characterSpacing = 0f;
// 设置对齐方式
if (originalAlignment != TextAlignmentOptions.Center)
SetAlignment(ui, originalAlignment);
}
private static bool GetTextFontPreset(LayoutInfo.TextInfo textInfo, out TextFontPresetOfUnity textFontPreset)

View File

@ -28,30 +28,163 @@ public static class ImageUtils
return Path.GetRelativePath(projectPath, imgFilePath).Replace("\\", "/");
}
public static void LoadPngImagesFromFolder(string folderPath, List<Mat> images, List<string> imagePaths)
public static void LoadPngImagesFromFolder(string folderPath, List<Mat> images, List<string> imagePaths, Func<string, bool> filterCallback)
{
foreach (string file in Directory.GetFiles(folderPath, "*.png"))
foreach (string filePath in Directory.GetFiles(folderPath, "*.png"))
{
Mat img = Imgcodecs.imread(file);
if (filterCallback(filePath)) continue;
Mat img = Imgcodecs.imread(filePath, Imgcodecs.IMREAD_UNCHANGED);
if (!img.empty())
{
images.Add(img);
imagePaths.Add(FormatImgFilePath(file));
imagePaths.Add(FormatImgFilePath(filePath));
}
}
}
#region SliceTexture
static List<int> hashListOfSlice;
static int ToHashCode(in Color color)
{
int a = Mathf.RoundToInt(color.a * 255);
if (a == 0) return 0;
int r = Mathf.RoundToInt(color.r * 255);
int g = Mathf.RoundToInt(color.g * 255);
int b = Mathf.RoundToInt(color.b * 255);
return (a << 24) + (r << 16) + (g << 8) + b;
}
static (int, int) CalcLine(List<int> hashList)
{
int start = 0, end = 0;
int tmpStart = 0, tmpEnd = 0;
int tmpHash = hashList[0];
for (int i = 0; i < hashList.Count; i++)
{
if (tmpHash == hashList[i])
{
tmpEnd = i;
}
else
{
if (end - start < tmpEnd - tmpStart)
{
start = tmpStart;
end = tmpEnd;
}
tmpStart = i;
tmpEnd = i;
tmpHash = hashList[i];
}
}
if (end - start < tmpEnd - tmpStart)
{
start = tmpStart;
end = tmpEnd;
}
return (start, end);
}
static List<int> CreateHashList(Mat image, in char axis)
{
if (hashListOfSlice == null) hashListOfSlice = new ();
var hashList = hashListOfSlice;
hashList.Clear();
if (axis == 'x')
{
for (int i = 0; i < image.cols(); i++)
{
int hash = 0;
for (int j = 0; j < image.rows(); j++)
{
double[] color = image.get(j, i);
hash += ToHashCode(new Color((float)color[2] / 255, (float)color[1] / 255, (float)color[0] / 255, (float)color[3] / 255));
}
hashList.Add(hash);
}
}
else
{
for (int j = 0; j < image.rows(); j++)
{
int hash = 0;
for (int i = 0; i < image.cols(); i++)
{
double[] color = image.get(j, i);
hash += ToHashCode(new Color((float)color[2] / 255, (float)color[1] / 255, (float)color[0] / 255, (float)color[3] / 255));
}
hashList.Add(hash);
}
}
return hashList;
}
public static void SliceTexture(string imagePath, string outputPath)
{
var mat = SliceTexture(imagePath);
Imgcodecs.imwrite(outputPath, mat, new MatOfInt(Imgcodecs.IMWRITE_PNG_COMPRESSION, 9));
}
public static Mat SliceTexture(string imagePath)
{
Mat image = Imgcodecs.imread(imagePath, Imgcodecs.IMREAD_UNCHANGED); // ʹÓÃOpenCV¼ÓÔØÍ¼Ïñ
int width = image.cols();
int height = image.rows();
List<int> hashListX = CreateHashList(image, 'x');
(int xStart, int xEnd) = CalcLine(hashListX);
List<int> hashListY = CreateHashList(image, 'y');
(int yStart, int yEnd) = CalcLine(hashListY);
int outputWidth = width - (xEnd - xStart);
int outputHeight = height - (yEnd - yStart);
var outputMat = new Mat(outputHeight, outputWidth, CvType.CV_8UC4);
for (int x = 0; x < outputWidth; x++)
{
int originalX = x < xStart ? x : x + (xEnd - xStart);
for (int y = 0; y < outputHeight; y++)
{
int originalY = y < yStart ? y : y + (yEnd - yStart);
double[] color = image.get(originalY, originalX);
outputMat.put(y, x, color);
}
}
return outputMat;
}
#endregion
static List<Task<(double?, (double, double)?)>> tasks;
static ObjectPool<RotationScaleDetector> detectorPool;
public static async Task ProcessFolderAsync(List<Mat> images, string targetFilePath,
double distanceDifference, Action<int, (double, (double, double), bool)> callback,
Action endCallback)
Action endCallback, bool isSliceTexture = false)
{
if (tasks == null) tasks = new (images.Count);
if (detectorPool == null) detectorPool = new (images.Count);
Mat targetImage = Imgcodecs.imread(targetFilePath);
Mat targetImage = null;
if (isSliceTexture)
{
targetImage = SliceTexture(targetFilePath);
}
else {
targetImage = Imgcodecs.imread(targetFilePath, Imgcodecs.IMREAD_UNCHANGED);
}
List<RotationScaleDetector> detectors = new(images.Count);
tasks.Clear();

View File

@ -1,5 +1,6 @@
#if UNITY_EDITOR
using Sirenix.OdinInspector.Editor;
using System;
using UguiToolkit.Editor.Windows;
using UnityEditor;
using UnityEditor.SceneManagement;
@ -9,6 +10,9 @@ namespace UguiToolkit.Editor
{
public static class PanelHelper
{
public static event Action<Transform> jumpOfGameCameraByCurPos;
public static event Action<Transform> recoverDataSelectionObjCache;
[InitializeOnLoadMethod]
public static void AddListener()
{
@ -45,11 +49,26 @@ namespace UguiToolkit.Editor
{
if (StageManager.Instance)
{
var entityMng = StageManager.Instance.GetManager<EntityManager>();
if (entityMng && Selection.activeGameObject)
{
entityMng.EffectLastApplyTransform(Selection.activeGameObject.transform);
}
if (Selection.activeGameObject)
jumpOfGameCameraByCurPos.Invoke(Selection.activeGameObject.transform);
Debug.Log("JumpOfGameCameraByCurPos");
}
}
/// <summary>
/// 创建热键 CTRL SPACE
/// </summary>
/// <param name="menuCommand"></param>
[MenuItem("GameObject/拼接助手/恢复子节点位置 %SPACE", false, 6)]
public static void RecoverDataSelectionObjCache(MenuCommand menuCommand)
{
if (StageManager.Instance)
{
if (Selection.activeGameObject)
recoverDataSelectionObjCache.Invoke(Selection.activeGameObject.transform);
Debug.Log("RecoverDataSelectionObjCache");
}
}
}

View File

@ -12,18 +12,25 @@ using UnityEngine.UI;
using UguiToolkit.Editor.Windows;
using System.Threading.Tasks;
using Unity.Mathematics;
using Securify.ShellLink.Flags;
namespace UguiToolkit.Editor
{
[ExecuteAlways]
public class EntityManager : MonoBehaviour, IManager
{
private const string m_backgroundFileName= "__background__";
private string m_BackgroundFileAllName= m_backgroundFileName + ".png";
private PanelCache m_panelCache;
private Transform m_entityRoot;
private Transform m_background;
private GameObject m_lastSelectionGo;
private IEntity m_lastSelectionEntity;
private GameObject m_curSelectionGo;
private GameObject m_lastApplyDataGo; // 上一次应用的游戏对象
private IEntity m_lastApplyDataEntity; // 上一次应用的entity
private GameObject m_curSelectionEntityGo; // 当前选中的entity游戏对象
private GameObject m_curSelectionGo; // 当前选中的游戏对象
private SelectionObjCache m_curSelectionObjCache = new (); // 当前选中的游戏对象的缓存数据
private Color m_curSelectionObjLabelColor = Color.yellow;
private List<ImageEntity> m_imageEntities;
private List<IEntity> m_textEntities;
@ -60,9 +67,12 @@ namespace UguiToolkit.Editor
editWindow.createAllTextEntity += CreateAllTextEntity;
editWindow.createAllPrefabEntity += CreateAllPrefabEntity;
editWindow.effectLastApplyTransform += EffectLastApplyTransform;
editWindow.recoverDataSelectionObjCache += OnRecoverDataSelectionObjCache;
}
EditorApplication.hierarchyWindowItemOnGUI += HandleHierarchyWindowItemOnGUI;
PanelHelper.jumpOfGameCameraByCurPos += EffectLastApplyTransform;
PanelHelper.recoverDataSelectionObjCache += RecoverDataSelectionObjCache;
ImageUtils.SetDebugMode(true);
}
@ -78,9 +88,12 @@ namespace UguiToolkit.Editor
editWindow.createAllTextEntity -= CreateAllTextEntity;
editWindow.createAllPrefabEntity -= CreateAllPrefabEntity;
editWindow.effectLastApplyTransform -= EffectLastApplyTransform;
editWindow.recoverDataSelectionObjCache -= OnRecoverDataSelectionObjCache;
}
EditorApplication.hierarchyWindowItemOnGUI -= HandleHierarchyWindowItemOnGUI;
PanelHelper.jumpOfGameCameraByCurPos -= EffectLastApplyTransform;
PanelHelper.recoverDataSelectionObjCache -= RecoverDataSelectionObjCache;
ImageUtils.SetDebugMode(false);
if (m_stageManager.PrefabAsset || m_panelCache != null)
@ -90,21 +103,21 @@ namespace UguiToolkit.Editor
private void Update()
{
// 检测是否到达可选实例矩形内部
if (m_selectionEntities != null && m_curSelectionGo)
if (m_selectionEntities != null && m_curSelectionEntityGo)
{
if (m_lastSelectionGo && m_lastSelectionGo == m_curSelectionGo)
if (m_lastApplyDataGo && m_lastApplyDataGo == m_curSelectionEntityGo)
{
if (m_lastSelectionEntity != null && !m_lastSelectionEntity.IsInside(m_lastSelectionGo.transform))
if (m_lastApplyDataEntity != null && !m_lastApplyDataEntity.IsInside(m_lastApplyDataGo.transform))
{
m_lastSelectionGo = null;
m_lastSelectionEntity = null;
m_lastApplyDataGo = null;
m_lastApplyDataEntity = null;
}
return;
}
foreach (var entity in m_selectionEntities)
{
var tf = m_curSelectionGo.transform;
var tf = m_curSelectionEntityGo.transform;
if (entity.IsInside(tf))
{
entity.ApplyTransform(tf);
@ -125,8 +138,8 @@ namespace UguiToolkit.Editor
entity.ApplyData(temp);
}
m_lastSelectionGo = m_curSelectionGo;
m_lastSelectionEntity = entity;
m_lastApplyDataGo = m_curSelectionEntityGo;
m_lastApplyDataEntity = entity;
Selection.activeGameObject = null;
break;
@ -135,11 +148,36 @@ namespace UguiToolkit.Editor
}
}
private void UpdateSelectionObjLabelColor()
{
m_curSelectionObjLabelColor = m_curSelectionObjLabelColor == Color.yellow ? Color.blue : Color.yellow;
}
private void OnRecoverDataSelectionObjCache()
{
if (m_curSelectionObjCache.Transform)
m_curSelectionObjCache.RecoverData();
}
private void RecoverDataSelectionObjCache(Transform parent)
{
if (m_curSelectionObjCache.Transform && m_curSelectionObjCache.Transform == parent)
{
m_curSelectionObjCache.RecoverData();
}
}
public void EffectLastApplyTransform(Transform parent)
{
if (m_lastSelectionEntity != null)
if (m_lastApplyDataEntity != null)
{
m_lastSelectionEntity.ApplyTransformByParent(parent, m_lastSelectionGo ? m_lastSelectionGo.transform: null);
m_lastApplyDataEntity.ApplyTransformByParent(parent, m_lastApplyDataGo ? m_lastApplyDataGo.transform: null);
if (m_curSelectionObjCache.Transform)
{
m_curSelectionObjCache.SetData(m_curSelectionObjCache.Transform);
UpdateSelectionObjLabelColor();
}
}
}
@ -148,11 +186,12 @@ namespace UguiToolkit.Editor
if (!m_stageManager) return;
var go = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
if (!go) return;
if (go == m_lastSelectionGo)
var goLabel = new GUIContent(go.name);
var goSize = EditorStyles.linkLabel.CalcSize(goLabel) + new Vector2(20, 0);
if (go == m_lastApplyDataGo)
{
var goLabel = new GUIContent(go.name);
var goSize = EditorStyles.linkLabel.CalcSize(goLabel) + new Vector2(20, 0);
var label = new GUIContent(" <-----");
var label = new GUIContent(" <---------锚点");
var size = EditorStyles.linkLabel.CalcSize(label) + new Vector2(10, 0);
var offsetRect =
new Rect(selectionRect.position + new Vector2(goSize.x, 0), size);
@ -161,6 +200,24 @@ namespace UguiToolkit.Editor
normal = new GUIStyleState() { textColor = Color.green },
});
}
if (go.transform == m_curSelectionObjCache.Transform)
{
var label = new GUIContent(" <---------复原子节点");
var size = EditorStyles.linkLabel.CalcSize(label) + new Vector2(10, 0);
var offsetRect =
new Rect(selectionRect.position + new Vector2(goSize.x, 0), size);
EditorGUI.LabelField(offsetRect, label, new GUIStyle()
{
normal = new GUIStyleState() { textColor = m_curSelectionObjLabelColor },
});
}
}
[Button("TestSliceTexture")]
private void TestSliceTexture(string imagePath, string outputPath)
{
ImageUtils.SliceTexture(imagePath, outputPath);
}
private void CreateAllTextEntity()
@ -208,7 +265,7 @@ namespace UguiToolkit.Editor
{
if (m_background) DestroyImmediate(m_background.gameObject);
var go = new GameObject("__background__", typeof(RectTransform));
var go = new GameObject(m_backgroundFileName, typeof(RectTransform));
UpdateHierarchyOfEntity(false, go);
m_background = go.transform;
m_background.SetParent(transform);
@ -228,7 +285,7 @@ namespace UguiToolkit.Editor
imgTf.localRotation = Quaternion.identity;
imgTf.localScale = Vector3.one;
var img = imgGo.AddComponent<Image>();
var imgPath = System.IO.Path.Join(m_panelCache.TargetImgDirPath, "__background__.png");
var imgPath = System.IO.Path.Join(m_panelCache.TargetImgDirPath, m_BackgroundFileAllName);
if (System.IO.File.Exists(imgPath))
{
byte[] fileData = System.IO.File.ReadAllBytes(imgPath);
@ -244,7 +301,7 @@ namespace UguiToolkit.Editor
UpdateHierarchyOfEntity(false, imgGo);
}
private void UpdatePanelCache(string srcImgPath)
private void UpdatePanelCache(string srcImgPath, bool isSliceTexture = false)
{
float distanceDifference = GlobalManager.Instance.setting.distanceDifference;
isCalcRotationScaleRunning = true;
@ -269,18 +326,22 @@ namespace UguiToolkit.Editor
m_panelCache.AddRotScaleInfo(srcImgPath, rotScaleItemList);
if (rotScaleItemList.Count > 0)
OnSelectionChanged();
});
}, isSliceTexture: isSliceTexture);
}
private void OnSelectionChanged()
{
if (m_noSelection || !Selection.activeGameObject || Selection.gameObjects.Length > 1) return;
if (Selection.activeGameObject == m_curSelectionGo || !Selection.activeGameObject.activeSelf) return;
if (Selection.activeGameObject == m_curSelectionEntityGo || !Selection.activeGameObject.activeSelf) return;
var activeGameObject = Selection.activeGameObject;
if (activeGameObject.transform.parent == m_entityRoot || activeGameObject.transform.parent == m_background)
return;
m_curSelectionGo = null;
m_curSelectionGo = activeGameObject;
m_curSelectionObjCache.SetData(activeGameObject.transform);
UpdateSelectionObjLabelColor();
m_curSelectionEntityGo = null;
m_selectionEntities.Clear();
m_entityRoot.gameObject.SetActive(false);
@ -304,14 +365,14 @@ namespace UguiToolkit.Editor
if (IsInside)
{
if (m_lastSelectionGo && m_lastSelectionGo == activeGameObject)
if (m_lastApplyDataGo && m_lastApplyDataGo == activeGameObject)
{
m_curSelectionGo = activeGameObject;
m_curSelectionEntityGo = activeGameObject;
}
}
else
{
m_curSelectionGo = activeGameObject;
m_curSelectionEntityGo = activeGameObject;
}
foreach (var imgEntity in m_imageEntities)
@ -367,14 +428,14 @@ namespace UguiToolkit.Editor
if (IsInside)
{
if (m_lastSelectionGo && m_lastSelectionGo == activeGameObject)
if (m_lastApplyDataGo && m_lastApplyDataGo == activeGameObject)
{
m_curSelectionGo = activeGameObject;
m_curSelectionEntityGo = activeGameObject;
}
}
else
{
m_curSelectionGo = activeGameObject;
m_curSelectionEntityGo = activeGameObject;
}
foreach (var textEntity in m_textEntities)
@ -406,14 +467,14 @@ namespace UguiToolkit.Editor
if (IsInside)
{
if (m_lastSelectionGo && m_lastSelectionGo == activeGameObject)
if (m_lastApplyDataGo && m_lastApplyDataGo == activeGameObject)
{
m_curSelectionGo = activeGameObject;
m_curSelectionEntityGo = activeGameObject;
}
}
else
{
m_curSelectionGo = activeGameObject;
m_curSelectionEntityGo = activeGameObject;
}
foreach (var imgEntity in m_imageEntities)
@ -431,11 +492,12 @@ namespace UguiToolkit.Editor
{
if (activeGameObject.TryGetComponent<Image>(out var image) && image.IsActive() && image.sprite)
{
var srcImgPath = AssetDatabase.GetAssetPath(image.sprite);
var sprite = image.sprite;
var srcImgPath = AssetDatabase.GetAssetPath(sprite);
if (!string.IsNullOrEmpty(srcImgPath) && !m_panelCache.HaveRotScaleInfo(srcImgPath) &&
!isCalcRotationScaleRunning)
{
UpdatePanelCache(srcImgPath);
UpdatePanelCache(srcImgPath, sprite.border != Vector4.zero);
//var srcImgDirPath = System.IO.Path.GetDirectoryName(srcImgPath);
//AddCheckImgDirPath(srcImgDirPath);
@ -453,9 +515,28 @@ namespace UguiToolkit.Editor
CreateAllEntity();
InitBackground();
HashSet<string> slicePaths = new HashSet<string>();
foreach (var entity in m_imageEntities)
{
var elementInfo = entity.ElementInfo;
if (elementInfo.HaveSlice)
{
var imageName = Path.GetFileName(elementInfo.imgPath);
slicePaths.Add(imageName);
}
}
targetImages = new ();
targetPaths = new ();
ImageUtils.LoadPngImagesFromFolder(panelCache.TargetImgDirPath, targetImages, targetPaths);
ImageUtils.LoadPngImagesFromFolder(panelCache.TargetImgDirPath, targetImages, targetPaths,
(imagePath) => {
var imageName = Path.GetFileName(imagePath);
if (m_BackgroundFileAllName == imageName) return true;
if (slicePaths.Contains(imageName)) return true;
return false;
});
}
private void OnUpdateBackgroundShow(bool show)
@ -574,6 +655,48 @@ namespace UguiToolkit.Editor
m_entityRoot.gameObject.SetActive(false);
}
class SelectionObjCache
{
Transform m_transform;
List<RectTransform> childrens = new ();
List<Vector3> originalPositions = new();
public Transform Transform => m_transform;
public void SetData(Transform tf)
{
ClearData();
m_transform = tf;
for (int i = 0; i < tf.childCount; i++)
{
var rt = tf.GetChild(i) as RectTransform;
childrens.Add(rt);
originalPositions.Add(rt.position);
}
}
public void ClearData()
{
childrens.Clear();
originalPositions.Clear();
originalPositions.Clear();
m_transform = null;
}
public void RecoverData()
{
// 恢复子节点的全局位置和大小
for (int i = 0; i < childrens.Count; i++)
{
Undo.RecordObject(childrens[i], "RecoverData");
childrens[i].position = originalPositions[i];
}
}
}
}
}
#endif

View File

@ -34,6 +34,11 @@ namespace UguiToolkit.Editor.Windows
/// </summary>
public event Action<Transform> effectLastApplyTransform;
/// <summary>
/// 应用上次变换
/// </summary>
public event Action recoverDataSelectionObjCache;
[SerializeField, HideInInspector]
private bool m_showHierarchyOfEntityChange = false;
@ -80,7 +85,7 @@ namespace UguiToolkit.Editor.Windows
[LabelText("需要应用变换的对象"), SerializeField]
private Transform m_targetTransform;
[Button("应用上次变换 (SPACE)")]
[Button("应用上次变换 (SPACE)")]
private void EffectLastApplyTransform()
{
if (m_targetTransform)
@ -89,6 +94,12 @@ namespace UguiToolkit.Editor.Windows
}
}
[Button("恢复子节点位置 (CTRL + SPACE)")]
private void RecoverDataSelectionObjCache()
{
recoverDataSelectionObjCache?.Invoke();
}
public override string GettitleContent()
{
return "助手编辑界面";

View File

@ -1,32 +1,34 @@
# C1 Ugui拼接助手
## 简介
> 该工具主要作用是优化工作流,提高重复劳动的工作效率,以下是当前版本已经实现的功能:
> 1. psd 导出自动切图,并处理九宫格
> 该工具主要作用是提高效果图还原度和提高拼接效率,以下是当前版本已经实现的功能:
> 1. psd 端自动切图,并处理九宫格
> 2. unity拼接时对psd上所标记的像素图层进行吸附设置位置和旋转、缩放
> 3. unity拼接时对psd上所标记的文本图层进行吸附设置位置和旋转、缩放并设置字体、字体大小、字体颜色、描边等
> 4. unity拼接时对公共组件预制体进行设置位置和旋转、缩放
## 展示
![GIF 2024-12-17 10-59-36](F:\c1workspace\svn\__workspace__dev__\client\PackagesSource\com.txcombo.c1.ugui-toolkit\.res\展示.gif)
## 工作流
![](./.res/流程图.png)
## 如何操作
### psd数据导出
#### 对图层名使用关键字标记
1. `$<图层名>` : 图片切图导出 例如:$img_tools
2. `%<图层名>` : 图片吸附用 例如:%img_tools
3. `%<文本图层名>` : 文本吸附用 例如:%text_tools
4. `<图层名>@九宫格` : 九宫格切图 例如:$img_tools@九宫格
4. `<图层名>@透明度=100` : 透明度属性 例如:$img_tools@透明度=50
1. `$<图层名>` : 图片切图导出并吸附 例如:$img_tools ,参数:九宫格:`<图层名>@九宫格`
2. `%<图层名>` : 仅图片吸附用 例如:%img_tools参数九宫格`<图层名>@九宫格`
3. `%<文本图层名>` : 仅文本吸附用 例如:%text_tools
5. `<图层名>@预制体=<资源唯一名称>` 引用通用组件预制体 例如:领取龙币@预制体=btn_common_yellow_large
#### 导出数据
> psd文件名不支持中文
运行指定脚本进行导出
![](./.res/ps导出入口.png)
选中项目中脚本
`client\PackagesSource\com.txcombo.c1.ugui-toolkit\.PhotoshopScript\JSZXPsd2Unity\PSD导出Unity.js`
`client\toolchains\c1_ugui_toolkit\.PhotoshopScript\JSZXPsd2Unity\PSD导出Unity.js`
执行完毕后会自动弹出目录
![](./.res/弹出目录.png)
@ -39,13 +41,25 @@
![img](F:\c1workspace\svn\__workspace__dev__\client\PackagesSource\com.txcombo.c1.ugui-toolkit\.res\开启助手.png)
#### 如何吸附
#### 选中image和text、预制体后自动吸附
##### 图片
![](./.res/吸附展示.gif)
##### 文本
##### 一键创建所有文本
![](./.res/创建text.png)
![](./.res/创建text后的结果.png)
##### 预制体
1. 选中预制体节点后,会显示界面所有可供创建的预制体预览
2. 将鼠标光标放入预制体预览框,会自动创建预制体
##### 一键创建所有预制体
![img](F:\c1workspace\svn\__workspace__dev__\client\PackagesSource\com.txcombo.c1.ugui-toolkit\.res\创建预制体.png)
#### 进阶操作
##### 父节点应用子节点变换
吸附完成后,选中父节点按下“空格”
![GIF 2024-12-12 10-19-28](F:\c1workspace\svn\__workspace__dev__\client\PackagesSource\com.txcombo.c1.ugui-toolkit\.res\父节点应用子节点变换.gif)
##### 修改父节点边框后复原子节点位置
对父节点边框进行调整后按下“Ctrl + 空格”
![GIF 2024-12-12 10-25-00](F:\c1workspace\svn\__workspace__dev__\client\PackagesSource\com.txcombo.c1.ugui-toolkit\.res\复原子节点位置.gif)