using UnityEditor; using UnityEngine; using System.Collections.Generic; public class TechTreeEditorWindow : EditorWindow { private List nodes = new List(); // 所有节点 private TechNode headnode; private Vector2 mousePosition; private TechNode selectedNode; // 当前选中的节点 private TechNode nodeToConnect; // 用于保存待连接的节点 // TechTreeData 用于保存和加载的 ScriptableObject private TechTreeData techTreeData; [MenuItem("Window/Tech Tree Editor")] public static void ShowWindow() { GetWindow("Tech Tree Editor"); } private void OnGUI() { Event e = Event.current; mousePosition = e.mousePosition; // 继续绘制节点和处理事件 DrawNodes(); ProcessNodeEvents(e); if (e.button == 1 && e.type == EventType.MouseDown) { ShowContextMenu(); } // 检测点击空白区域以取消选中节点 if (e.button == 0 && e.type == EventType.MouseDown && !IsMouseOverAnyNode(mousePosition)) { // 取消选择 if (nodeToConnect != null) { nodeToConnect.title = "节点"; // 恢复节点标题 nodeToConnect = null; selectedNode = null; Debug.Log("取消选中"); } } // 刷新窗口 Repaint(); } private void OnEnable() { LoadTechTreeData(); } private void OnDisable() { SaveTechTreeData(); } private void DrawNodes() { foreach (TechNode node in nodes) { node.Draw(); } } // 显示右键菜单 private void ShowContextMenu() { GenericMenu menu = new GenericMenu(); if (selectedNode != null) { menu.AddItem(new GUIContent("Remove Node"), false, RemoveSelectedNode); menu.AddItem(new GUIContent("Remove Connections"), false, RemoveSelectedNodeConnections); } else { menu.AddItem(new GUIContent("Add Node"), false, () => AddNode(mousePosition)); } menu.ShowAsContext(); } // 添加节点 private void AddNode(Vector2 position) { TechNode newNode = new TechNode(position, 100, 50); if (nodes.Count == 0) { headnode = newNode; } nodes.Add(newNode); } // 删除选中的节点 private void RemoveSelectedNode() { if (selectedNode != null) { if (selectedNode == headnode) { // 不能删除头节点 } else { // 首先删除与其他节点的连接 foreach (TechNode node in nodes) { node.RemoveConnection(selectedNode); } nodes.Remove(selectedNode); selectedNode = null; } } } // 删除选中节点的所有连接 private void RemoveSelectedNodeConnections() { if (selectedNode != null) { selectedNode.RemoveAllConnections(); } } // 检查鼠标是否悬停在某个节点上 private bool IsMouseOverAnyNode(Vector2 mousePos) { foreach (TechNode node in nodes) { if (node.rect.Contains(mousePos)) { return true; // 鼠标在某个节点上 } } return false; // 鼠标不在任何节点上 } // 处理节点事件(拖拽、连接、选择) private void ProcessNodeEvents(Event e) { foreach (TechNode node in nodes) { bool guiChanged = node.ProcessEvents(e); if (guiChanged) { GUI.changed = true; } // 处理右键选择 if (e.type == EventType.MouseDown && e.button == 1 && node.rect.Contains(e.mousePosition)) { selectedNode = node; // 选中节点 } // 处理左键点击的节点选择与连接 if (e.type == EventType.MouseDown && e.button == 0 && node.rect.Contains(e.mousePosition)) { Debug.LogWarning("鼠标位置" + e.mousePosition + "---" + node.rect); // 如果是第一次选择节点,标记为待连接 if (nodeToConnect == null) { Debug.Log("已选择"); nodeToConnect = node; node.title = "已选择"; } else if (nodeToConnect != node && node.techItem != null && node.techItem != null) { // 如果选择了不同的节点,执行连接操作 nodeToConnect.ConnectTo(node); // 支持多个父节点 nodeToConnect.title = "节点"; nodeToConnect = null; // 完成连接后清空选择 } } } } #region 存储 private void SaveTechTreeData() { // 确保文件夹存在 string folderPath = "Assets/科技树/科技树窗口"; if (!System.IO.Directory.Exists(folderPath)) { System.IO.Directory.CreateDirectory(folderPath); } // 检查是否有 techTreeData,如果没有则创建 if (techTreeData == null) { techTreeData = CreateInstance(); } // 保存头节点的数据 if (headnode != null) { techTreeData.headNode = SaveNodeData(headnode); // 递归保存头节点及其子节点 } // 保存 TechTreeData 资产文件 string techTreeDataPath = $"{folderPath}/窗口数据.asset"; if (!AssetDatabase.Contains(techTreeData)) { AssetDatabase.CreateAsset(techTreeData, techTreeDataPath); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Debug.Log("科技树数据已成功保存!"); } // 递归保存节点及其子节点数据 private TechNodeData SaveNodeData(TechNode node) { var nodeData = new TechNodeData { position = node.rect.position, title = node.title, techItemPath = AssetDatabase.GetAssetPath(node.techItem) // 保存 TechItem 的路径 }; // 如果 TechItem 是新建的,保存它 if (string.IsNullOrEmpty(nodeData.techItemPath) && node.techItem != null) { string techItemPath = AssetDatabase.GenerateUniqueAssetPath($"Assets/科技树/科技树窗口/{node.techItem.itemName}.asset"); AssetDatabase.CreateAsset(node.techItem, techItemPath); nodeData.techItemPath = techItemPath; } // 递归保存子节点 foreach (var childNode in node.children) { var childNodeData = SaveNodeData(childNode); // 递归调用 nodeData.children.Add(childNodeData); } return nodeData; } private void LoadTechTreeData() { string assetPath = "Assets/科技树/科技树窗口/窗口数据.asset"; techTreeData = AssetDatabase.LoadAssetAtPath(assetPath); if (techTreeData != null && techTreeData.headNode != null) { // 通过保存的头节点数据加载头节点 headnode = LoadNodeData(techTreeData.headNode); Debug.Log("科技树数据已加载成功!"); } else { Debug.LogWarning("TechTreeData 资产不存在!"); } } // 递归加载节点及其子节点 private TechNode LoadNodeData(TechNodeData nodeData) { var newNode = new TechNode(nodeData.position, 100, 50) { title = nodeData.title }; // 加载对应的 TechItem if (!string.IsNullOrEmpty(nodeData.techItemPath)) { newNode.techItem = AssetDatabase.LoadAssetAtPath(nodeData.techItemPath); if (newNode.techItem != null) { // 清空旧的父子关系 newNode.techItem.parent = new List(); newNode.techItem.children.Clear(); // 恢复 TechItem 的父对象 foreach (var parentPath in nodeData.parents) { TechItem parentTechItem = AssetDatabase.LoadAssetAtPath(parentPath); if (parentTechItem != null) { newNode.techItem.parent.Add(parentTechItem); } } // 恢复 TechItem 的子对象 List validChildren = new List(); foreach (var childTechItem in newNode.techItem.children) { string childPath = AssetDatabase.GetAssetPath(childTechItem); TechItem childItem = AssetDatabase.LoadAssetAtPath(childPath); if (childItem != null) { validChildren.Add(childItem); } } newNode.techItem.children = validChildren; // 更新 TechItem 的子节点列表 } } nodes.Add(newNode); // 递归加载子节点 foreach (var childNodeData in nodeData.children) { var childNode = LoadNodeData(childNodeData); // 递归调用 newNode.ConnectTo(childNode); // 恢复父子关系 } return newNode; } #endregion }