feat(tools): 添加UI工具脚本及部署文档
新增内容: 1. 创建 06_工具脚本/UI工具/ 目录,包含4个核心工具脚本 - ExternalCommandListener.cs - 外部命令监听器 - RemoteCommand.cs - 远程命令接口 - UIPrefabGenerator.cs - JSON转预制体生成器 - UIPrefabToJson.cs - 预制体转JSON导出器 2. 更新 UI界面拼接设计指南.md - 新增8.9节工具脚本部署说明 - 包含手动部署和自动部署两种方式 - 添加部署规则和验证步骤 3. 更新 README.md - 添加06_工具脚本章节索引 部署方法: - 手动复制:复制工具脚本到项目 Assets/Editor/Command/ 目录 - 自动部署:使用 DeployUITools.bat 脚本
This commit is contained in:
379
06_工具脚本/UI工具/UIPrefabToJson.cs
Normal file
379
06_工具脚本/UI工具/UIPrefabToJson.cs
Normal file
@@ -0,0 +1,379 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEditor;
|
||||
using TMPro;
|
||||
|
||||
public static class UIPrefabToJson
|
||||
{
|
||||
[MenuItem("Tools/UI/Export Prefab to JSON")]
|
||||
public static void ExportPrefabToJsonMenu()
|
||||
{
|
||||
string prefabPath = EditorUtility.OpenFilePanel("选择预制体", "Assets", "prefab");
|
||||
if (!string.IsNullOrEmpty(prefabPath))
|
||||
{
|
||||
string projectPath = Application.dataPath.Replace("/Assets", "");
|
||||
string relativePath = prefabPath.Replace(projectPath + "/", "");
|
||||
string jsonPath = relativePath.Replace(".prefab", ".json");
|
||||
ExportPrefabToJson(relativePath, jsonPath);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExportPrefabToJson(string prefabPath, string jsonPath = null)
|
||||
{
|
||||
if (!AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath))
|
||||
{
|
||||
Debug.LogError("Prefab not found: " + prefabPath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(jsonPath))
|
||||
{
|
||||
jsonPath = prefabPath.Replace(".prefab", ".json");
|
||||
}
|
||||
|
||||
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
||||
UILayoutData layoutData = ConvertPrefabToLayoutData(prefab);
|
||||
|
||||
string jsonContent = JsonUtility.ToJson(layoutData, true);
|
||||
string fullPath = Path.Combine(Application.dataPath, "..", jsonPath);
|
||||
string directory = Path.GetDirectoryName(fullPath);
|
||||
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
File.WriteAllText(fullPath, jsonContent);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
Debug.Log("JSON exported successfully: " + jsonPath);
|
||||
}
|
||||
|
||||
private static UILayoutData ConvertPrefabToLayoutData(GameObject prefab)
|
||||
{
|
||||
UILayoutData data = new UILayoutData();
|
||||
data.name = prefab.name;
|
||||
data.type = "Canvas";
|
||||
data.layer = prefab.layer;
|
||||
|
||||
Canvas canvas = prefab.GetComponent<Canvas>();
|
||||
if (canvas != null)
|
||||
{
|
||||
data.canvas = new CanvasData();
|
||||
data.canvas.renderMode = canvas.renderMode.ToString();
|
||||
data.canvas.pixelPerfect = canvas.pixelPerfect;
|
||||
}
|
||||
|
||||
RectTransform rectTransform = prefab.GetComponent<RectTransform>();
|
||||
if (rectTransform != null)
|
||||
{
|
||||
data.rectTransform = ConvertRectTransform(rectTransform);
|
||||
}
|
||||
|
||||
data.children = new List<UIElementData>();
|
||||
foreach (Transform child in prefab.transform)
|
||||
{
|
||||
UIElementData childData = ConvertTransformToElement(child);
|
||||
if (childData != null)
|
||||
{
|
||||
data.children.Add(childData);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static UIElementData ConvertTransformToElement(Transform transform)
|
||||
{
|
||||
UIElementData data = new UIElementData();
|
||||
data.name = transform.name;
|
||||
|
||||
RectTransform rectTransform = transform.GetComponent<RectTransform>();
|
||||
if (rectTransform != null)
|
||||
{
|
||||
data.rectTransform = ConvertRectTransform(rectTransform);
|
||||
}
|
||||
|
||||
Component[] components = transform.GetComponents<Component>();
|
||||
List<string> componentTypes = new List<string>();
|
||||
|
||||
foreach (Component comp in components)
|
||||
{
|
||||
if (comp == null) continue;
|
||||
|
||||
string compTypeName = comp.GetType().Name;
|
||||
componentTypes.Add(compTypeName);
|
||||
|
||||
switch (compTypeName)
|
||||
{
|
||||
case "Image":
|
||||
case "SFUI_Image":
|
||||
data.type = compTypeName;
|
||||
data.image = ConvertImage((Image)comp);
|
||||
break;
|
||||
case "Button":
|
||||
case "SFUI_Button":
|
||||
data.type = compTypeName;
|
||||
data.button = ConvertButton((Button)comp);
|
||||
break;
|
||||
case "TextMeshProUGUI":
|
||||
case "SFUI_TextMeshProUGUI":
|
||||
data.type = compTypeName;
|
||||
data.text = ConvertText((TextMeshProUGUI)comp);
|
||||
break;
|
||||
case "ScrollRect":
|
||||
case "SFUI_ScrollRect":
|
||||
data.type = compTypeName;
|
||||
data.scrollRect = ConvertScrollRect((ScrollRect)comp);
|
||||
break;
|
||||
case "GridLayoutGroup":
|
||||
data.type = compTypeName;
|
||||
data.layoutGroup = ConvertGridLayoutGroup((GridLayoutGroup)comp);
|
||||
break;
|
||||
case "VerticalLayoutGroup":
|
||||
data.type = compTypeName;
|
||||
data.layoutGroup = ConvertVerticalLayoutGroup((VerticalLayoutGroup)comp);
|
||||
break;
|
||||
case "HorizontalLayoutGroup":
|
||||
data.type = compTypeName;
|
||||
data.layoutGroup = ConvertHorizontalLayoutGroup((HorizontalLayoutGroup)comp);
|
||||
break;
|
||||
case "Toggle":
|
||||
case "SFUI_Toggle":
|
||||
data.type = compTypeName;
|
||||
data.toggle = ConvertToggle((Toggle)comp);
|
||||
break;
|
||||
case "Slider":
|
||||
case "SFUI_Slider":
|
||||
data.type = compTypeName;
|
||||
data.slider = ConvertSlider((Slider)comp);
|
||||
break;
|
||||
case "InputField":
|
||||
case "SFUI_InputField":
|
||||
data.type = compTypeName;
|
||||
data.inputField = ConvertInputField((InputField)comp);
|
||||
break;
|
||||
case "RectTransform":
|
||||
if (string.IsNullOrEmpty(data.type))
|
||||
data.type = compTypeName;
|
||||
break;
|
||||
case "Canvas":
|
||||
if (string.IsNullOrEmpty(data.type))
|
||||
data.type = compTypeName;
|
||||
break;
|
||||
case "CanvasScaler":
|
||||
data.type = compTypeName;
|
||||
break;
|
||||
case "GraphicRaycaster":
|
||||
data.type = compTypeName;
|
||||
break;
|
||||
default:
|
||||
if (compTypeName != "Transform" && compTypeName != "RectTransform")
|
||||
{
|
||||
if (data.customComponents == null)
|
||||
data.customComponents = new List<CustomComponentData>();
|
||||
data.customComponents.Add(ConvertCustomComponent(comp));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(data.type))
|
||||
{
|
||||
data.type = "Transform";
|
||||
}
|
||||
|
||||
if (transform.childCount > 0)
|
||||
{
|
||||
data.children = new List<UIElementData>();
|
||||
foreach (Transform child in transform)
|
||||
{
|
||||
UIElementData childData = ConvertTransformToElement(child);
|
||||
if (childData != null)
|
||||
{
|
||||
data.children.Add(childData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static RectTransformData ConvertRectTransform(RectTransform rect)
|
||||
{
|
||||
RectTransformData data = new RectTransformData();
|
||||
data.anchorMin = new float[] { rect.anchorMin.x, rect.anchorMin.y };
|
||||
data.anchorMax = new float[] { rect.anchorMax.x, rect.anchorMax.y };
|
||||
data.position = new float[] { rect.anchoredPosition3D.x, rect.anchoredPosition3D.y, rect.anchoredPosition3D.z };
|
||||
data.sizeDelta = new float[] { rect.sizeDelta.x, rect.sizeDelta.y };
|
||||
data.pivot = new float[] { rect.pivot.x, rect.pivot.y };
|
||||
data.localScale = new float[] { rect.localScale.x, rect.localScale.y, rect.localScale.z };
|
||||
data.localRotation = new float[] { rect.localEulerAngles.x, rect.localEulerAngles.y, rect.localEulerAngles.z };
|
||||
return data;
|
||||
}
|
||||
|
||||
private static ImageData ConvertImage(Image image)
|
||||
{
|
||||
ImageData data = new ImageData();
|
||||
data.type = image.type.ToString();
|
||||
data.color = new float[] { image.color.r, image.color.g, image.color.b, image.color.a };
|
||||
data.raycastTarget = image.raycastTarget;
|
||||
data.preserveAspect = image.preserveAspect;
|
||||
|
||||
if (image.sprite != null)
|
||||
{
|
||||
string spritePath = AssetDatabase.GetAssetPath(image.sprite);
|
||||
if (!string.IsNullOrEmpty(spritePath))
|
||||
{
|
||||
data.sprite = spritePath;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static ButtonData ConvertButton(Button button)
|
||||
{
|
||||
ButtonData data = new ButtonData();
|
||||
data.interactable = button.interactable;
|
||||
data.transition = button.transition.ToString();
|
||||
data.navigationMode = button.navigation.mode.ToString();
|
||||
return data;
|
||||
}
|
||||
|
||||
private static TextData ConvertText(TextMeshProUGUI text)
|
||||
{
|
||||
TextData data = new TextData();
|
||||
data.text = text.text;
|
||||
data.fontSize = text.fontSize;
|
||||
data.color = new float[] { text.color.r, text.color.g, text.color.b, text.color.a };
|
||||
data.alignment = text.alignment.ToString();
|
||||
data.verticalAlignment = text.verticalAlignment.ToString();
|
||||
data.richText = text.richText;
|
||||
data.overflowMode = text.overflowMode.ToString();
|
||||
data.enableWordWrapping = text.enableWordWrapping;
|
||||
|
||||
if (text.font != null)
|
||||
{
|
||||
string fontPath = AssetDatabase.GetAssetPath(text.font);
|
||||
if (!string.IsNullOrEmpty(fontPath))
|
||||
{
|
||||
data.font = fontPath;
|
||||
}
|
||||
}
|
||||
|
||||
if (text.material != null)
|
||||
{
|
||||
string materialPath = AssetDatabase.GetAssetPath(text.material);
|
||||
if (!string.IsNullOrEmpty(materialPath))
|
||||
{
|
||||
data.materialPreset = materialPath;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static ScrollRectData ConvertScrollRect(ScrollRect scrollRect)
|
||||
{
|
||||
ScrollRectData data = new ScrollRectData();
|
||||
data.horizontal = scrollRect.horizontal;
|
||||
data.vertical = scrollRect.vertical;
|
||||
data.movementType = scrollRect.movementType.ToString();
|
||||
data.horizontalScrollbarVisibility = scrollRect.horizontalScrollbarVisibility.ToString();
|
||||
data.verticalScrollbarVisibility = scrollRect.verticalScrollbarVisibility.ToString();
|
||||
return data;
|
||||
}
|
||||
|
||||
private static LayoutGroupData ConvertGridLayoutGroup(GridLayoutGroup layout)
|
||||
{
|
||||
LayoutGroupData data = new LayoutGroupData();
|
||||
data.type = "GridLayoutGroup";
|
||||
data.cellSize = new float[] { layout.cellSize.x, layout.cellSize.y };
|
||||
data.spacing = new float[] { layout.spacing.x, layout.spacing.y };
|
||||
data.constraint = (int)layout.constraint;
|
||||
data.childAlignment = layout.childAlignment.ToString();
|
||||
data.padding = new int[] { layout.padding.left, layout.padding.right, layout.padding.top, layout.padding.bottom };
|
||||
return data;
|
||||
}
|
||||
|
||||
private static LayoutGroupData ConvertVerticalLayoutGroup(VerticalLayoutGroup layout)
|
||||
{
|
||||
LayoutGroupData data = new LayoutGroupData();
|
||||
data.type = "VerticalLayoutGroup";
|
||||
data.spacing = new float[] { layout.spacing, layout.spacing };
|
||||
data.childAlignment = layout.childAlignment.ToString();
|
||||
data.padding = new int[] { layout.padding.left, layout.padding.right, layout.padding.top, layout.padding.bottom };
|
||||
return data;
|
||||
}
|
||||
|
||||
private static LayoutGroupData ConvertHorizontalLayoutGroup(HorizontalLayoutGroup layout)
|
||||
{
|
||||
LayoutGroupData data = new LayoutGroupData();
|
||||
data.type = "HorizontalLayoutGroup";
|
||||
data.spacing = new float[] { layout.spacing, layout.spacing };
|
||||
data.childAlignment = layout.childAlignment.ToString();
|
||||
data.padding = new int[] { layout.padding.left, layout.padding.right, layout.padding.top, layout.padding.bottom };
|
||||
return data;
|
||||
}
|
||||
|
||||
private static ToggleData ConvertToggle(Toggle toggle)
|
||||
{
|
||||
ToggleData data = new ToggleData();
|
||||
data.isOn = toggle.isOn;
|
||||
data.toggleTransition = toggle.toggleTransition.ToString();
|
||||
data.transition = toggle.transition.ToString();
|
||||
return data;
|
||||
}
|
||||
|
||||
private static SliderData ConvertSlider(Slider slider)
|
||||
{
|
||||
SliderData data = new SliderData();
|
||||
data.minValue = slider.minValue;
|
||||
data.maxValue = slider.maxValue;
|
||||
data.value = slider.value;
|
||||
data.wholeNumbers = slider.wholeNumbers;
|
||||
data.direction = slider.direction.ToString();
|
||||
return data;
|
||||
}
|
||||
|
||||
private static InputFieldData ConvertInputField(InputField inputField)
|
||||
{
|
||||
InputFieldData data = new InputFieldData();
|
||||
data.text = inputField.text;
|
||||
|
||||
if (inputField.placeholder != null)
|
||||
{
|
||||
Text textPlaceholder = inputField.placeholder as Text;
|
||||
if (textPlaceholder != null)
|
||||
{
|
||||
data.placeholder = textPlaceholder.text;
|
||||
}
|
||||
else
|
||||
{
|
||||
TextMeshProUGUI tmpPlaceholder = inputField.placeholder as TextMeshProUGUI;
|
||||
if (tmpPlaceholder != null)
|
||||
{
|
||||
data.placeholder = tmpPlaceholder.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data.characterLimit = inputField.characterLimit;
|
||||
data.contentType = inputField.contentType.ToString();
|
||||
data.inputType = inputField.inputType.ToString();
|
||||
return data;
|
||||
}
|
||||
|
||||
private static CustomComponentData ConvertCustomComponent(Component comp)
|
||||
{
|
||||
CustomComponentData data = new CustomComponentData();
|
||||
data.typeName = comp.GetType().Name;
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user