三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

别再手动拖了!用脚本一键将Unity场景Hierarchy结构生成UI折叠菜单(支持无限级)

别再手动拖了!用脚本一键将Unity场景Hierarchy结构生成UI折叠菜单(支持无限级)

Unity场景层级一键转UGUI折叠菜单的工程化实践

在游戏开发中,我们经常需要将复杂的场景层级结构(如任务系统、技能树或配置菜单)可视化为可交互的UI菜单。传统的手动拖拽方式不仅效率低下,更难以维护层级结构的同步更新。本文将分享一套完整的解决方案,通过脚本自动将Unity场景的Hierarchy结构转化为UGUI折叠菜单,支持无限级嵌套和动态更新。

1. 核心架构设计

1.1 组件选型与布局方案

实现折叠菜单需要精心选择UGUI组件组合:

  • ScrollRect:作为容器处理滚动视图
  • VerticalLayoutGroup:自动管理子项垂直排列
  • ContentSizeFitter:动态调整内容区域大小

关键配置参数:

// ScrollView初始化示例 scrollRect.vertical = true; scrollRect.horizontal = false; contentSizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; verticalLayoutGroup.childControlHeight = false;

1.2 数据结构设计

采用树形结构存储层级关系:

public class MenuNode { public string name; public int level; public List<MenuNode> children; public RectTransform uiInstance; public bool isExpanded; }

1.3 预设体制作规范

创建通用菜单项预设体需包含:

  • 文本标签(显示名称)
  • 折叠/展开图标按钮
  • 子项容器(带ContentSizeFitter)
  • 背景交互区域

提示:使用Anchor Presets确保不同层级菜单的缩进对齐

2. 自动化生成实现

2.1 场景层级解析算法

利用Transform.GetComponentsInChildren的遍历特性:

Transform[] allTransforms = root.GetComponentsInChildren<Transform>(true); Dictionary<Transform, int> levelMap = new Dictionary<Transform, int>(); foreach (Transform t in allTransforms) { int level = CalculateLevel(t); levelMap[t] = level; // 创建对应层级的UI项 }

层级计算采用递归方式:

int CalculateLevel(Transform t) { return t.parent == null ? 0 : 1 + CalculateLevel(t.parent); }

2.2 动态UI生成策略

采用对象池技术优化性能:

Stack<GameObject> menuItemPool = new Stack<GameObject>(); GameObject GetMenuItem() { return menuItemPool.Count > 0 ? menuItemPool.Pop() : Instantiate(menuItemPrefab); }

2.3 无限级嵌套处理

关键实现逻辑:

  1. 每个菜单项维护子项列表和展开状态
  2. 展开时递归计算总高度
  3. 使用协程处理大规模数据的渐进式加载
IEnumerator GenerateMenuCoroutine(MenuNode node) { var uiItem = CreateUIItem(node); yield return null; if (node.isExpanded) { foreach (var child in node.children) { StartCoroutine(GenerateMenuCoroutine(child)); yield return new WaitForEndOfFrame(); } } }

3. 交互功能实现

3.1 折叠/展开动画优化

平滑过渡方案:

IEnumerator ToggleExpand(MenuNode node, bool expand) { float duration = 0.2f; float elapsed = 0f; Vector2 startSize = node.uiInstance.sizeDelta; Vector2 targetSize = expand ? CalculateExpandedSize(node) : collapsedSize; while (elapsed < duration) { node.uiInstance.sizeDelta = Vector2.Lerp(startSize, targetSize, elapsed/duration); elapsed += Time.deltaTime; yield return null; } node.uiInstance.sizeDelta = targetSize; node.isExpanded = expand; }

3.2 性能优化技巧

针对大规模层级的优化策略:

  • 虚拟滚动(只渲染可见区域)
  • 异步加载子项
  • 合并布局计算
void OptimizeLargeHierarchy() { Canvas.ForceUpdateCanvases(); LayoutRebuilder.ForceRebuildLayoutImmediate(contentRect); ScrollRect.StopMovement(); }

4. 工程化扩展功能

4.1 编辑器工具集成

创建自定义编辑器窗口:

[MenuItem("Tools/Generate Menu from Hierarchy")] static void GenerateMenu() { var window = CreateInstance<MenuGeneratorWindow>(); window.Show(); } class MenuGeneratorWindow : EditorWindow { // 实现UI和生成逻辑 }

4.2 样式定制系统

支持通过ScriptableObject配置视觉样式:

[CreateAssetMenu] public class MenuStyle : ScriptableObject { public Color[] levelColors; public Sprite[] foldIcons; public Font font; // 其他样式属性 }

4.3 动态更新机制

实现场景与UI的实时同步:

void OnTransformChildrenChanged() { if (autoSync) { RegenerateMenu(); } }

5. 实战问题解决方案

5.1 常见问题排查表

问题现象可能原因解决方案
菜单项错位LayoutGroup刷新延迟强制布局重建
滚动跳动ContentSizeFitter计算不及时添加一帧延迟
性能卡顿一次性生成过多项实现分批加载

5.2 高级调试技巧

使用Editor GUI绘制调试信息:

void OnDrawGizmosSelected() { GUIStyle style = new GUIStyle(); style.normal.textColor = Color.white; Handles.Label(transform.position, $"Level:{level}\nChildCount:{children.Count}", style); }

5.3 移动端适配要点

针对触摸设备的优化:

  • 增大点击区域
  • 添加触觉反馈
  • 优化滚动惯性参数
scrollRect.decelerationRate = 0.135f; // iOS风格滚动 scrollRect.scrollSensitivity = 12f;

这套方案已在多个商业项目中验证,特别适合配置复杂的RPG游戏和工具开发。实际使用中发现,对于超过500个节点的层级结构,建议结合虚拟滚动技术以获得流畅体验。

← 返回列表