MayHeCome/Assets/Editor/科技树/TechTreeEditorWindow.cs

323 lines
9.6 KiB
C#
Raw Normal View History

2024-12-18 09:55:34 +00:00
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
public class TechTreeEditorWindow : EditorWindow
{
private List<TechNode> nodes = new List<TechNode>(); // 所有节点
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<TechTreeEditorWindow>("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<TechTreeData>();
}
// 保存头节点的数据
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<TechTreeData>(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<TechItem>(nodeData.techItemPath);
if (newNode.techItem != null)
{
// 清空旧的父子关系
newNode.techItem.parent = new List<TechItem>();
newNode.techItem.children.Clear();
// 恢复 TechItem 的父对象
foreach (var parentPath in nodeData.parents)
{
TechItem parentTechItem = AssetDatabase.LoadAssetAtPath<TechItem>(parentPath);
if (parentTechItem != null)
{
newNode.techItem.parent.Add(parentTechItem);
}
}
// 恢复 TechItem 的子对象
List<TechItem> validChildren = new List<TechItem>();
foreach (var childTechItem in newNode.techItem.children)
{
string childPath = AssetDatabase.GetAssetPath(childTechItem);
TechItem childItem = AssetDatabase.LoadAssetAtPath<TechItem>(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
}