290 lines
9.7 KiB
C#
290 lines
9.7 KiB
C#
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<TechNode> children = new List<TechNode>(); // 子节点列表
|
|
public List<TechNode> parent = new List<TechNode>(); // 父节点列表(支持多个父节点)
|
|
|
|
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;
|
|
}
|
|
}
|