using System; using System.IO; using UnityEditor; using UnityEngine; using Framework.Manager; using Sirenix.Utilities; using Framework.GameBuild; using Sirenix.OdinInspector; using Sirenix.Utilities.Editor; using System.Collections.Generic; using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using Sirenix.OdinInspector.Editor; public class GameBuildWindow : OdinEditorWindow { [Serializable] public class NodeEditor { [LabelText("挂点")] [ReadOnly] public string name; [LabelText("选项实例")] [HideInInspector] public List optionObj; [LabelText("选项资源路径")] [ReadOnly] public string optionPath = "Assets/Art/GameBuild/Texture"; [HideInInspector] public BuildData.BuildNode BuildNode; public NodeEditor(string name, int count) { this.name = name; optionObj = new List(); } } private const string NodeRootPath = "BuildRoot"; 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}"; private const string BtnBubble = "Btn"; private const int BuildItemLayer = 10; private const string BuildTexturePath = "Assets/Art/GameBuild/Texture/{0}"; /// /// 当前窗口 /// private static GameBuildWindow _curWindow; /// /// 当前建造编辑器数据 /// private BuildEditor _buildEditor; private readonly List _tempNodeObj = new List(); [LabelText("当前建造数据")] [VerticalGroup("BuildInfo")] public BuildData curBuildData; [LabelText("当前建造资源文件夹")] [VerticalGroup("BuildInfo")] [FolderPath] public string buildDataPath; /// /// 打开窗口 /// public static void OpenWindow(BuildEditor buildEditor) { _curWindow = GetWindow(); _curWindow.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600); _curWindow._buildEditor = buildEditor; _curWindow.LoadBuildData(buildEditor.BuildData); } private void LoadBuildData(BuildData buildData) { editorNodeResource = false; var assetName = _buildEditor.BuildDataJson.name; buildDataPath = string.Format(BuildTexturePath, assetName.Replace(".json", "")); DebugUtil.LogError("问价家:{0}", buildDataPath); _curWindow.curBuildData = buildData; curBuildData.buildID = GameBuildUtils.GetFileNameWithoutExtension(_buildEditor.BuildDataJson.name); var root = GameObject.Find(NodeRootPath); if (buildData.NodeInfos == null) { DebugUtil.LogError("需要重启该场景"); return; } editorNodes = new List(buildData.nodeCount); foreach (var node in buildData.NodeInfos) { var nodeObj = root.transform.Find(node.Name).gameObject; if (nodeObj != null) { var editorNode = new NodeEditor(node.Name, buildData.thematicCount); foreach (Transform child in nodeObj.transform) { if (!child.gameObject.name.Equals(BtnBubble)) { editorNode.optionObj.Add(child.gameObject); } } editorNode.BuildNode = node; if (!string.IsNullOrEmpty(node.IconPath)) editorNode.optionPath = node.IconPath.Replace("Icon/{0}.png", "Normal"); editorNodes.Add(editorNode); } } _tempNodeObj.Clear(); foreach (Transform child in root.transform) { _tempNodeObj.Add(child.gameObject); } } [VerticalGroup("BuildInfo/Create")] [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(); var optionPaths = new Dictionary(); 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 iconPaths, Dictionary optionPaths) { editorNodeResource = false; if (editorNodes != null) editorNodes.Clear(); switch (curBuildData.unlockType) { case UnlockType.ForGroup: InitBuildInfo(curBuildData.nodeCount, iconPaths); break; case UnlockType.ForThematic: InitBuildInfo(curBuildData.thematicCount, iconPaths); break; default: DebugUtil.LogError("解锁条件错误"); break; } CreateNodeObj(optionPaths); } /// /// 初始化建造数据 /// private void InitBuildInfo(int count, Dictionary iconPaths) { //挂点初始化 curBuildData.NodeInfos = new List(curBuildData.nodeCount); for (int i = 0; i < curBuildData.nodeCount; i++) { 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"); } var node = new BuildData.BuildNode { Name = nodeName, IconPath = iconPath }; curBuildData.NodeInfos.Add(node); } //解锁条件初始化 curBuildData.unlockInfos = new List(count); for (int i = 0; i < count; i++) { var unlock = new BuildData.UnlockInfo(); curBuildData.unlockInfos.Add(unlock); } } /// /// 创建实例挂点 /// private void CreateNodeObj(Dictionary optionPaths) { //清除 DeleteNode(); var root = GameObject.Find(NodeRootPath); editorNodes = new List(curBuildData.nodeCount); var nodeTemplate = AssetDatabase.LoadAssetAtPath(NodeTemplatePath); foreach (var node in curBuildData.NodeInfos) { //生成节点 var nodeObj = Instantiate(nodeTemplate, root.transform); nodeObj.name = node.Name; _tempNodeObj.Add(nodeObj); //生成选项 node.Options = new List(curBuildData.thematicCount); var optionTemplate = nodeObj.transform.Find(OptionTemplatePath).gameObject; var tempEditorNode = new NodeEditor(node.Name, curBuildData.thematicCount); for (int i = 0; i < curBuildData.thematicCount; i++) { var optionObj = Instantiate(optionTemplate, nodeObj.transform); optionObj.name = string.Format(OptionName, i + 1); tempEditorNode.optionObj.Add(optionObj); node.Options.Add(optionObj.name); if (i != 0) optionObj.SetActive(false); } if (optionPaths.TryGetValue(node.Name, out var optionPath)) { tempEditorNode.optionPath = optionPath; } else { DebugUtil.LogError("没有检测到{0}的选项路径!!!", node.Name); } tempEditorNode.BuildNode = node; editorNodes.Add(tempEditorNode); DestroyImmediate(optionTemplate); //置顶泡泡按钮 UI操作 /*var btn = nodeObj.transform.Find(BtnBubble); btn.transform.SetSiblingIndex(curBuildData.thematicCount);*/ } } [VerticalGroup("Node")] [LabelText("编辑挂点资源")] public bool editorNodeResource; [VerticalGroup("Node/Info")] [LabelText("挂点资源")] [ShowIf("@editorNodeResource")] public List editorNodes; [VerticalGroup("Node/NodeCreate")] [Button("填充挂点资源")] [ShowIf("@editorNodeResource")] public void CreateNodeResource() { var sortingOrder = curBuildData.nodeCount; foreach (var editorNode in editorNodes) { //加载路径下的资源 var fileEntries = Directory.GetFiles(editorNode.optionPath, "*.png"); var spriteList = new List(); foreach (var filePath in fileEntries) { var assetPath = filePath.Replace(Application.dataPath, "").Replace('\\', '/'); var sprite = AssetDatabase.LoadAssetAtPath(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]; //UI处理 /*var normalObj = option.transform.Find("Normal").gameObject.GetComponent(); normalObj.sprite = spriteList[i]; var rect = normalObj.GetComponent(); rect.sizeDelta = spriteSize;*/ var normalObj = option.transform.Find("Normal").gameObject; var normalSprite = normalObj.GetComponent(); normalSprite.sortingOrder = sortingOrder; normalSprite.sprite = spriteList[i]; normalObj.AddComponent(); normalObj.layer = BuildItemLayer; var btn = option.transform.parent.Find(BtnBubble); btn.GetComponent().sortingOrder = sortingOrder; } } sortingOrder--; //初始化Icon资源路径 editorNode.BuildNode.IconPath = editorNode.optionPath.Replace("Normal", "Icon/{0}.png"); } } [VerticalGroup("Save")] [Button("保存")] public void Save() { _buildEditor.SaveData(); //保存场景 var activeScene = SceneManager.GetActiveScene(); var saveResult = EditorSceneManager.SaveScene(activeScene); if (!saveResult) DebugUtil.LogError("保存失败!!!"); } private void DeleteNode() { foreach (var obj in _tempNodeObj) { DestroyImmediate(obj); } _tempNodeObj.Clear(); } }