2025-11-08 14:03:17 +08:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.EventSystems;
|
|
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
|
|
|
|
|
|
namespace SceneView
|
|
|
|
|
|
{
|
|
|
|
|
|
public class SceneViewPanel : MonoBehaviour, IDragHandler, IBeginDragHandler
|
|
|
|
|
|
{
|
|
|
|
|
|
public const float titleHeight = 50;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
public ScrollRect? scrollRect;
|
|
|
|
|
|
|
|
|
|
|
|
public string currentAimObj;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
private Vector2 shift;
|
|
|
|
|
|
|
|
|
|
|
|
private TreeViewNode? treeViewNode;
|
|
|
|
|
|
|
|
|
|
|
|
private void Start()
|
|
|
|
|
|
{
|
|
|
|
|
|
currentAimObj = CanvasControl.ShowAim;
|
|
|
|
|
|
CreateUI();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
public void OnBeginDrag(PointerEventData eventData)
|
|
|
|
|
|
{
|
|
|
|
|
|
shift = transform.position - new Vector3(eventData.position.x, eventData.position.y);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
|
|
|
|
{
|
|
|
|
|
|
transform.position = eventData.position + shift;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-08 14:03:17 +08:00
|
|
|
|
private void CreateUI()
|
|
|
|
|
|
{
|
|
|
|
|
|
CreateTitleBar();
|
|
|
|
|
|
var scrollConfig = ScrollViewConfig.Default;
|
|
|
|
|
|
scrollConfig.Horizontal = true;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
scrollConfig.RectConfig.SizeDelta = CanvasControl.panelSize - new Vector2(0, titleHeight);
|
2025-11-08 14:03:17 +08:00
|
|
|
|
var scrollRectArr = ControlUtilities.CreateScrollView(transform, scrollConfig);
|
|
|
|
|
|
scrollRect = scrollRectArr.scrollRect;
|
|
|
|
|
|
if (scrollRect == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to create ScrollView.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var scrollRectRectTransform = scrollRect.GetComponent<RectTransform>();
|
|
|
|
|
|
if (scrollRectRectTransform == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to get RectTransform for ScrollView.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
scrollRectRectTransform.anchorMin = new Vector2(0, 0);
|
|
|
|
|
|
scrollRectRectTransform.anchorMax = new Vector2(1, 1);
|
|
|
|
|
|
scrollRectRectTransform.offsetMin = Vector2.zero;
|
|
|
|
|
|
scrollRectRectTransform.offsetMax = new Vector2(0, -titleHeight);
|
|
|
|
|
|
|
|
|
|
|
|
var content = scrollRect.content.gameObject;
|
|
|
|
|
|
if (content == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to get content for ScrollView.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// var contentRectTransform = content.GetComponent<RectTransform>();
|
|
|
|
|
|
// contentRectTransform.anchorMin = Vector2.up;
|
|
|
|
|
|
// contentRectTransform.anchorMax = Vector2.one;
|
|
|
|
|
|
// contentRectTransform.sizeDelta = Vector2.zero;
|
|
|
|
|
|
// contentRectTransform.offsetMin = Vector2.zero;
|
|
|
|
|
|
// contentRectTransform.offsetMax = new Vector2(0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
// var root = new GameObject("root");
|
|
|
|
|
|
// root.AddComponent<RectTransform>();
|
|
|
|
|
|
// root.transform.SetParent(content.transform, false);
|
|
|
|
|
|
|
|
|
|
|
|
treeViewNode = content.AddComponent<TreeViewNode>();
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// treeViewNode.UpdateHeight();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
// var vLayout = content.AddComponent<VerticalLayoutGroup>();
|
|
|
|
|
|
// vLayout.padding = new RectOffset(2, 2, 2, 2);
|
|
|
|
|
|
// vLayout.spacing = 5;
|
|
|
|
|
|
// vLayout.childControlWidth = true;
|
|
|
|
|
|
// vLayout.childControlHeight = false;
|
|
|
|
|
|
// var size= content.AddComponent<ContentSizeFitter>();
|
|
|
|
|
|
// size.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
|
|
|
|
|
// size.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
|
|
|
|
|
|
|
|
|
|
|
var inputConfig = InputFieldConfig.Default;
|
|
|
|
|
|
inputConfig.RectConfig.AnchorMin = Vector2.zero;
|
|
|
|
|
|
inputConfig.RectConfig.AnchorMax = Vector2.right;
|
|
|
|
|
|
inputConfig.RectConfig.Pivot = new Vector2(0.5f, 1);
|
|
|
|
|
|
inputConfig.RectConfig.SizeDelta = new Vector2(0, titleHeight);
|
2025-11-13 16:24:49 +08:00
|
|
|
|
inputConfig.PlaceholderText = "输入对象名称";
|
2025-11-08 14:03:17 +08:00
|
|
|
|
var inputObj = ControlUtilities.CreateInputField(transform, inputConfig);
|
|
|
|
|
|
inputObj.inputField.onEndEdit.AddListener(s =>
|
|
|
|
|
|
{
|
|
|
|
|
|
currentAimObj = s;
|
|
|
|
|
|
Refresh();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
// Refresh();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void CreateTitleBar()
|
|
|
|
|
|
{
|
|
|
|
|
|
var titleBar = new GameObject("TitleBar").AddComponent<RectTransform>();
|
|
|
|
|
|
titleBar.transform.SetParent(transform, false);
|
|
|
|
|
|
if (titleBar == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to create TitleBar RectTransform.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
titleBar.anchorMin = new Vector2(0, 1);
|
|
|
|
|
|
titleBar.anchorMax = new Vector2(1, 1);
|
|
|
|
|
|
titleBar.pivot = new Vector2(0.5f, 1);
|
|
|
|
|
|
titleBar.sizeDelta = new Vector2(0, titleHeight);
|
|
|
|
|
|
titleBar.anchoredPosition = Vector2.zero;
|
|
|
|
|
|
|
|
|
|
|
|
var titleTextConfig = TextConfig.Default;
|
|
|
|
|
|
titleTextConfig.Text = "场景视图";
|
|
|
|
|
|
titleTextConfig.RectConfig.AnchorMin = Vector2.zero;
|
|
|
|
|
|
titleTextConfig.RectConfig.AnchorMax = Vector2.one;
|
|
|
|
|
|
|
|
|
|
|
|
var titleText = ControlUtilities.CreateText(titleBar, titleTextConfig);
|
2025-11-13 16:24:49 +08:00
|
|
|
|
if (titleText == null) Debug.LogError("Failed to create TitleText.");
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
var refreshButtonConfig = ButtonConfig.Default;
|
|
|
|
|
|
refreshButtonConfig.Text = "刷新";
|
|
|
|
|
|
refreshButtonConfig.BackgroundColor = Color.yellow;
|
|
|
|
|
|
refreshButtonConfig.RectConfig.SizeDelta = new Vector2(60, 40);
|
|
|
|
|
|
refreshButtonConfig.RectConfig.AnchoredPosition = new Vector2(35, -25);
|
|
|
|
|
|
var refreshButton = ControlUtilities.CreateButton(titleBar, refreshButtonConfig, Refresh);
|
|
|
|
|
|
|
|
|
|
|
|
var closeButtonConfig = ButtonConfig.Default;
|
|
|
|
|
|
closeButtonConfig.Text = "X";
|
|
|
|
|
|
closeButtonConfig.BackgroundColor = Color.red;
|
|
|
|
|
|
closeButtonConfig.RectConfig.AnchorMax = Vector2.one;
|
|
|
|
|
|
closeButtonConfig.RectConfig.AnchorMin = Vector2.one;
|
|
|
|
|
|
closeButtonConfig.RectConfig.SizeDelta = new Vector2(30, 30);
|
|
|
|
|
|
closeButtonConfig.RectConfig.AnchoredPosition = new Vector2(-25, -25);
|
|
|
|
|
|
ControlUtilities.CreateButton(titleBar, closeButtonConfig, () => gameObject.SetActive(false));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Refresh()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (treeViewNode)
|
|
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var canvas = GameObject.Find(currentAimObj);
|
|
|
|
|
|
// var canvas = FindIncludingHidden(currentAimObj);
|
|
|
|
|
|
if (!canvas && !string.IsNullOrEmpty(currentAimObj))
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"{currentAimObj} not found.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-11-18 18:45:14 +08:00
|
|
|
|
treeViewNode.ClearChildNodes();
|
|
|
|
|
|
StartCoroutine(treeViewNode.InitializeNode(canvas));
|
|
|
|
|
|
// StartCoroutine(treeViewNode.DisplayGameObjectStructureCoroutine(canvas));
|
2025-11-08 14:03:17 +08:00
|
|
|
|
// treeViewNode.DisplayGameObjectStructure(canvas);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-13 16:24:49 +08:00
|
|
|
|
/// 按名称查找场景中的GameObject,包括隐藏(非激活)对象和DontDestroyOnLoad对象。
|
|
|
|
|
|
/// 此方法会遍历所有当前加载到内存中的GameObject实例。
|
|
|
|
|
|
/// **重要提示:**
|
|
|
|
|
|
/// 1. **性能开销较大:** 该方法会遍历所有已加载的GameObject,性能开销相对较高。
|
|
|
|
|
|
/// 因此,**不建议在Update、FixedUpdate等帧循环中频繁调用。**
|
|
|
|
|
|
/// 2. **适用场景:** 更适合在初始化、加载场景、调试或不频繁的查找操作中使用。
|
|
|
|
|
|
/// 3. **同名对象:** 如果场景中存在多个同名对象,此方法将返回它遇到的第一个匹配项。
|
|
|
|
|
|
/// 4. **DontDestroyOnLoad:** 自动包含在DontDestroyOnLoad根下的对象。
|
|
|
|
|
|
/// 5. **隐藏对象:** 自动包含Hierarchy中非激活(隐藏)的对象。
|
2025-11-08 14:03:17 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="name">要查找的GameObject的名称。</param>
|
|
|
|
|
|
/// <returns>找到的第一个GameObject,如果未找到则返回null。</returns>
|
|
|
|
|
|
public static GameObject FindIncludingHidden(string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. 验证名称 - 处理null, empty, 或只包含空白字符的名称
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(name))
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("FindIncludingHidden: Provided name is null, empty, or whitespace. Returning null.");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-11-13 16:24:49 +08:00
|
|
|
|
|
|
|
|
|
|
var allGameObjects = Resources.FindObjectsOfTypeAll<GameObject>();
|
|
|
|
|
|
foreach (var obj in allGameObjects)
|
2025-11-08 14:03:17 +08:00
|
|
|
|
if (obj.name == name)
|
|
|
|
|
|
return obj; // 4. 返回第一个匹配项
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-13 16:24:49 +08:00
|
|
|
|
}
|