MayHeCome/Assets/Editor/科技树/TechNode.cs
2024-12-18 17:55:34 +08:00

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;
}
}