【AI编码】【UI信息】增加UI信息提取器
parent
80c7d490f9
commit
c46093301d
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f36e65c488d04421a7e348157f4511d2
|
||||
timeCreated: 1770186775
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c7b013a71e0f4c54fb23197d54448dd8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
using UIInfoBuilder.Data;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UIInfoBuilder.ComponentExtractors
|
||||
{
|
||||
/// <summary>
|
||||
/// Button 精细提取器
|
||||
/// </summary>
|
||||
public class ButtonExtractor : IComponentExtractor
|
||||
{
|
||||
public bool CanExtract(Component component)
|
||||
{
|
||||
return component is Button;
|
||||
}
|
||||
|
||||
public void Extract(Component component, UIInfoComponent info)
|
||||
{
|
||||
var button = (Button)component;
|
||||
|
||||
// Interactable
|
||||
info.properties.Add($"Interactable:{button.interactable.ToString().ToLower()}");
|
||||
|
||||
// Transition
|
||||
info.properties.Add($"Transition:{button.transition}");
|
||||
|
||||
// Target Graphic
|
||||
string targetGraphicName = button.targetGraphic != null ? button.targetGraphic.name : "";
|
||||
info.properties.Add($"TargetGraphic:{targetGraphicName}");
|
||||
|
||||
// 根据 Transition 类型提取不同属性
|
||||
switch (button.transition)
|
||||
{
|
||||
case Selectable.Transition.ColorTint:
|
||||
_ExtractColorBlock(button.colors, info);
|
||||
break;
|
||||
|
||||
case Selectable.Transition.SpriteSwap:
|
||||
_ExtractSpriteState(button.spriteState, info);
|
||||
break;
|
||||
|
||||
case Selectable.Transition.Animation:
|
||||
_ExtractAnimationTriggers(button.animationTriggers, info);
|
||||
break;
|
||||
}
|
||||
|
||||
// Navigation
|
||||
info.properties.Add($"NavigationMode:{button.navigation.mode}");
|
||||
}
|
||||
|
||||
private void _ExtractColorBlock(ColorBlock colors, UIInfoComponent info)
|
||||
{
|
||||
info.properties.Add($"NormalColor:{_ColorToHex(colors.normalColor)}");
|
||||
info.properties.Add($"HighlightedColor:{_ColorToHex(colors.highlightedColor)}");
|
||||
info.properties.Add($"PressedColor:{_ColorToHex(colors.pressedColor)}");
|
||||
info.properties.Add($"SelectedColor:{_ColorToHex(colors.selectedColor)}");
|
||||
info.properties.Add($"DisabledColor:{_ColorToHex(colors.disabledColor)}");
|
||||
info.properties.Add($"ColorMultiplier:{colors.colorMultiplier}");
|
||||
info.properties.Add($"FadeDuration:{colors.fadeDuration}");
|
||||
}
|
||||
|
||||
private void _ExtractSpriteState(SpriteState spriteState, UIInfoComponent info)
|
||||
{
|
||||
string highlightedSprite = spriteState.highlightedSprite != null ? spriteState.highlightedSprite.name : "";
|
||||
string pressedSprite = spriteState.pressedSprite != null ? spriteState.pressedSprite.name : "";
|
||||
string selectedSprite = spriteState.selectedSprite != null ? spriteState.selectedSprite.name : "";
|
||||
string disabledSprite = spriteState.disabledSprite != null ? spriteState.disabledSprite.name : "";
|
||||
|
||||
info.properties.Add($"HighlightedSprite:{highlightedSprite}");
|
||||
info.properties.Add($"PressedSprite:{pressedSprite}");
|
||||
info.properties.Add($"SelectedSprite:{selectedSprite}");
|
||||
info.properties.Add($"DisabledSprite:{disabledSprite}");
|
||||
}
|
||||
|
||||
private void _ExtractAnimationTriggers(AnimationTriggers triggers, UIInfoComponent info)
|
||||
{
|
||||
info.properties.Add($"NormalTrigger:{triggers.normalTrigger}");
|
||||
info.properties.Add($"HighlightedTrigger:{triggers.highlightedTrigger}");
|
||||
info.properties.Add($"PressedTrigger:{triggers.pressedTrigger}");
|
||||
info.properties.Add($"SelectedTrigger:{triggers.selectedTrigger}");
|
||||
info.properties.Add($"DisabledTrigger:{triggers.disabledTrigger}");
|
||||
}
|
||||
|
||||
private string _ColorToHex(Color color)
|
||||
{
|
||||
int r = Mathf.RoundToInt(color.r * 255);
|
||||
int g = Mathf.RoundToInt(color.g * 255);
|
||||
int b = Mathf.RoundToInt(color.b * 255);
|
||||
int a = Mathf.RoundToInt(color.a * 255);
|
||||
return $"#{r:X2}{g:X2}{b:X2}{a:X2}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 336c9f3eded04b24fb4b51dfaf7b8b81
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
using UIInfoBuilder.Data;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UIInfoBuilder.ComponentExtractors
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认组件提取器,通过反射读取 SerializedProperty
|
||||
/// </summary>
|
||||
public class DefaultComponentExtractor : IComponentExtractor
|
||||
{
|
||||
public bool CanExtract(Component component)
|
||||
{
|
||||
return true; // 作为兜底,处理所有组件
|
||||
}
|
||||
|
||||
public void Extract(Component component, UIInfoComponent info)
|
||||
{
|
||||
var serializedObject = new SerializedObject(component);
|
||||
var iterator = serializedObject.GetIterator();
|
||||
|
||||
// 进入第一个属性
|
||||
if (iterator.NextVisible(true))
|
||||
{
|
||||
do
|
||||
{
|
||||
// 跳过 m_Script 属性
|
||||
if (iterator.name == "m_Script")
|
||||
continue;
|
||||
|
||||
var propertyString = _FormatProperty(iterator);
|
||||
if (!string.IsNullOrEmpty(propertyString))
|
||||
{
|
||||
info.properties.Add(propertyString);
|
||||
}
|
||||
} while (iterator.NextVisible(false));
|
||||
}
|
||||
}
|
||||
|
||||
private string _FormatProperty(SerializedProperty property)
|
||||
{
|
||||
string name = property.displayName;
|
||||
string value = _GetPropertyValue(property);
|
||||
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
return $"{name}:{value}";
|
||||
}
|
||||
|
||||
private string _GetPropertyValue(SerializedProperty property)
|
||||
{
|
||||
switch (property.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.Integer:
|
||||
return property.intValue.ToString();
|
||||
|
||||
case SerializedPropertyType.Boolean:
|
||||
return property.boolValue.ToString().ToLower();
|
||||
|
||||
case SerializedPropertyType.Float:
|
||||
return property.floatValue.ToString("G");
|
||||
|
||||
case SerializedPropertyType.String:
|
||||
return property.stringValue;
|
||||
|
||||
case SerializedPropertyType.Color:
|
||||
return _ColorToHex(property.colorValue);
|
||||
|
||||
case SerializedPropertyType.ObjectReference:
|
||||
if (property.objectReferenceValue != null)
|
||||
return property.objectReferenceValue.name;
|
||||
return "";
|
||||
|
||||
case SerializedPropertyType.Enum:
|
||||
return property.enumNames[property.enumValueIndex];
|
||||
|
||||
case SerializedPropertyType.Vector2:
|
||||
var v2 = property.vector2Value;
|
||||
return $"{v2.x},{v2.y}";
|
||||
|
||||
case SerializedPropertyType.Vector3:
|
||||
var v3 = property.vector3Value;
|
||||
return $"{v3.x},{v3.y},{v3.z}";
|
||||
|
||||
case SerializedPropertyType.Vector4:
|
||||
var v4 = property.vector4Value;
|
||||
return $"{v4.x},{v4.y},{v4.z},{v4.w}";
|
||||
|
||||
case SerializedPropertyType.Rect:
|
||||
var rect = property.rectValue;
|
||||
return $"{rect.x},{rect.y},{rect.width},{rect.height}";
|
||||
|
||||
case SerializedPropertyType.Bounds:
|
||||
var bounds = property.boundsValue;
|
||||
return $"center:{bounds.center.x},{bounds.center.y},{bounds.center.z};size:{bounds.size.x},{bounds.size.y},{bounds.size.z}";
|
||||
|
||||
case SerializedPropertyType.Quaternion:
|
||||
var euler = property.quaternionValue.eulerAngles;
|
||||
return $"{euler.x},{euler.y},{euler.z}";
|
||||
|
||||
case SerializedPropertyType.Vector2Int:
|
||||
var v2i = property.vector2IntValue;
|
||||
return $"{v2i.x},{v2i.y}";
|
||||
|
||||
case SerializedPropertyType.Vector3Int:
|
||||
var v3i = property.vector3IntValue;
|
||||
return $"{v3i.x},{v3i.y},{v3i.z}";
|
||||
|
||||
case SerializedPropertyType.RectInt:
|
||||
var rectInt = property.rectIntValue;
|
||||
return $"{rectInt.x},{rectInt.y},{rectInt.width},{rectInt.height}";
|
||||
|
||||
case SerializedPropertyType.BoundsInt:
|
||||
var boundsInt = property.boundsIntValue;
|
||||
return $"position:{boundsInt.position.x},{boundsInt.position.y},{boundsInt.position.z};size:{boundsInt.size.x},{boundsInt.size.y},{boundsInt.size.z}";
|
||||
|
||||
case SerializedPropertyType.LayerMask:
|
||||
return property.intValue.ToString();
|
||||
|
||||
case SerializedPropertyType.ArraySize:
|
||||
case SerializedPropertyType.Generic:
|
||||
case SerializedPropertyType.AnimationCurve:
|
||||
case SerializedPropertyType.Gradient:
|
||||
case SerializedPropertyType.ExposedReference:
|
||||
case SerializedPropertyType.FixedBufferSize:
|
||||
case SerializedPropertyType.ManagedReference:
|
||||
default:
|
||||
// 复杂类型跳过
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private string _ColorToHex(Color color)
|
||||
{
|
||||
int r = Mathf.RoundToInt(color.r * 255);
|
||||
int g = Mathf.RoundToInt(color.g * 255);
|
||||
int b = Mathf.RoundToInt(color.b * 255);
|
||||
int a = Mathf.RoundToInt(color.a * 255);
|
||||
return $"#{r:X2}{g:X2}{b:X2}{a:X2}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c14494d2d4d893249988c4111fbeb8de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
using UIInfoBuilder.Data;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UIInfoBuilder.ComponentExtractors
|
||||
{
|
||||
public interface IComponentExtractor
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断是否可以处理该组件
|
||||
/// </summary>
|
||||
bool CanExtract(Component component);
|
||||
|
||||
/// <summary>
|
||||
/// 提取组件属性到 UIInfoComponent
|
||||
/// </summary>
|
||||
void Extract(Component component, UIInfoComponent info);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c8b92a2dfbee7f54dad85e6a3c1fa287
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
using UIInfoBuilder.Data;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UIInfoBuilder.ComponentExtractors
|
||||
{
|
||||
/// <summary>
|
||||
/// Image 精细提取器
|
||||
/// </summary>
|
||||
public class ImageExtractor : IComponentExtractor
|
||||
{
|
||||
public bool CanExtract(Component component)
|
||||
{
|
||||
return component is Image;
|
||||
}
|
||||
|
||||
public void Extract(Component component, UIInfoComponent info)
|
||||
{
|
||||
var image = (Image)component;
|
||||
|
||||
// Sprite
|
||||
string spriteName = image.sprite != null ? image.sprite.name : "";
|
||||
info.properties.Add($"Sprite:{spriteName}");
|
||||
|
||||
// Color
|
||||
info.properties.Add($"Color:{_ColorToHex(image.color)}");
|
||||
|
||||
// Material
|
||||
string materialName = image.material != null ? image.material.name : "";
|
||||
info.properties.Add($"Material:{materialName}");
|
||||
|
||||
// Raycast Target
|
||||
info.properties.Add($"RaycastTarget:{image.raycastTarget.ToString().ToLower()}");
|
||||
|
||||
// Raycast Padding
|
||||
var padding = image.raycastPadding;
|
||||
info.properties.Add($"RaycastPadding:{padding.x},{padding.y},{padding.z},{padding.w}");
|
||||
|
||||
// Maskable
|
||||
info.properties.Add($"Maskable:{image.maskable.ToString().ToLower()}");
|
||||
|
||||
// Image Type
|
||||
info.properties.Add($"ImageType:{image.type}");
|
||||
|
||||
// Fill相关属性
|
||||
if (image.type == Image.Type.Filled)
|
||||
{
|
||||
info.properties.Add($"FillMethod:{image.fillMethod}");
|
||||
info.properties.Add($"FillOrigin:{image.fillOrigin}");
|
||||
info.properties.Add($"FillAmount:{image.fillAmount}");
|
||||
info.properties.Add($"FillClockwise:{image.fillClockwise.ToString().ToLower()}");
|
||||
}
|
||||
|
||||
// Preserve Aspect
|
||||
info.properties.Add($"PreserveAspect:{image.preserveAspect.ToString().ToLower()}");
|
||||
|
||||
// Use Sprite Mesh
|
||||
info.properties.Add($"UseSpriteMesh:{image.useSpriteMesh.ToString().ToLower()}");
|
||||
|
||||
// Pixels Per Unit Multiplier
|
||||
info.properties.Add($"PixelsPerUnitMultiplier:{image.pixelsPerUnitMultiplier}");
|
||||
}
|
||||
|
||||
private string _ColorToHex(Color color)
|
||||
{
|
||||
int r = Mathf.RoundToInt(color.r * 255);
|
||||
int g = Mathf.RoundToInt(color.g * 255);
|
||||
int b = Mathf.RoundToInt(color.b * 255);
|
||||
int a = Mathf.RoundToInt(color.a * 255);
|
||||
return $"#{r:X2}{g:X2}{b:X2}{a:X2}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 615b792b55aa1a14195508d00b4e54d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using UIInfoBuilder.Data;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UIInfoBuilder.ComponentExtractors
|
||||
{
|
||||
/// <summary>
|
||||
/// RectTransform 精细提取器
|
||||
/// </summary>
|
||||
public class RectTransformExtractor : IComponentExtractor
|
||||
{
|
||||
public bool CanExtract(Component component)
|
||||
{
|
||||
return component is RectTransform;
|
||||
}
|
||||
|
||||
public void Extract(Component component, UIInfoComponent info)
|
||||
{
|
||||
var rt = (RectTransform)component;
|
||||
|
||||
// Anchors
|
||||
info.properties.Add($"AnchorMin:{rt.anchorMin.x},{rt.anchorMin.y}");
|
||||
info.properties.Add($"AnchorMax:{rt.anchorMax.x},{rt.anchorMax.y}");
|
||||
|
||||
// Pivot
|
||||
info.properties.Add($"Pivot:{rt.pivot.x},{rt.pivot.y}");
|
||||
|
||||
// AnchoredPosition
|
||||
info.properties.Add($"AnchoredPosition:{rt.anchoredPosition.x},{rt.anchoredPosition.y}");
|
||||
info.properties.Add($"AnchoredPosition3D:{rt.anchoredPosition3D.x},{rt.anchoredPosition3D.y},{rt.anchoredPosition3D.z}");
|
||||
|
||||
// SizeDelta
|
||||
info.properties.Add($"SizeDelta:{rt.sizeDelta.x},{rt.sizeDelta.y}");
|
||||
|
||||
// LocalPosition
|
||||
info.properties.Add($"LocalPosition:{rt.localPosition.x},{rt.localPosition.y},{rt.localPosition.z}");
|
||||
|
||||
// LocalRotation (欧拉角)
|
||||
var euler = rt.localRotation.eulerAngles;
|
||||
info.properties.Add($"LocalRotation:{euler.x},{euler.y},{euler.z}");
|
||||
|
||||
// LocalScale
|
||||
info.properties.Add($"LocalScale:{rt.localScale.x},{rt.localScale.y},{rt.localScale.z}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dbe97f03e1fcc5b4892cb91dc13af5ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
using UIInfoBuilder.Data;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace UIInfoBuilder.ComponentExtractors
|
||||
{
|
||||
/// <summary>
|
||||
/// Text 和 TextMeshProUGUI 精细提取器
|
||||
/// </summary>
|
||||
public class TextExtractor : IComponentExtractor
|
||||
{
|
||||
public bool CanExtract(Component component)
|
||||
{
|
||||
return component is Text || component is TMP_Text;
|
||||
}
|
||||
|
||||
public void Extract(Component component, UIInfoComponent info)
|
||||
{
|
||||
if (component is Text text)
|
||||
{
|
||||
_ExtractText(text, info);
|
||||
}
|
||||
else if (component is TMP_Text tmpText)
|
||||
{
|
||||
_ExtractTMPText(tmpText, info);
|
||||
}
|
||||
}
|
||||
|
||||
private void _ExtractText(Text text, UIInfoComponent info)
|
||||
{
|
||||
// Text
|
||||
info.properties.Add($"Text:{text.text}");
|
||||
|
||||
// Font
|
||||
string fontName = text.font != null ? text.font.name : "";
|
||||
info.properties.Add($"Font:{fontName}");
|
||||
|
||||
// Font Style
|
||||
info.properties.Add($"FontStyle:{text.fontStyle}");
|
||||
|
||||
// Font Size
|
||||
info.properties.Add($"FontSize:{text.fontSize}");
|
||||
|
||||
// Line Spacing
|
||||
info.properties.Add($"LineSpacing:{text.lineSpacing}");
|
||||
|
||||
// Rich Text
|
||||
info.properties.Add($"RichText:{text.supportRichText.ToString().ToLower()}");
|
||||
|
||||
// Alignment
|
||||
info.properties.Add($"Alignment:{text.alignment}");
|
||||
|
||||
// Align By Geometry
|
||||
info.properties.Add($"AlignByGeometry:{text.alignByGeometry.ToString().ToLower()}");
|
||||
|
||||
// Horizontal Overflow
|
||||
info.properties.Add($"HorizontalOverflow:{text.horizontalOverflow}");
|
||||
|
||||
// Vertical Overflow
|
||||
info.properties.Add($"VerticalOverflow:{text.verticalOverflow}");
|
||||
|
||||
// Best Fit
|
||||
info.properties.Add($"BestFit:{text.resizeTextForBestFit.ToString().ToLower()}");
|
||||
|
||||
// Color
|
||||
info.properties.Add($"Color:{_ColorToHex(text.color)}");
|
||||
|
||||
// Material
|
||||
string materialName = text.material != null ? text.material.name : "";
|
||||
info.properties.Add($"Material:{materialName}");
|
||||
|
||||
// Raycast Target
|
||||
info.properties.Add($"RaycastTarget:{text.raycastTarget.ToString().ToLower()}");
|
||||
|
||||
// Maskable
|
||||
info.properties.Add($"Maskable:{text.maskable.ToString().ToLower()}");
|
||||
}
|
||||
|
||||
private void _ExtractTMPText(TMP_Text tmpText, UIInfoComponent info)
|
||||
{
|
||||
// Text
|
||||
info.properties.Add($"Text:{tmpText.text}");
|
||||
|
||||
// Font Asset
|
||||
string fontName = tmpText.font != null ? tmpText.font.name : "";
|
||||
info.properties.Add($"FontAsset:{fontName}");
|
||||
|
||||
// Material Preset
|
||||
string materialName = tmpText.fontSharedMaterial != null ? tmpText.fontSharedMaterial.name : "";
|
||||
info.properties.Add($"MaterialPreset:{materialName}");
|
||||
|
||||
// Font Style
|
||||
info.properties.Add($"FontStyle:{tmpText.fontStyle}");
|
||||
|
||||
// Font Size
|
||||
info.properties.Add($"FontSize:{tmpText.fontSize}");
|
||||
|
||||
// Auto Size
|
||||
info.properties.Add($"AutoSize:{tmpText.enableAutoSizing.ToString().ToLower()}");
|
||||
|
||||
// Vertex Color
|
||||
info.properties.Add($"Color:{_ColorToHex(tmpText.color)}");
|
||||
|
||||
// Color Gradient
|
||||
info.properties.Add($"EnableVertexGradient:{tmpText.enableVertexGradient.ToString().ToLower()}");
|
||||
|
||||
// Spacing - Character
|
||||
info.properties.Add($"CharacterSpacing:{tmpText.characterSpacing}");
|
||||
|
||||
// Spacing - Word
|
||||
info.properties.Add($"WordSpacing:{tmpText.wordSpacing}");
|
||||
|
||||
// Spacing - Line
|
||||
info.properties.Add($"LineSpacing:{tmpText.lineSpacing}");
|
||||
|
||||
// Spacing - Paragraph
|
||||
info.properties.Add($"ParagraphSpacing:{tmpText.paragraphSpacing}");
|
||||
|
||||
// Alignment
|
||||
info.properties.Add($"Alignment:{tmpText.alignment}");
|
||||
|
||||
// Wrapping
|
||||
info.properties.Add($"EnableWordWrapping:{tmpText.enableWordWrapping.ToString().ToLower()}");
|
||||
|
||||
// Overflow
|
||||
info.properties.Add($"OverflowMode:{tmpText.overflowMode}");
|
||||
|
||||
// Raycast Target
|
||||
info.properties.Add($"RaycastTarget:{tmpText.raycastTarget.ToString().ToLower()}");
|
||||
|
||||
// Maskable
|
||||
info.properties.Add($"Maskable:{tmpText.maskable.ToString().ToLower()}");
|
||||
}
|
||||
|
||||
private string _ColorToHex(Color color)
|
||||
{
|
||||
int r = Mathf.RoundToInt(color.r * 255);
|
||||
int g = Mathf.RoundToInt(color.g * 255);
|
||||
int b = Mathf.RoundToInt(color.b * 255);
|
||||
int a = Mathf.RoundToInt(color.a * 255);
|
||||
return $"#{r:X2}{g:X2}{b:X2}{a:X2}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ee690f93e76c6e04abe3904b6db19a8f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ca3089d0044b40ecaad89583bfcdbf43
|
||||
timeCreated: 1770186781
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
namespace UIInfoBuilder.Data
|
||||
{
|
||||
public class UIInfoComponent
|
||||
{
|
||||
public string componentName;
|
||||
public bool enable;
|
||||
public List<string> properties = new List<string>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e1a05d01923d414ab0733f15a2e9b267
|
||||
timeCreated: 1770186861
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
namespace UIInfoBuilder.Data
|
||||
{
|
||||
public class UIInfoNode
|
||||
{
|
||||
public string name;
|
||||
public bool active;
|
||||
public List<UIInfoComponent> components = new List<UIInfoComponent>();
|
||||
public List<UIInfoNode> children = new List<UIInfoNode>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 45573fea4d42434cbe8a1cbc92b14ece
|
||||
timeCreated: 1770186795
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UIInfoBuilder.ComponentExtractors;
|
||||
using UIInfoBuilder.Data;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UIInfoBuilder
|
||||
{
|
||||
public class UIInfoExtractor
|
||||
{
|
||||
private static readonly List<IComponentExtractor> _extractors = new List<IComponentExtractor>();
|
||||
private static readonly DefaultComponentExtractor _defaultExtractor = new DefaultComponentExtractor();
|
||||
|
||||
static UIInfoExtractor()
|
||||
{
|
||||
// 注册特殊组件提取器(优先级高的放前面)
|
||||
_extractors.Add(new RectTransformExtractor());
|
||||
_extractors.Add(new ImageExtractor());
|
||||
_extractors.Add(new TextExtractor());
|
||||
_extractors.Add(new ButtonExtractor());
|
||||
}
|
||||
|
||||
[MenuItem("Assets/UIInfoBuilder/ExtractPrefab")]
|
||||
private static void _AssetHandle()
|
||||
{
|
||||
var selectedObjects = Selection.gameObjects;
|
||||
foreach (var obj in selectedObjects)
|
||||
{
|
||||
string savePath = Application.dataPath + "/../ExtractedPrefabs/" + obj.name + ".json";
|
||||
ExtractPrefab(obj, savePath);
|
||||
Debug.Log($"[UIInfoBuilder] Extracted: {obj.name} -> {savePath}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提取 Prefab 信息并保存为 JSON
|
||||
/// </summary>
|
||||
public static void ExtractPrefab(GameObject prefab, string savePath)
|
||||
{
|
||||
var rootNode = _ExtractNode(prefab);
|
||||
_SaveToJson(rootNode, savePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 递归提取节点信息
|
||||
/// </summary>
|
||||
private static UIInfoNode _ExtractNode(GameObject go)
|
||||
{
|
||||
var node = new UIInfoNode
|
||||
{
|
||||
name = go.name,
|
||||
active = go.activeSelf
|
||||
};
|
||||
|
||||
// 提取所有组件
|
||||
var components = go.GetComponents<Component>();
|
||||
foreach (var component in components)
|
||||
{
|
||||
if (component == null)
|
||||
continue;
|
||||
|
||||
var compInfo = _ExtractComponent(component);
|
||||
node.components.Add(compInfo);
|
||||
}
|
||||
|
||||
// 递归提取子节点
|
||||
for (int i = 0; i < go.transform.childCount; i++)
|
||||
{
|
||||
var child = go.transform.GetChild(i).gameObject;
|
||||
var childNode = _ExtractNode(child);
|
||||
node.children.Add(childNode);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提取单个组件信息
|
||||
/// </summary>
|
||||
private static UIInfoComponent _ExtractComponent(Component component)
|
||||
{
|
||||
var info = new UIInfoComponent
|
||||
{
|
||||
componentName = component.GetType().Name,
|
||||
enable = _GetComponentEnabled(component)
|
||||
};
|
||||
|
||||
// 查找匹配的特殊提取器
|
||||
IComponentExtractor extractor = null;
|
||||
foreach (var ext in _extractors)
|
||||
{
|
||||
if (ext.CanExtract(component))
|
||||
{
|
||||
extractor = ext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用特殊提取器或默认提取器
|
||||
if (extractor != null)
|
||||
{
|
||||
extractor.Extract(component, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
_defaultExtractor.Extract(component, info);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取组件的启用状态
|
||||
/// </summary>
|
||||
private static bool _GetComponentEnabled(Component component)
|
||||
{
|
||||
// Behaviour 类型的组件有 enabled 属性
|
||||
if (component is Behaviour behaviour)
|
||||
{
|
||||
return behaviour.enabled;
|
||||
}
|
||||
|
||||
// Renderer 类型的组件有 enabled 属性
|
||||
if (component is Renderer renderer)
|
||||
{
|
||||
return renderer.enabled;
|
||||
}
|
||||
|
||||
// Collider 类型的组件有 enabled 属性
|
||||
if (component is Collider collider)
|
||||
{
|
||||
return collider.enabled;
|
||||
}
|
||||
|
||||
// 其他组件默认返回 true
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存为 JSON 文件
|
||||
/// </summary>
|
||||
private static void _SaveToJson(UIInfoNode node, string savePath)
|
||||
{
|
||||
// 确保目录存在
|
||||
string directory = Path.GetDirectoryName(savePath);
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
// 使用自定义递归序列化(JsonUtility 不支持嵌套 List 递归)
|
||||
var sb = new StringBuilder();
|
||||
_SerializeNode(node, sb, 0);
|
||||
File.WriteAllText(savePath, sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 递归序列化节点为 JSON
|
||||
/// </summary>
|
||||
private static void _SerializeNode(UIInfoNode node, StringBuilder sb, int indent)
|
||||
{
|
||||
string indentStr = new string(' ', indent * 2);
|
||||
string indentStr1 = new string(' ', (indent + 1) * 2);
|
||||
string indentStr2 = new string(' ', (indent + 2) * 2);
|
||||
string indentStr3 = new string(' ', (indent + 3) * 2);
|
||||
|
||||
sb.AppendLine($"{indentStr}{{");
|
||||
sb.AppendLine($"{indentStr1}\"name\": \"{_EscapeJsonString(node.name)}\",");
|
||||
sb.AppendLine($"{indentStr1}\"active\": {node.active.ToString().ToLower()},");
|
||||
|
||||
// Components
|
||||
sb.AppendLine($"{indentStr1}\"components\": [");
|
||||
for (int i = 0; i < node.components.Count; i++)
|
||||
{
|
||||
var comp = node.components[i];
|
||||
sb.AppendLine($"{indentStr2}{{");
|
||||
sb.AppendLine($"{indentStr3}\"componentName\": \"{_EscapeJsonString(comp.componentName)}\",");
|
||||
sb.AppendLine($"{indentStr3}\"enable\": {comp.enable.ToString().ToLower()},");
|
||||
sb.Append($"{indentStr3}\"properties\": [");
|
||||
|
||||
if (comp.properties.Count > 0)
|
||||
{
|
||||
sb.AppendLine();
|
||||
for (int j = 0; j < comp.properties.Count; j++)
|
||||
{
|
||||
string comma = j < comp.properties.Count - 1 ? "," : "";
|
||||
sb.AppendLine($"{indentStr3} \"{_EscapeJsonString(comp.properties[j])}\"{comma}");
|
||||
}
|
||||
sb.AppendLine($"{indentStr3}]");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine("]");
|
||||
}
|
||||
|
||||
string compComma = i < node.components.Count - 1 ? "," : "";
|
||||
sb.AppendLine($"{indentStr2}}}{compComma}");
|
||||
}
|
||||
sb.AppendLine($"{indentStr1}],");
|
||||
|
||||
// Children
|
||||
sb.AppendLine($"{indentStr1}\"children\": [");
|
||||
for (int i = 0; i < node.children.Count; i++)
|
||||
{
|
||||
_SerializeNode(node.children[i], sb, indent + 2);
|
||||
if (i < node.children.Count - 1)
|
||||
{
|
||||
// 在上一个 } 后面加逗号
|
||||
sb.Length -= Environment.NewLine.Length; // 移除换行
|
||||
sb.AppendLine(",");
|
||||
}
|
||||
}
|
||||
sb.AppendLine($"{indentStr1}]");
|
||||
|
||||
sb.AppendLine($"{indentStr}}}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转义 JSON 字符串中的特殊字符
|
||||
/// </summary>
|
||||
private static string _EscapeJsonString(string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return str;
|
||||
|
||||
return str
|
||||
.Replace("\\", "\\\\")
|
||||
.Replace("\"", "\\\"")
|
||||
.Replace("\n", "\\n")
|
||||
.Replace("\r", "\\r")
|
||||
.Replace("\t", "\\t");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bdc0f7ce965c45b3a83334b4b6a116f8
|
||||
timeCreated: 1770186962
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue