using UnityEngine; using UnityEditor; using System.Collections.Generic; using System.IO; using Newtonsoft.Json; public class QuestionConfigEditor : EditorWindow { private QuestionConfigData configData; private Vector2 scrollPosition; private const string CONFIG_PATH = "Assets/Resources/QuestionConfigData.json"; private List foldouts = new List(); [MenuItem("Tools/题目配置编辑器")] public static void ShowWindow() { GetWindow("题目配置编辑器"); } private void OnEnable() { LoadConfigData(); SyncFoldouts(); } private void LoadConfigData() { if (!Directory.Exists("Assets/Resources")) { Directory.CreateDirectory("Assets/Resources"); } if (File.Exists(CONFIG_PATH)) { string jsonContent = File.ReadAllText(CONFIG_PATH); configData = JsonConvert.DeserializeObject(jsonContent); } if (configData == null) { configData = new QuestionConfigData(); SaveConfigData(); } } private void SaveConfigData() { string jsonContent = JsonConvert.SerializeObject(configData, Formatting.Indented); File.WriteAllText(CONFIG_PATH, jsonContent); AssetDatabase.Refresh(); } private void SyncFoldouts() { while (foldouts.Count < configData.configs.Count) foldouts.Add(false); while (foldouts.Count > configData.configs.Count) foldouts.RemoveAt(foldouts.Count - 1); } // 获取对象的Hierarchy路径 public static string GetHierarchyPath(Transform trans) { string path = trans.name; while (trans.parent != null) { trans = trans.parent; path = trans.name + "/" + path; } return path; } // 通过路径查找对象 public static GameObject FindByHierarchyPath(string path) { return GameObject.Find(path); } private void OnGUI() { if (configData == null) { EditorGUILayout.HelpBox("未找到配置文件,请先创建配置文件。", MessageType.Error); if (GUILayout.Button("创建配置文件")) { LoadConfigData(); } return; } EditorGUILayout.BeginVertical(); scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); SyncFoldouts(); for (int i = 0; i < configData.configs.Count; i++) { var config = configData.configs[i]; if (foldouts.Count <= i) foldouts.Add(false); // 根据配置类型显示不同的标题和颜色 string configTypeText = config.configType == ConfigType.大类 ? "大类" : "题目"; string displayName = $"{configTypeText}:{config.questionName}"; // 使用不同的样式区分大类和小类 var foldoutStyle = config.configType == ConfigType.大类 ? EditorStyles.foldoutHeader : EditorStyles.foldout; foldouts[i] = EditorGUILayout.Foldout(foldouts[i], displayName, true, foldoutStyle); if (foldouts[i]) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); // 配置类型选择 EditorGUILayout.BeginHorizontal(); config.configType = (ConfigType)EditorGUILayout.EnumPopup("配置类型", config.configType); if (GUILayout.Button("删除", GUILayout.Width(80))) { configData.configs.RemoveAt(i); foldouts.RemoveAt(i); i--; EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); continue; } EditorGUILayout.EndHorizontal(); // 名称输入 string nameLabel = config.configType == ConfigType.大类 ? "大类名称" : "题目名称"; config.questionName = EditorGUILayout.TextField(nameLabel, config.questionName); // 按钮-界面对象成对列表 EditorGUILayout.LabelField("按钮-界面对象列表", EditorStyles.boldLabel); for (int j = 0; j < config.pairs.Count; j++) { var pair = config.pairs[j]; EditorGUILayout.BeginVertical(EditorStyles.helpBox); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField($"按钮-界面对象 {j + 1}", EditorStyles.boldLabel); if (GUILayout.Button("删除", GUILayout.Width(60))) { config.pairs.RemoveAt(j); j--; EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); continue; } EditorGUILayout.EndHorizontal(); // 按钮对象 GameObject menuObj = string.IsNullOrEmpty(pair.menuButtonPath) ? null : FindByHierarchyPath(pair.menuButtonPath); GameObject newMenuObj = (GameObject)EditorGUILayout.ObjectField("按钮对象", menuObj, typeof(GameObject), true); if (newMenuObj != menuObj && newMenuObj != null) { pair.menuButtonPath = GetHierarchyPath(newMenuObj.transform); } // 界面对象 GameObject panelObj = string.IsNullOrEmpty(pair.panelObjectPath) ? null : FindByHierarchyPath(pair.panelObjectPath); GameObject newPanelObj = (GameObject)EditorGUILayout.ObjectField("界面对象", panelObj, typeof(GameObject), true); if (newPanelObj != panelObj && newPanelObj != null) { pair.panelObjectPath = GetHierarchyPath(newPanelObj.transform); } pair.shouldActivate = EditorGUILayout.Toggle("激活界面", pair.shouldActivate); // 多选脚本 if (newPanelObj != null) { var scripts = newPanelObj.GetComponents(); EditorGUILayout.LabelField("要启动的脚本(可多选)", EditorStyles.boldLabel); // 从配置中获取已选择的脚本列表 List selectedScripts = new List(); if (!string.IsNullOrEmpty(pair.scriptTypeName)) { selectedScripts.AddRange(pair.scriptTypeName.Split(',')); } foreach (var script in scripts) { var type = script.GetType(); if (type.Namespace != null && type.Namespace.StartsWith("UnityEngine")) continue; if (type.Module.ScopeName == "UnityEngine.dll") continue; bool selected = selectedScripts.Contains(type.Name); bool newSelected = EditorGUILayout.ToggleLeft(type.Name, selected); if (newSelected && !selected) { selectedScripts.Add(type.Name); } else if (!newSelected && selected) { selectedScripts.Remove(type.Name); } } // 保存多选到配置 pair.scriptTypeName = string.Join(",", selectedScripts); } else { EditorGUILayout.HelpBox("请先选择界面对象", MessageType.Info); } EditorGUILayout.EndVertical(); } if (GUILayout.Button("添加按钮-界面对象")) { config.pairs.Add(new ButtonPanelPair()); } EditorGUILayout.EndVertical(); EditorGUILayout.Space(); } } EditorGUILayout.EndScrollView(); // 添加按钮区域 EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("添加新题目")) { var newConfig = new QuestionConfig(); newConfig.configType = ConfigType.小类; newConfig.questionName = "新题目"; configData.configs.Add(newConfig); foldouts.Add(true); } if (GUILayout.Button("添加新大类")) { var newConfig = new QuestionConfig(); newConfig.configType = ConfigType.大类; newConfig.questionName = "新大类"; configData.configs.Add(newConfig); foldouts.Add(true); } EditorGUILayout.EndHorizontal(); if (GUILayout.Button("保存配置")) { SaveConfigData(); Debug.Log("配置已保存!"); } EditorGUILayout.EndVertical(); } }