2024-07-10 19:06:07 +08:00
|
|
|
using System;
|
2024-07-11 14:45:15 +08:00
|
|
|
using System.IO;
|
|
|
|
using UnityEditor;
|
|
|
|
using UnityEngine;
|
2024-07-10 19:06:07 +08:00
|
|
|
using Framework.Manager;
|
|
|
|
using Sirenix.Utilities;
|
2024-07-11 14:45:15 +08:00
|
|
|
using Framework.GameBuild;
|
|
|
|
using Sirenix.OdinInspector;
|
2024-07-10 19:06:07 +08:00
|
|
|
using Sirenix.Utilities.Editor;
|
2024-07-11 14:45:15 +08:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using UnityEngine.SceneManagement;
|
|
|
|
using UnityEditor.SceneManagement;
|
|
|
|
using Sirenix.OdinInspector.Editor;
|
2024-07-10 19:06:07 +08:00
|
|
|
|
|
|
|
public class GameBuildWindow : OdinEditorWindow
|
|
|
|
{
|
|
|
|
[Serializable]
|
|
|
|
public class NodeEditor
|
|
|
|
{
|
|
|
|
[LabelText("挂点")] [ReadOnly] public string name;
|
|
|
|
|
2024-08-15 16:03:41 +08:00
|
|
|
[LabelText("选项实例")] [HideInInspector] public List<GameObject> optionObj;
|
2024-07-10 19:06:07 +08:00
|
|
|
|
2024-08-15 16:03:41 +08:00
|
|
|
[LabelText("选项资源路径")] [ReadOnly] public string optionPath = "Assets/Art/GameBuild/Texture";
|
2024-07-11 16:14:51 +08:00
|
|
|
|
|
|
|
[HideInInspector] public BuildData.BuildNode BuildNode;
|
2024-07-10 19:06:07 +08:00
|
|
|
|
|
|
|
public NodeEditor(string name, int count)
|
|
|
|
{
|
|
|
|
this.name = name;
|
2024-07-11 14:45:15 +08:00
|
|
|
optionObj = new List<GameObject>();
|
2024-07-10 19:06:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-17 17:56:02 +08:00
|
|
|
private const string NodeRootPath = "BuildRoot";
|
2024-07-10 19:06:07 +08:00
|
|
|
private const string NodeTemplatePath = "Assets/Art/GameBuild/Prefab/Node.prefab";
|
|
|
|
private const string OptionTemplatePath = "Option";
|
|
|
|
private const string NodeName = "Node{0}";
|
|
|
|
private const string OptionName = "Option{0}";
|
2024-07-11 14:45:15 +08:00
|
|
|
private const string BtnBubble = "Btn";
|
2024-07-12 17:10:33 +08:00
|
|
|
private const int BuildItemLayer = 10;
|
2024-08-15 16:03:41 +08:00
|
|
|
private const string BuildTexturePath = "Assets/Art/GameBuild/Texture/{0}";
|
2024-07-10 19:06:07 +08:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 当前窗口
|
|
|
|
/// </summary>
|
|
|
|
private static GameBuildWindow _curWindow;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 当前建造编辑器数据
|
|
|
|
/// </summary>
|
|
|
|
private BuildEditor _buildEditor;
|
|
|
|
|
2024-08-15 16:03:41 +08:00
|
|
|
private readonly List<GameObject> _tempNodeObj = new List<GameObject>();
|
2024-07-11 16:14:51 +08:00
|
|
|
|
2024-07-10 19:06:07 +08:00
|
|
|
[LabelText("当前建造数据")] [VerticalGroup("BuildInfo")]
|
|
|
|
public BuildData curBuildData;
|
|
|
|
|
2024-08-15 16:03:41 +08:00
|
|
|
[LabelText("当前建造资源文件夹")] [VerticalGroup("BuildInfo")] [FolderPath]
|
|
|
|
public string buildDataPath;
|
|
|
|
|
2024-07-11 14:45:15 +08:00
|
|
|
/// <summary>
|
|
|
|
/// 打开窗口
|
|
|
|
/// </summary>
|
2024-07-10 19:06:07 +08:00
|
|
|
public static void OpenWindow(BuildEditor buildEditor)
|
|
|
|
{
|
|
|
|
_curWindow = GetWindow<GameBuildWindow>();
|
|
|
|
_curWindow.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600);
|
|
|
|
_curWindow._buildEditor = buildEditor;
|
2024-07-11 14:45:15 +08:00
|
|
|
_curWindow.LoadBuildData(buildEditor.BuildData);
|
2024-07-10 19:06:07 +08:00
|
|
|
}
|
|
|
|
|
2024-07-11 14:45:15 +08:00
|
|
|
private void LoadBuildData(BuildData buildData)
|
|
|
|
{
|
2024-08-15 16:03:41 +08:00
|
|
|
editorNodeResource = false;
|
|
|
|
var assetName = _buildEditor.BuildDataJson.name;
|
|
|
|
buildDataPath = string.Format(BuildTexturePath, assetName.Replace(".json", ""));
|
|
|
|
DebugUtil.LogError("问价家:{0}", buildDataPath);
|
2024-07-11 14:45:15 +08:00
|
|
|
_curWindow.curBuildData = buildData;
|
2024-07-17 18:56:07 +08:00
|
|
|
curBuildData.buildID = GameBuildUtils.GetFileNameWithoutExtension(_buildEditor.BuildDataJson.name);
|
2024-07-11 14:45:15 +08:00
|
|
|
var root = GameObject.Find(NodeRootPath);
|
2024-07-17 18:56:07 +08:00
|
|
|
if (buildData.NodeInfos == null)
|
2024-07-17 17:56:02 +08:00
|
|
|
{
|
|
|
|
DebugUtil.LogError("需要重启该场景");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-07-11 14:45:15 +08:00
|
|
|
editorNodes = new List<NodeEditor>(buildData.nodeCount);
|
2024-07-17 18:56:07 +08:00
|
|
|
foreach (var node in buildData.NodeInfos)
|
2024-07-11 14:45:15 +08:00
|
|
|
{
|
2024-07-17 18:56:07 +08:00
|
|
|
var nodeObj = root.transform.Find(node.Name).gameObject;
|
2024-07-11 14:45:15 +08:00
|
|
|
if (nodeObj != null)
|
|
|
|
{
|
2024-07-17 18:56:07 +08:00
|
|
|
var editorNode = new NodeEditor(node.Name, buildData.thematicCount);
|
2024-07-11 14:45:15 +08:00
|
|
|
foreach (Transform child in nodeObj.transform)
|
|
|
|
{
|
|
|
|
if (!child.gameObject.name.Equals(BtnBubble))
|
|
|
|
{
|
|
|
|
editorNode.optionObj.Add(child.gameObject);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-11 16:14:51 +08:00
|
|
|
editorNode.BuildNode = node;
|
2024-07-12 17:10:33 +08:00
|
|
|
if (!string.IsNullOrEmpty(node.IconPath))
|
2024-07-19 17:18:17 +08:00
|
|
|
editorNode.optionPath = node.IconPath.Replace("Icon/{0}.png", "Normal");
|
2024-07-11 14:45:15 +08:00
|
|
|
editorNodes.Add(editorNode);
|
|
|
|
}
|
|
|
|
}
|
2024-07-11 16:14:51 +08:00
|
|
|
|
|
|
|
_tempNodeObj.Clear();
|
|
|
|
foreach (Transform child in root.transform)
|
|
|
|
{
|
|
|
|
_tempNodeObj.Add(child.gameObject);
|
|
|
|
}
|
2024-07-11 14:45:15 +08:00
|
|
|
}
|
|
|
|
|
2024-07-10 19:06:07 +08:00
|
|
|
[VerticalGroup("BuildInfo/Create")]
|
2024-08-15 16:03:41 +08:00
|
|
|
[Button("生成挂点实例")]
|
|
|
|
[InfoBox("会重新创建物体!!! 需要重新调整位置")]
|
|
|
|
public void Create()
|
|
|
|
{
|
|
|
|
if (string.IsNullOrEmpty(buildDataPath) || !Directory.Exists(buildDataPath)) return;
|
|
|
|
|
|
|
|
string[] directories = Directory.GetDirectories(buildDataPath);
|
|
|
|
|
|
|
|
curBuildData.nodeCount = directories.Length;
|
|
|
|
|
|
|
|
var iconPaths = new Dictionary<string, string>();
|
|
|
|
var optionPaths = new Dictionary<string, string>();
|
|
|
|
var optionCount = new int[curBuildData.nodeCount];
|
|
|
|
|
|
|
|
for (int i = 0; i < curBuildData.nodeCount; i++)
|
|
|
|
{
|
|
|
|
var nodePath = directories[i];
|
|
|
|
var nodeName = Path.GetFileName(nodePath);
|
|
|
|
|
|
|
|
//图标路径
|
|
|
|
var iconDir = Path.Combine(nodePath, "Icon");
|
|
|
|
var iconPath = Path.Combine("Assets", Path.GetFullPath(iconDir).Substring(Application.dataPath.Length + 1));
|
|
|
|
iconPaths.Add(nodeName, iconPath);
|
|
|
|
|
|
|
|
//选项路径
|
|
|
|
var normalDir = Path.Combine(nodePath, "Normal");
|
|
|
|
var normalPath = Path.Combine("Assets",
|
|
|
|
Path.GetFullPath(normalDir).Substring(Application.dataPath.Length + 1));
|
|
|
|
optionPaths.Add(nodeName, normalPath);
|
|
|
|
|
|
|
|
//选项数量
|
|
|
|
var optionFiles = Directory.GetFiles(normalDir, "*.png");
|
|
|
|
optionCount[i] = optionFiles.Length;
|
|
|
|
|
|
|
|
DebugUtil.LogError("挂点:{2},选项路径:{0},图标路径:{1}", normalPath, iconPath, nodeName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (optionCount.Length > 0)
|
|
|
|
{
|
|
|
|
curBuildData.thematicCount = optionCount[0];
|
|
|
|
DebugUtil.LogError("有挂点:{0} 个", curBuildData.thematicCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateNode(iconPaths, optionPaths);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateNode(Dictionary<string, string> iconPaths, Dictionary<string, string> optionPaths)
|
2024-07-10 19:06:07 +08:00
|
|
|
{
|
2024-07-11 14:45:15 +08:00
|
|
|
editorNodeResource = false;
|
|
|
|
if (editorNodes != null)
|
|
|
|
editorNodes.Clear();
|
|
|
|
|
2024-07-10 19:06:07 +08:00
|
|
|
switch (curBuildData.unlockType)
|
|
|
|
{
|
|
|
|
case UnlockType.ForGroup:
|
2024-08-15 16:03:41 +08:00
|
|
|
InitBuildInfo(curBuildData.nodeCount, iconPaths);
|
2024-07-10 19:06:07 +08:00
|
|
|
break;
|
|
|
|
case UnlockType.ForThematic:
|
2024-08-15 16:03:41 +08:00
|
|
|
InitBuildInfo(curBuildData.thematicCount, iconPaths);
|
2024-07-10 19:06:07 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DebugUtil.LogError("解锁条件错误");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-08-15 16:03:41 +08:00
|
|
|
CreateNodeObj(optionPaths);
|
2024-07-10 19:06:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 初始化建造数据
|
|
|
|
/// </summary>
|
2024-08-15 16:03:41 +08:00
|
|
|
private void InitBuildInfo(int count, Dictionary<string, string> iconPaths)
|
2024-07-10 19:06:07 +08:00
|
|
|
{
|
|
|
|
//挂点初始化
|
2024-07-17 18:56:07 +08:00
|
|
|
curBuildData.NodeInfos = new List<BuildData.BuildNode>(curBuildData.nodeCount);
|
2024-07-10 19:06:07 +08:00
|
|
|
for (int i = 0; i < curBuildData.nodeCount; i++)
|
|
|
|
{
|
2024-08-15 16:03:41 +08:00
|
|
|
var nodeName = string.Format(NodeName, i + 1);
|
|
|
|
if (!iconPaths.TryGetValue(nodeName, out var iconPath))
|
|
|
|
{
|
|
|
|
DebugUtil.LogError("没有检测到{0}的选项图标路径!!!", nodeName);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iconPath = iconPath.Replace("Icon", "Icon/{0}.png");
|
|
|
|
}
|
|
|
|
|
2024-07-19 15:27:04 +08:00
|
|
|
var node = new BuildData.BuildNode
|
|
|
|
{
|
2024-08-15 16:03:41 +08:00
|
|
|
Name = nodeName,
|
|
|
|
IconPath = iconPath
|
2024-07-19 15:27:04 +08:00
|
|
|
};
|
2024-07-17 18:56:07 +08:00
|
|
|
curBuildData.NodeInfos.Add(node);
|
2024-07-10 19:06:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//解锁条件初始化
|
|
|
|
curBuildData.unlockInfos = new List<BuildData.UnlockInfo>(count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
var unlock = new BuildData.UnlockInfo();
|
|
|
|
curBuildData.unlockInfos.Add(unlock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2024-08-15 16:03:41 +08:00
|
|
|
/// 创建实例挂点
|
2024-07-10 19:06:07 +08:00
|
|
|
/// </summary>
|
2024-08-15 16:03:41 +08:00
|
|
|
private void CreateNodeObj(Dictionary<string, string> optionPaths)
|
2024-07-10 19:06:07 +08:00
|
|
|
{
|
|
|
|
//清除
|
|
|
|
DeleteNode();
|
|
|
|
|
2024-07-11 16:14:51 +08:00
|
|
|
var root = GameObject.Find(NodeRootPath);
|
2024-07-10 19:06:07 +08:00
|
|
|
editorNodes = new List<NodeEditor>(curBuildData.nodeCount);
|
|
|
|
var nodeTemplate = AssetDatabase.LoadAssetAtPath<GameObject>(NodeTemplatePath);
|
2024-07-17 18:56:07 +08:00
|
|
|
foreach (var node in curBuildData.NodeInfos)
|
2024-07-10 19:06:07 +08:00
|
|
|
{
|
2024-07-11 14:45:15 +08:00
|
|
|
//生成节点
|
2024-07-11 16:14:51 +08:00
|
|
|
var nodeObj = Instantiate(nodeTemplate, root.transform);
|
2024-07-17 18:56:07 +08:00
|
|
|
nodeObj.name = node.Name;
|
2024-07-11 20:03:13 +08:00
|
|
|
_tempNodeObj.Add(nodeObj);
|
2024-07-10 19:06:07 +08:00
|
|
|
|
2024-07-11 14:45:15 +08:00
|
|
|
//生成选项
|
2024-07-12 17:10:33 +08:00
|
|
|
|
2024-07-17 18:56:07 +08:00
|
|
|
node.Options = new List<string>(curBuildData.thematicCount);
|
2024-07-12 17:10:33 +08:00
|
|
|
|
2024-07-10 19:06:07 +08:00
|
|
|
var optionTemplate = nodeObj.transform.Find(OptionTemplatePath).gameObject;
|
2024-07-17 18:56:07 +08:00
|
|
|
var tempEditorNode = new NodeEditor(node.Name, curBuildData.thematicCount);
|
2024-07-10 19:06:07 +08:00
|
|
|
for (int i = 0; i < curBuildData.thematicCount; i++)
|
|
|
|
{
|
|
|
|
var optionObj = Instantiate(optionTemplate, nodeObj.transform);
|
|
|
|
optionObj.name = string.Format(OptionName, i + 1);
|
2024-07-11 14:45:15 +08:00
|
|
|
tempEditorNode.optionObj.Add(optionObj);
|
2024-07-17 18:56:07 +08:00
|
|
|
node.Options.Add(optionObj.name);
|
2024-07-11 16:14:51 +08:00
|
|
|
if (i != 0)
|
|
|
|
optionObj.SetActive(false);
|
2024-07-10 19:06:07 +08:00
|
|
|
}
|
|
|
|
|
2024-08-15 16:03:41 +08:00
|
|
|
if (optionPaths.TryGetValue(node.Name, out var optionPath))
|
|
|
|
{
|
|
|
|
tempEditorNode.optionPath = optionPath;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DebugUtil.LogError("没有检测到{0}的选项路径!!!", node.Name);
|
|
|
|
}
|
|
|
|
|
2024-07-11 16:14:51 +08:00
|
|
|
tempEditorNode.BuildNode = node;
|
2024-07-10 19:06:07 +08:00
|
|
|
editorNodes.Add(tempEditorNode);
|
2024-07-11 14:45:15 +08:00
|
|
|
DestroyImmediate(optionTemplate);
|
2024-07-10 19:06:07 +08:00
|
|
|
|
2024-07-12 17:10:33 +08:00
|
|
|
//置顶泡泡按钮 UI操作
|
|
|
|
/*var btn = nodeObj.transform.Find(BtnBubble);
|
|
|
|
btn.transform.SetSiblingIndex(curBuildData.thematicCount);*/
|
2024-07-10 19:06:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[VerticalGroup("Node")] [LabelText("编辑挂点资源")]
|
|
|
|
public bool editorNodeResource;
|
|
|
|
|
|
|
|
[VerticalGroup("Node/Info")] [LabelText("挂点资源")] [ShowIf("@editorNodeResource")]
|
|
|
|
public List<NodeEditor> editorNodes;
|
|
|
|
|
|
|
|
[VerticalGroup("Node/NodeCreate")]
|
2024-08-15 16:03:41 +08:00
|
|
|
[Button("填充挂点资源")]
|
2024-07-10 19:06:07 +08:00
|
|
|
[ShowIf("@editorNodeResource")]
|
|
|
|
public void CreateNodeResource()
|
|
|
|
{
|
2024-08-15 16:03:41 +08:00
|
|
|
var sortingOrder = curBuildData.nodeCount;
|
2024-07-10 19:06:07 +08:00
|
|
|
foreach (var editorNode in editorNodes)
|
|
|
|
{
|
2024-07-11 14:45:15 +08:00
|
|
|
//加载路径下的资源
|
|
|
|
var fileEntries = Directory.GetFiles(editorNode.optionPath, "*.png");
|
|
|
|
var spriteList = new List<Sprite>();
|
|
|
|
foreach (var filePath in fileEntries)
|
2024-07-10 19:06:07 +08:00
|
|
|
{
|
2024-07-11 14:45:15 +08:00
|
|
|
var assetPath = filePath.Replace(Application.dataPath, "").Replace('\\', '/');
|
|
|
|
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(assetPath);
|
|
|
|
if (sprite != null)
|
|
|
|
{
|
|
|
|
spriteList.Add(sprite);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//应用资源
|
|
|
|
for (var i = 0; i < editorNode.optionObj.Count; i++)
|
|
|
|
{
|
|
|
|
if (i < spriteList.Count)
|
|
|
|
{
|
|
|
|
var spriteSize = new Vector2(spriteList[i].texture.width, spriteList[i].texture.height);
|
|
|
|
var option = editorNode.optionObj[i];
|
2024-07-12 17:10:33 +08:00
|
|
|
//UI处理
|
|
|
|
/*var normalObj = option.transform.Find("Normal").gameObject.GetComponent<Image>();
|
2024-07-11 14:45:15 +08:00
|
|
|
normalObj.sprite = spriteList[i];
|
|
|
|
var rect = normalObj.GetComponent<RectTransform>();
|
2024-07-12 17:10:33 +08:00
|
|
|
rect.sizeDelta = spriteSize;*/
|
|
|
|
var normalObj = option.transform.Find("Normal").gameObject;
|
|
|
|
var normalSprite = normalObj.GetComponent<SpriteRenderer>();
|
|
|
|
normalSprite.sortingOrder = sortingOrder;
|
|
|
|
normalSprite.sprite = spriteList[i];
|
|
|
|
normalObj.AddComponent<PolygonCollider2D>();
|
|
|
|
normalObj.layer = BuildItemLayer;
|
|
|
|
|
|
|
|
var btn = option.transform.parent.Find(BtnBubble);
|
|
|
|
btn.GetComponent<SpriteRenderer>().sortingOrder = sortingOrder;
|
2024-07-11 14:45:15 +08:00
|
|
|
}
|
2024-07-10 19:06:07 +08:00
|
|
|
}
|
2024-07-11 16:14:51 +08:00
|
|
|
|
2024-08-15 16:03:41 +08:00
|
|
|
sortingOrder--;
|
2024-07-11 16:14:51 +08:00
|
|
|
//初始化Icon资源路径
|
2024-07-19 17:18:17 +08:00
|
|
|
editorNode.BuildNode.IconPath = editorNode.optionPath.Replace("Normal", "Icon/{0}.png");
|
2024-07-10 19:06:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-11 14:45:15 +08:00
|
|
|
[VerticalGroup("Save")]
|
|
|
|
[Button("保存")]
|
|
|
|
public void Save()
|
|
|
|
{
|
|
|
|
_buildEditor.SaveData();
|
|
|
|
|
2024-07-11 16:14:51 +08:00
|
|
|
//保存场景
|
|
|
|
var activeScene = SceneManager.GetActiveScene();
|
2024-07-11 14:45:15 +08:00
|
|
|
var saveResult = EditorSceneManager.SaveScene(activeScene);
|
|
|
|
if (!saveResult)
|
|
|
|
DebugUtil.LogError("保存失败!!!");
|
|
|
|
}
|
|
|
|
|
2024-07-10 19:06:07 +08:00
|
|
|
private void DeleteNode()
|
|
|
|
{
|
2024-07-11 16:14:51 +08:00
|
|
|
foreach (var obj in _tempNodeObj)
|
2024-07-10 19:06:07 +08:00
|
|
|
{
|
2024-07-11 16:14:51 +08:00
|
|
|
DestroyImmediate(obj);
|
2024-07-10 19:06:07 +08:00
|
|
|
}
|
2024-07-11 16:14:51 +08:00
|
|
|
|
|
|
|
_tempNodeObj.Clear();
|
2024-07-10 19:06:07 +08:00
|
|
|
}
|
|
|
|
}
|