[docs][refactor]: 将旧 01~06 中文教程合并整理为 modules/frameworks 文件夹结构

- 删除 01~05 旧中文教程目录
- 将 03 核心功能教程拆分为各 framework 模块的子文档
- 06 工具脚本移入 modules/frameworks/编辑器工具/UI工具/
- 非框架内容合并进 rules/20-开发规则.md 与 rules/40-工作流清单.md
- 更新所有交叉链接与文档关联表

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
lms
2026-07-07 18:36:15 +08:00
parent 5e5b9f8c80
commit ee1ff7f444
77 changed files with 6263 additions and 1133 deletions

View File

@@ -0,0 +1,584 @@
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
using TMPro;
public static class UIPrefabGenerator
{
public static void GeneratePrefabFromJson(string jsonPath, string prefabPath = null)
{
if (!File.Exists(jsonPath))
{
Debug.LogError("JSON file not found: " + jsonPath);
return;
}
string jsonContent = File.ReadAllText(jsonPath);
UILayoutData layoutData = JsonUtility.FromJson<UILayoutData>(jsonContent);
if (layoutData == null)
{
Debug.LogError("Failed to parse JSON file: " + jsonPath);
return;
}
if (string.IsNullOrEmpty(prefabPath))
{
prefabPath = "Assets/Game/GameHFResource/CN/UIWindows/" + layoutData.name + "/" + layoutData.name + ".prefab";
}
GameObject root = new GameObject(layoutData.name);
root.layer = layoutData.layer;
Canvas canvas = root.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
if (layoutData.canvas != null)
{
canvas.pixelPerfect = layoutData.canvas.pixelPerfect;
}
root.AddComponent<CanvasScaler>();
root.AddComponent<GraphicRaycaster>();
RectTransform rootRect = root.GetComponent<RectTransform>();
SetRectTransform(rootRect, layoutData.rectTransform);
foreach (var childData in layoutData.children)
{
CreateUIElement(childData, root.transform);
}
CreatePrefab(root, prefabPath);
GameObject.DestroyImmediate(root);
AssetDatabase.Refresh();
Debug.Log("UI Prefab generated successfully: " + prefabPath);
}
private static void CreateUIElement(UIElementData data, Transform parent)
{
GameObject obj = new GameObject(data.name);
obj.transform.SetParent(parent, false);
RectTransform rect = obj.AddComponent<RectTransform>();
SetRectTransform(rect, data.rectTransform);
switch (data.type)
{
case "Image":
case "SFUI_Image":
CreateImage(obj, data.image);
break;
case "Button":
case "SFUI_Button":
CreateButton(obj, data.button, data.image);
break;
case "TextMeshProUGUI":
case "SFUI_TextMeshProUGUI":
CreateTextMeshPro(obj, data.text);
break;
case "RectTransform":
case "SFUI_Viewport":
case "SFUI_Content":
CreateRectTransform(obj, data.layoutGroup);
break;
case "ScrollRect":
case "SFUI_ScrollRect":
CreateScrollRect(obj, data.scrollRect);
break;
case "GridLayoutGroup":
CreateGridLayoutGroup(obj, data.layoutGroup);
break;
case "VerticalLayoutGroup":
CreateVerticalLayoutGroup(obj, data.layoutGroup);
break;
case "HorizontalLayoutGroup":
CreateHorizontalLayoutGroup(obj, data.layoutGroup);
break;
case "Toggle":
case "SFUI_Toggle":
CreateToggle(obj, data.toggle);
break;
case "Slider":
case "SFUI_Slider":
CreateSlider(obj, data.slider);
break;
case "InputField":
case "SFUI_InputField":
CreateInputField(obj, data.inputField);
break;
case "CanvasScaler":
case "GraphicRaycaster":
break;
case "SFUI_ListViewItem":
CreateListViewItemPlaceholder(obj);
break;
case "Canvas":
case "SFUI_Window":
break;
default:
break;
}
if (data.children != null)
{
foreach (var childData in data.children)
{
CreateUIElement(childData, obj.transform);
}
}
}
private static void SetRectTransform(RectTransform rect, RectTransformData data)
{
if (data == null) return;
rect.anchorMin = new Vector2(data.anchorMin[0], data.anchorMin[1]);
rect.anchorMax = new Vector2(data.anchorMax[0], data.anchorMax[1]);
rect.anchoredPosition3D = new Vector3(data.position[0], data.position[1], data.position[2]);
rect.sizeDelta = new Vector2(data.sizeDelta[0], data.sizeDelta[1]);
rect.pivot = new Vector2(data.pivot[0], data.pivot[1]);
if (data.localScale != null && data.localScale.Length >= 3)
{
rect.localScale = new Vector3(data.localScale[0], data.localScale[1], data.localScale[2]);
}
if (data.localRotation != null && data.localRotation.Length >= 3)
{
rect.localEulerAngles = new Vector3(data.localRotation[0], data.localRotation[1], data.localRotation[2]);
}
}
private static void CreateImage(GameObject obj, ImageData data)
{
if (data == null) return;
Image image = obj.AddComponent<Image>();
if (!string.IsNullOrEmpty(data.sprite))
{
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(data.sprite);
if (sprite != null)
{
image.sprite = sprite;
}
}
try
{
image.type = (Image.Type)Enum.Parse(typeof(Image.Type), data.type);
}
catch
{
image.type = Image.Type.Simple;
}
image.color = new Color(data.color[0], data.color[1], data.color[2], data.color[3]);
image.raycastTarget = data.raycastTarget;
image.preserveAspect = data.preserveAspect;
}
private static void CreateButton(GameObject obj, ButtonData buttonData, ImageData imageData)
{
Button button = obj.AddComponent<Button>();
if (buttonData != null)
{
button.interactable = buttonData.interactable;
try
{
button.transition = (Selectable.Transition)Enum.Parse(typeof(Selectable.Transition), buttonData.transition);
}
catch
{
button.transition = Selectable.Transition.ColorTint;
}
}
if (imageData != null)
{
CreateImage(obj, imageData);
}
}
private static void CreateTextMeshPro(GameObject obj, TextData data)
{
if (data == null) return;
TextMeshProUGUI text = obj.AddComponent<TextMeshProUGUI>();
text.text = data.text;
text.fontSize = data.fontSize;
text.color = new Color(data.color[0], data.color[1], data.color[2], data.color[3]);
if (!string.IsNullOrEmpty(data.font))
{
TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(data.font);
if (fontAsset != null)
{
text.font = fontAsset;
}
}
if (!string.IsNullOrEmpty(data.materialPreset))
{
Material material = AssetDatabase.LoadAssetAtPath<Material>(data.materialPreset);
if (material != null)
{
text.material = material;
}
}
try
{
text.alignment = (TextAlignmentOptions)Enum.Parse(typeof(TextAlignmentOptions), data.alignment);
}
catch
{
text.alignment = TextAlignmentOptions.Center;
}
try
{
text.verticalAlignment = (VerticalAlignmentOptions)Enum.Parse(typeof(VerticalAlignmentOptions), data.verticalAlignment);
}
catch
{
text.verticalAlignment = VerticalAlignmentOptions.Middle;
}
text.richText = data.richText;
try
{
text.overflowMode = (TextOverflowModes)Enum.Parse(typeof(TextOverflowModes), data.overflowMode);
}
catch
{
text.overflowMode = TextOverflowModes.Truncate;
}
text.enableWordWrapping = data.enableWordWrapping;
}
private static void CreateRectTransform(GameObject obj, LayoutGroupData layoutData)
{
if (layoutData != null)
{
switch (layoutData.type)
{
case "GridLayoutGroup":
CreateGridLayoutGroup(obj, layoutData);
break;
case "VerticalLayoutGroup":
CreateVerticalLayoutGroup(obj, layoutData);
break;
case "HorizontalLayoutGroup":
CreateHorizontalLayoutGroup(obj, layoutData);
break;
}
}
}
private static void CreateGridLayoutGroup(GameObject obj, LayoutGroupData layoutData)
{
if (layoutData == null) return;
GridLayoutGroup grid = obj.AddComponent<GridLayoutGroup>();
grid.cellSize = new Vector2(layoutData.cellSize[0], layoutData.cellSize[1]);
grid.spacing = new Vector2(layoutData.spacing[0], layoutData.spacing[1]);
grid.constraint = (GridLayoutGroup.Constraint)layoutData.constraint;
try
{
grid.childAlignment = (TextAnchor)Enum.Parse(typeof(TextAnchor), layoutData.childAlignment);
}
catch
{
grid.childAlignment = TextAnchor.UpperLeft;
}
grid.padding = new RectOffset(layoutData.padding[0], layoutData.padding[1], layoutData.padding[2], layoutData.padding[3]);
}
private static void CreateVerticalLayoutGroup(GameObject obj, LayoutGroupData layoutData)
{
if (layoutData == null) return;
VerticalLayoutGroup vertical = obj.AddComponent<VerticalLayoutGroup>();
vertical.spacing = layoutData.spacing[1];
try
{
vertical.childAlignment = (TextAnchor)Enum.Parse(typeof(TextAnchor), layoutData.childAlignment);
}
catch
{
vertical.childAlignment = TextAnchor.UpperLeft;
}
vertical.padding = new RectOffset(layoutData.padding[0], layoutData.padding[1], layoutData.padding[2], layoutData.padding[3]);
}
private static void CreateHorizontalLayoutGroup(GameObject obj, LayoutGroupData layoutData)
{
if (layoutData == null) return;
HorizontalLayoutGroup horizontal = obj.AddComponent<HorizontalLayoutGroup>();
horizontal.spacing = layoutData.spacing[0];
try
{
horizontal.childAlignment = (TextAnchor)Enum.Parse(typeof(TextAnchor), layoutData.childAlignment);
}
catch
{
horizontal.childAlignment = TextAnchor.UpperLeft;
}
horizontal.padding = new RectOffset(layoutData.padding[0], layoutData.padding[1], layoutData.padding[2], layoutData.padding[3]);
}
private static void CreateScrollRect(GameObject obj, ScrollRectData data)
{
if (data == null) return;
ScrollRect scrollRect = obj.AddComponent<ScrollRect>();
scrollRect.horizontal = data.horizontal;
scrollRect.vertical = data.vertical;
try
{
scrollRect.movementType = (ScrollRect.MovementType)Enum.Parse(typeof(ScrollRect.MovementType), data.movementType);
}
catch
{
scrollRect.movementType = ScrollRect.MovementType.Clamped;
}
}
private static void CreateToggle(GameObject obj, ToggleData data)
{
if (data == null) return;
Toggle toggle = obj.AddComponent<Toggle>();
toggle.isOn = data.isOn;
try
{
toggle.toggleTransition = (Toggle.ToggleTransition)Enum.Parse(typeof(Toggle.ToggleTransition), data.toggleTransition);
}
catch
{
toggle.toggleTransition = Toggle.ToggleTransition.Fade;
}
try
{
toggle.transition = (Selectable.Transition)Enum.Parse(typeof(Selectable.Transition), data.transition);
}
catch
{
toggle.transition = Selectable.Transition.ColorTint;
}
}
private static void CreateSlider(GameObject obj, SliderData data)
{
if (data == null) return;
Slider slider = obj.AddComponent<Slider>();
slider.minValue = data.minValue;
slider.maxValue = data.maxValue;
slider.value = data.value;
slider.wholeNumbers = data.wholeNumbers;
try
{
slider.direction = (Slider.Direction)Enum.Parse(typeof(Slider.Direction), data.direction);
}
catch
{
slider.direction = Slider.Direction.LeftToRight;
}
}
private static void CreateInputField(GameObject obj, InputFieldData data)
{
if (data == null) return;
InputField inputField = obj.AddComponent<InputField>();
inputField.text = data.text;
inputField.characterLimit = data.characterLimit;
try
{
inputField.contentType = (InputField.ContentType)Enum.Parse(typeof(InputField.ContentType), data.contentType);
}
catch
{
inputField.contentType = InputField.ContentType.Standard;
}
try
{
inputField.inputType = (InputField.InputType)Enum.Parse(typeof(InputField.InputType), data.inputType);
}
catch
{
inputField.inputType = InputField.InputType.Standard;
}
}
private static void CreateListViewItemPlaceholder(GameObject obj)
{
}
private static void CreatePrefab(GameObject root, string path)
{
string directory = Path.GetDirectoryName(path);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
PrefabUtility.SaveAsPrefabAsset(root, path);
}
}
[Serializable]
public class UILayoutData
{
public string name;
public string type;
public int layer;
public RectTransformData rectTransform;
public CanvasData canvas;
public List<UIElementData> children;
}
[Serializable]
public class UIElementData
{
public string name;
public string type;
public RectTransformData rectTransform;
public ImageData image;
public ButtonData button;
public TextData text;
public LayoutGroupData layoutGroup;
public ScrollRectData scrollRect;
public ToggleData toggle;
public SliderData slider;
public InputFieldData inputField;
public List<CustomComponentData> customComponents;
public List<UIElementData> children;
}
[Serializable]
public class RectTransformData
{
public float[] anchorMin;
public float[] anchorMax;
public float[] position;
public float[] sizeDelta;
public float[] pivot;
public float[] localScale;
public float[] localRotation;
}
[Serializable]
public class CanvasData
{
public string renderMode;
public bool pixelPerfect;
}
[Serializable]
public class ImageData
{
public string sprite;
public string type;
public float[] color;
public bool raycastTarget;
public bool preserveAspect;
}
[Serializable]
public class ButtonData
{
public bool interactable;
public string transition;
public string navigationMode;
}
[Serializable]
public class TextData
{
public string text;
public float fontSize;
public string font;
public string materialPreset;
public string alignment;
public string verticalAlignment;
public float[] color;
public bool richText;
public string overflowMode;
public bool enableWordWrapping;
}
[Serializable]
public class LayoutGroupData
{
public string type;
public float[] cellSize;
public float[] spacing;
public int constraint;
public string childAlignment;
public int[] padding;
}
[Serializable]
public class ScrollRectData
{
public bool horizontal;
public bool vertical;
public string movementType;
public string horizontalScrollbarVisibility;
public string verticalScrollbarVisibility;
}
[Serializable]
public class ToggleData
{
public bool isOn;
public string toggleTransition;
public string transition;
}
[Serializable]
public class SliderData
{
public float minValue;
public float maxValue;
public float value;
public bool wholeNumbers;
public string direction;
}
[Serializable]
public class InputFieldData
{
public string text;
public string placeholder;
public int characterLimit;
public string contentType;
public string inputType;
}
[Serializable]
public class CustomComponentData
{
public string typeName;
}