优化查询效率,完善文档
@ -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;
|
||||
|
@ -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
|
||||
|
BIN
.res/创建text.png
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 529 KiB After Width: | Height: | Size: 274 KiB |
BIN
.res/创建预制体.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
.res/吸附展示.gif
Before Width: | Height: | Size: 337 KiB After Width: | Height: | Size: 667 KiB |
BIN
.res/复原子节点位置.gif
Normal file
After Width: | Height: | Size: 1005 KiB |
BIN
.res/展示.gif
Normal file
After Width: | Height: | Size: 656 KiB |
BIN
.res/开启助手.png
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 14 KiB |
BIN
.res/父节点应用子节点变换.gif
Normal file
After Width: | Height: | Size: 413 KiB |
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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,12 +49,27 @@ 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
var label = new GUIContent(" <-----");
|
||||
|
||||
if (go == m_lastApplyDataGo)
|
||||
{
|
||||
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
|
@ -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;
|
||||
@ -89,6 +94,12 @@ namespace UguiToolkit.Editor.Windows
|
||||
}
|
||||
}
|
||||
|
||||
[Button("恢复子节点位置 (CTRL + SPACE)")]
|
||||
private void RecoverDataSelectionObjCache()
|
||||
{
|
||||
recoverDataSelectionObjCache?.Invoke();
|
||||
}
|
||||
|
||||
public override string GettitleContent()
|
||||
{
|
||||
return "助手编辑界面";
|
||||
|
46
README.md
@ -1,32 +1,34 @@
|
||||
# C1 Ugui拼接助手
|
||||
|
||||
## 简介
|
||||
> 该工具主要作用是优化工作流,提高重复劳动的工作效率,以下是当前版本已经实现的功能:
|
||||
> 1. psd 导出自动切图,并处理九宫格
|
||||
|
||||
> 该工具主要作用是提高效果图还原度和提高拼接效率,以下是当前版本已经实现的功能:
|
||||
> 1. psd 端自动切图,并处理九宫格
|
||||
> 2. unity拼接时,对psd上所标记的像素图层进行吸附,设置位置和旋转、缩放
|
||||
> 3. unity拼接时,对psd上所标记的文本图层进行吸附,设置位置和旋转、缩放,并设置字体、字体大小、字体颜色、描边等
|
||||
> 4. unity拼接时,对公共组件预制体进行设置位置和旋转、缩放
|
||||
|
||||
## 展示
|
||||
|
||||

|
||||
|
||||
## 工作流
|
||||
|
||||

|
||||
## 如何操作
|
||||
### 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文件名不支持中文
|
||||
|
||||
运行指定脚本进行导出
|
||||

|
||||
|
||||
选中项目中脚本
|
||||
`client\PackagesSource\com.txcombo.c1.ugui-toolkit\.PhotoshopScript\JSZXPsd2Unity\PSD导出Unity.js`
|
||||
`client\toolchains\c1_ugui_toolkit\.PhotoshopScript\JSZXPsd2Unity\PSD导出Unity.js`
|
||||
执行完毕后会自动弹出目录
|
||||

|
||||
|
||||
@ -39,13 +41,25 @@
|
||||
|
||||

|
||||
|
||||
#### 如何吸附
|
||||
#### 选中image和text、预制体后,自动吸附
|
||||
##### 图片
|
||||
|
||||

|
||||
##### 文本
|
||||
##### 一键创建所有文本
|
||||

|
||||

|
||||
##### 预制体
|
||||
1. 选中预制体节点后,会显示界面所有可供创建的预制体预览
|
||||
2. 将鼠标光标放入预制体预览框,会自动创建预制体
|
||||
|
||||
##### 一键创建所有预制体
|
||||

|
||||
|
||||
#### 进阶操作
|
||||
##### 父节点应用子节点变换
|
||||
|
||||
吸附完成后,选中父节点按下“空格”
|
||||
|
||||

|
||||
|
||||
##### 修改父节点边框后复原子节点位置
|
||||
|
||||
对父节点边框进行调整后,按下“Ctrl + 空格”
|
||||
|
||||

|
||||
|