using System.Collections.Generic; using UnityEditor; using UnityEngine; [System.Serializable] public class TechNode { public TechItem techItem; // 对应的 TechItem public Rect rect; public string title; private bool isDragged; public List children = new List(); // 子节点列表 public List parent = new List(); // 父节点列表(支持多个父节点) public TechNode(Vector2 position, float width, float height) { rect = new Rect(position.x, position.y, width, height); title = "节点"; } public void Draw() { // 设置节点框的颜色,如果被拖动则改变颜色 Color originalColor = GUI.color; if (isDragged) { GUI.color = Color.yellow; // 拖拽时节点变黄 } // 绘制节点框 GUI.Box(rect, title); // 绘制与父节点和子节点的连线 DrawConnections(); // 恢复颜色 GUI.color = originalColor; GUILayout.BeginArea(new Rect(rect.x, rect.y + 25, rect.width, rect.height - 25)); GUILayout.Space(10); // 保存旧的 TechItem TechItem oldTechItem = techItem; // 监控变化 EditorGUI.BeginChangeCheck(); // 允许用户选择或更改 TechItem techItem = (TechItem)EditorGUILayout.ObjectField(techItem, typeof(TechItem), false); // 如果检测到变化 if (EditorGUI.EndChangeCheck()) { HandleTechItemChange(oldTechItem); } GUILayout.EndArea(); } // 处理 TechItem 变化 private void HandleTechItemChange(TechItem oldTechItem) { // 清理旧 TechItem 的父子关系时,添加防护措施,避免无效操作 if (oldTechItem != null) { Debug.Log($"Old TechItem: {oldTechItem.itemName} - Removing old relationships..."); // 删除旧 TechItem 的所有父对象引用 foreach (var parentNode in oldTechItem.parent) { if (parentNode != null && parentNode.children.Contains(oldTechItem)) { parentNode.children.Remove(oldTechItem); // 从父节点的子节点列表中移除 Debug.Log($"Removing {oldTechItem.itemName} from parent {parentNode.itemName}"); } } oldTechItem.parent.Clear(); // 清空旧的父节点列表 // 删除旧 TechItem 的子对象引用 if (oldTechItem.children != null && oldTechItem.children.Count > 0) { foreach (var child in oldTechItem.children) { if (child.parent.Contains(oldTechItem)) { Debug.Log($"Removing {oldTechItem.itemName}'s child {child.itemName}'s parent reference"); child.parent.Remove(oldTechItem); // 清空每个子对象的父引用 } } oldTechItem.children.Clear(); // 清空子对象列表 } } // 对新的 TechItem 执行操作 if (techItem != null) { Debug.Log($"New TechItem: {techItem.itemName} - Establishing new relationships..."); // 为新的 TechItem 设置父对象 foreach (var parentNode in parent) { if (parentNode != null && parentNode.techItem != null && !parentNode.techItem.children.Contains(techItem)) { techItem.parent.Add(parentNode.techItem); // 设置新的 TechItem 的父对象 parentNode.techItem.children.Add(techItem); // 将新 TechItem 添加到父对象的子节点列表中 Debug.Log($"New TechItem {techItem.itemName} is now a child of {parentNode.techItem.itemName}"); } } // 为新的 TechItem 设置子对象 foreach (var childNode in children) { if (childNode.techItem != null && !techItem.children.Contains(childNode.techItem)) { techItem.children.Add(childNode.techItem); // 将子节点的 TechItem 添加到新 TechItem 的子对象列表 childNode.techItem.parent.Add(techItem); // 设置子 TechItem 的父对象为新 TechItem Debug.Log($"New TechItem {techItem.itemName} is now the parent of {childNode.techItem.itemName}"); } } } } // 绘制与父节点和子节点的连线 public void DrawConnections() { // 绘制与子节点的连线 foreach (TechNode child in children) { DrawBezierConnection(rect, child.rect); } // 绘制与父节点的连线 foreach (TechNode parentNode in parent) { DrawBezierConnection(parentNode.rect, rect); } } private void DrawBezierConnection(Rect fromRect, Rect toRect) { Vector3 startPos = new Vector3(fromRect.xMin + fromRect.width / 2, fromRect.yMax, 0); Vector3 endPos = new Vector3(toRect.xMin + toRect.width / 2, toRect.yMin, 0); Vector3 startTangent = startPos + Vector3.down * 50f; Vector3 endTangent = endPos + Vector3.up * 50f; Handles.DrawBezier( startPos, endPos, startTangent, endTangent, Color.white, null, 2f ); Vector3 arrowPosition = GetPointOnBezierCurve(0.95f, startPos, startTangent, endTangent, endPos); // 更靠近末端 Vector3 arrowDirection = GetTangentOnBezierCurve(0.95f, startPos, startTangent, endTangent, endPos).normalized; DrawArrow(arrowPosition, arrowDirection); } // 绘制箭头 private void DrawArrow(Vector3 position, Vector3 direction) { float arrowHeadAngle = 20.0f; float arrowHeadLength = 15.0f; Vector3 rightArrow = Quaternion.Euler(0, 0, -arrowHeadAngle) * direction * arrowHeadLength; Vector3 leftArrow = Quaternion.Euler(0, 0, arrowHeadAngle) * direction * arrowHeadLength; Handles.color = Color.red; Handles.DrawLine(position, position + rightArrow); Handles.DrawLine(position, position + leftArrow); } // 删除所有子节点连接,同时更新 TechItem 的父子关系 public void RemoveAllConnections() { foreach (TechNode childNode in children) { if (techItem != null && childNode.techItem != null) { childNode.techItem.parent.Remove(techItem); // 移除 TechItem 的父节点 techItem.children.Remove(childNode.techItem); // 从父节点的子节点列表中移除 } childNode.parent.Remove(this); // 移除节点的父节点 } children.Clear(); } // 删除指定的子节点连接,同时更新 TechItem 的父子关系 public void RemoveConnection(TechNode targetNode) { if (children.Contains(targetNode)) { if (techItem != null && targetNode.techItem != null) { targetNode.techItem.parent.Remove(techItem); // 移除目标 TechItem 的父节点 techItem.children.Remove(targetNode.techItem); // 从父节点的子节点列表中移除 } targetNode.parent.Remove(this); // 移除节点的父节点 children.Remove(targetNode); // 从节点的子节点列表中移除 } } // 连接到子节点,同时更新 TechItem 的父子关系 public void ConnectTo(TechNode childNode) { if (!children.Contains(childNode) && childNode != this && !childNode.parent.Contains(this)) { children.Add(childNode); childNode.parent.Add(this); if (techItem != null && childNode.techItem != null) { techItem.children.Add(childNode.techItem); // 更新 TechItem 的子节点列表 childNode.techItem.parent.Add(techItem); // 设置子节点的父节点 } } } // 计算贝塞尔曲线上的点 private Vector3 GetPointOnBezierCurve(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { float u = 1 - t; float tt = t * t; float uu = u * u; float uuu = uu * u; float ttt = tt * t; Vector3 point = uuu * p0; point += 3 * uu * t * p1; point += 3 * u * tt * p2; point += ttt * p3; return point; } // 计算贝塞尔曲线上的切线(方向) private Vector3 GetTangentOnBezierCurve(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { float u = 1 - t; float tt = t * t; float uu = u * u; Vector3 tangent = -3 * uu * p0 + 3 * uu * p1 - 6 * u * t * p1 + 6 * u * t * p2 - 3 * tt * p2 + 3 * tt * p3; return tangent; } // 处理节点事件 public bool ProcessEvents(Event e) { switch (e.type) { case EventType.MouseDown: if (e.button == 0 && rect.Contains(e.mousePosition)) { isDragged = true; GUI.changed = true; } break; case EventType.MouseUp: isDragged = false; break; case EventType.MouseDrag: if (e.button == 0 && isDragged) { Drag(e.delta); e.Use(); return true; } break; } return false; } // 拖拽节点 public void Drag(Vector2 delta) { rect.position += delta; } }