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

323 lines
9.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}