当前位置:   article > 正文

Unity 编辑器扩展 ( 案例1.在代码中进行GameObject生成和赋值保存预知体 案例2  代码生成器 案例3重启项目)_unity 编辑器扩展 ( 案例1.在代码中进行gameobject生成和赋值保存预知体 案例2 代

unity 编辑器扩展 ( 案例1.在代码中进行gameobject生成和赋值保存预知体 案例2 代

初步学习Unity EditorWindow 的扩展

案例1.在代码中进行GameObject生成和赋值保存预知体  下面有GIF演示图片

  • 生成Gameobject 并对其进行赋值
  • 序列化
  • 生成Prefabs
  • 编辑器窗口 EditorWindow

新建UIRoot类

  1. using UnityEngine;
  2. public class UIRoot : MonoBehaviour
  3. {
  4. public Transform bg;
  5. public Transform common;
  6. public Transform uiPop;
  7. public Transform forward;
  8. [SerializeField]
  9. private Canvas mRootCanvas;
  10. }

生成Canvas 等。。

  1. using System.IO;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using UnityEditor;
  7. using UnityEngine.EventSystems;
  8. using UnityEngine.UI;
  9. public class CreateUIRootPanel : EditorWindow
  10. {
  11. static CreateUIRootPanel window;
  12. [MenuItem("编辑器扩展/1.SetUp(UIRoot)", true)]
  13. static bool ValidateUIRoot()
  14. {
  15. return !GameObject.Find("UIRoot");
  16. }
  17. [MenuItem("编辑器扩展/1.SetUp(UIRoot)", false)]
  18. static void MenuItem()
  19. {
  20. window = GetWindow<CreateUIRootPanel>();
  21. window.Show();
  22. }
  23. private string mWidth = "720";
  24. private string mHeight = "1280";
  25. private void OnGUI()
  26. {
  27. GUILayout.BeginHorizontal();
  28. //var width = GUILayout.TextField("width", GUILayout.Width(50));
  29. mWidth = GUILayout.TextField(mWidth, GUILayout.Width(50));
  30. GUILayout.Label("X", GUILayout.Width(15));
  31. mHeight = GUILayout.TextField(mHeight, GUILayout.Width(55));
  32. GUILayout.EndHorizontal();
  33. if (GUILayout.Button("Build"))
  34. {
  35. Debug.Log("build");
  36. SetUP(float.Parse(mWidth), float.Parse(mHeight));
  37. // window.Close();
  38. }
  39. }
  40. public static void SetUP(float width, float height)
  41. {
  42. Debug.Log("编辑器扩展");
  43. // GameObject go = Resources.Load<GameObject>("UIroot");
  44. // GameObject.Instantiate(go);
  45. var UIRootObj = new GameObject("UIRoot");
  46. UIRootObj.layer = LayerMask.NameToLayer("UI");
  47. UIRoot UIScript = UIRootObj.AddComponent<UIRoot>();
  48. var canvas = new GameObject("Canvas");
  49. canvas.transform.SetParent(UIRootObj.transform);
  50. canvas.layer = LayerMask.NameToLayer("UI");
  51. canvas.AddComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
  52. //canvas.AddComponent<CanvasGroup>();
  53. //CanvasScaler
  54. CanvasScaler canvasScaler = canvas.AddComponent<CanvasScaler>();
  55. canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
  56. canvasScaler.referenceResolution = new Vector2(width, height);
  57. canvas.AddComponent<GraphicRaycaster>();
  58. //EventSystem
  59. var eventSystem = new GameObject("EventSystem");
  60. eventSystem.layer = LayerMask.NameToLayer("UI");
  61. eventSystem.transform.SetParent(UIRootObj.transform);
  62. eventSystem.AddComponent<EventSystem>();
  63. eventSystem.AddComponent<StandaloneInputModule>();
  64. //BG
  65. var bgObj = new GameObject("Bg");
  66. bgObj.AddComponent<RectTransform>();
  67. bgObj.transform.SetParent(canvas.transform);
  68. bgObj.transform.localPosition = Vector3.zero;
  69. UIScript.bg = bgObj.transform;
  70. //Common
  71. var commonObj = new GameObject("Common");
  72. commonObj.AddComponent<RectTransform>();
  73. commonObj.transform.SetParent(canvas.transform);
  74. commonObj.transform.localPosition = Vector3.zero;
  75. UIScript.common = commonObj.transform;
  76. //PopUI
  77. var popUI = new GameObject("PopUI");
  78. popUI.AddComponent<RectTransform>();
  79. popUI.transform.SetParent(canvas.transform);
  80. popUI.transform.localPosition = Vector3.zero;
  81. UIScript.uiPop = popUI.transform;
  82. //ForwardObj
  83. var forwardObj = new GameObject("Forward");
  84. forwardObj.AddComponent<RectTransform>();
  85. forwardObj.transform.SetParent(canvas.transform);
  86. forwardObj.transform.localPosition = Vector3.zero;
  87. UIScript.forward = forwardObj.transform;
  88. ///序列化脚本 添加 UIRoot中的Private的值
  89. var uirootScriptSerializedObj = new SerializedObject(UIScript);
  90. uirootScriptSerializedObj.FindProperty("mRootCanvas").objectReferenceValue = canvas.GetComponent<Canvas>();
  91. uirootScriptSerializedObj.ApplyModifiedProperties();
  92. var saveFolder = Application.dataPath + "/Resources";
  93. if (!Directory.Exists(saveFolder))
  94. {
  95. Directory.CreateDirectory(saveFolder);
  96. }
  97. var saveFilePath = saveFolder + "/UIRoot.Prefab";
  98. // PrefabUtility.CreatePrefab(saveFilePath, UIRootObj);
  99. bool IsLoad = false;
  100. PrefabUtility.SaveAsPrefabAsset(UIRootObj, saveFilePath, out IsLoad);
  101. Debug.Log(string.Format(" 保存预知体[{0}]", IsLoad ? "成功" : "失败"));
  102. }
  103. }

案例1最终效果 

 

 案例2  代码生成器  下面有GIF演示图片

  • 在Hierarchy生成脚本指令菜单
  • 生成脚本
  • 添加标签
  • 搜索并且生成功能
  • 生成代码分为两个脚本
  • 命名空间的设置 (包括在windows窗口进行设置命名空间)
  • 生成路径选择路径修改路径和保存路径
  • 创建Prefab
  • 触发自动编译
  • 快捷键的支持
  • 生成脚本的组件类型指定
  • 自定义面板

主要的生成代码脚本 CreateComponentCode   在Editor文件夹下

  1. using System;
  2. using System.Linq;
  3. using System.IO;
  4. using System.Collections.Generic;
  5. using UnityEditor;
  6. using UnityEngine;
  7. using UnityEditor.Callbacks;
  8. using EditorExtension;
  9. public class CreateComponentCode : EditorWindow
  10. {
  11. [MenuItem("编辑器扩展/2.Build 配合 GameObject的@EdtiorExtemsion-CreateCode使用 %#T", false, 2 )]
  12. public static void OpenMenu()
  13. {
  14. GetWindow<CreateComponentCode>().Show();
  15. }
  16. [MenuItem("GameObject/@(Alt+A)EdtiorExtemsion-Add View %A", false, 0)]
  17. public static void AddView()
  18. {
  19. GameObject currentGameObject = Selection.gameObjects.First();
  20. if (currentGameObject == null)
  21. {
  22. Debug.LogError("请选择Gameobject");
  23. return;
  24. }
  25. var view = currentGameObject.GetComponent<CodeGenderateInfo>();
  26. if (!view)
  27. {
  28. currentGameObject.AddComponent<CodeGenderateInfo>();
  29. }
  30. }
  31. [MenuItem("GameObject/@(Alt+B)EdtiorExtemsion-Bind %B", false, 0)]
  32. public static void Bind()
  33. {
  34. GameObject currentGameObject = Selection.gameObjects.First();
  35. if (currentGameObject == null)
  36. {
  37. Debug.LogError("请选择Gameobject");
  38. return;
  39. }
  40. var view = currentGameObject.GetComponent<UIMark>();
  41. if (!view)
  42. {
  43. currentGameObject.AddComponent<UIMark>();
  44. }
  45. }
  46. private void OnGUI()
  47. {
  48. GUILayout.BeginHorizontal();
  49. GUILayout.Label("NameSpace");
  50. NamespaceSettingsData.Namespace = GUILayout.TextField(NamespaceSettingsData.Namespace);
  51. GUILayout.EndHorizontal();
  52. }
  53. static List<UIMarkInfo> uIMarkInfos = new List<UIMarkInfo>();
  54. [MenuItem("GameObject/@(Alt+C)EdtiorExtemsion-CreateCode %C", true, 0)]
  55. static bool ValidateCreateCode()
  56. {
  57. Debug.Log("Create Code");
  58. GameObject currentGameObject = Selection.gameObjects.First();
  59. if (currentGameObject == null)
  60. {
  61. Debug.LogError("请选择Gameobject");
  62. return false;
  63. }
  64. return currentGameObject.GetComponent<ViewMark>();
  65. }
  66. [MenuItem("GameObject/@EdtiorExtemsion-CreateCode", false, 0)]
  67. static void CreateCode()
  68. {
  69. Debug.Log("Create Code");
  70. GameObject currentGameObject = Selection.gameObjects.First();
  71. if (currentGameObject == null)
  72. {
  73. Debug.LogError("请选择Gameobject");
  74. return;
  75. }
  76. var mName = currentGameObject.name;
  77. var scriptsFolder = Application.dataPath + "/Scripts";
  78. var generateInfo = currentGameObject.GetComponent<CodeGenderateInfo>();
  79. if (generateInfo != null)
  80. {
  81. scriptsFolder = generateInfo.ScriptsFolder;
  82. }
  83. if (!Directory.Exists(scriptsFolder))
  84. {
  85. Directory.CreateDirectory(scriptsFolder);
  86. }
  87. uIMarkInfos.Clear();
  88. //搜索所有绑定
  89. SearchBinds("", currentGameObject.transform, uIMarkInfos);
  90. ComponentTemplate.Write(mName, scriptsFolder);
  91. ComponentDesignerTemplate.Write(mName, scriptsFolder, uIMarkInfos);
  92. EditorPrefs.SetString("Load", mName);
  93. //刷新目录
  94. AssetDatabase.Refresh();
  95. }
  96. static void SearchBinds(string basePath, Transform transform, List<UIMarkInfo> uIMarks)
  97. {
  98. var uiMark = transform.GetComponent<UIMark>();
  99. var isRoot = string.IsNullOrEmpty(basePath);
  100. if (uiMark && !isRoot)
  101. {
  102. uIMarks.Add(new UIMarkInfo() { FindPath = basePath, Name = transform.name, ComponentName = uiMark.ComponentName });
  103. }
  104. foreach (Transform childTrans in transform)
  105. {
  106. SearchBinds(isRoot ? childTrans.name : basePath + "/" + childTrans.name, childTrans, uIMarks);
  107. }
  108. }
  109. //系统的事件 DidReloadScripts 编译完成以后就会调用
  110. //将此属性添加到方法中,以便在重新加载脚本后获得通知。
  111. //DidReloadScript有一个提供订单索引的选项。这允许您更改调用回调的顺序。(Builtin回调的值始终为0)。
  112. [DidReloadScripts]
  113. static void AddComponent2GameObject()
  114. {
  115. Debug.Log("DidReloadScripts" + System.DateTime.Now);
  116. string generateClassGame = EditorPrefs.GetString("Load");
  117. Debug.Log(generateClassGame);
  118. if (string.IsNullOrWhiteSpace(generateClassGame))
  119. {
  120. Debug.Log("不进行操作");
  121. EditorPrefs.DeleteKey("Load");
  122. }
  123. else
  124. {
  125. Debug.Log("继续操作");
  126. // 1.获取当前项目中所有的 assembly (可以理解为 代码编译好的 dll)
  127. var assemblies = AppDomain.CurrentDomain.GetAssemblies();
  128. // 2.获取编辑器环境(dll)
  129. var defaultAssetBly = assemblies.First(assembly => assembly.GetName().Name == "Assembly-CSharp");
  130. //添加Namespace
  131. var typeName = NamespaceSettingsData.Namespace + "." + generateClassGame;
  132. Debug.Log(typeName);
  133. Type type = defaultAssetBly.GetType(typeName);
  134. Debug.Log(type);
  135. if (type == null)
  136. {
  137. Debug.Log("编译失败~");
  138. return;
  139. }
  140. var currentGameObject = GameObject.Find(generateClassGame);
  141. var scriptComponent = currentGameObject.GetComponent(type);
  142. if (!scriptComponent)
  143. {
  144. scriptComponent = currentGameObject.AddComponent(type);
  145. }
  146. var serialiedScript = new SerializedObject(scriptComponent);
  147. uIMarkInfos.Clear();
  148. //搜索所有绑定
  149. SearchBinds("", currentGameObject.transform, uIMarkInfos);
  150. foreach (UIMarkInfo markInfo in uIMarkInfos)
  151. {
  152. // var name=
  153. var name =markInfo.Name;
  154. serialiedScript.FindProperty(name).objectReferenceValue = currentGameObject.transform.Find(markInfo.FindPath).gameObject;
  155. Debug.Log(markInfo.FindPath);
  156. }
  157. var codeGenerateInfo = currentGameObject.GetComponent<CodeGenderateInfo>();
  158. if (codeGenerateInfo != null)
  159. {
  160. serialiedScript.FindProperty("ScriptsFolder").stringValue = codeGenerateInfo.ScriptsFolder;
  161. var generatePrefab = codeGenerateInfo.GeneratePrefab;
  162. var prefabForder = codeGenerateInfo.PrefabFolder;
  163. serialiedScript.FindProperty("PrefabFolder").stringValue = prefabForder;
  164. serialiedScript.FindProperty("GeneratePrefab").boolValue = generatePrefab;
  165. var fullPrefabFolder = prefabForder.Replace("Assets", Application.dataPath);
  166. serialiedScript.ApplyModifiedPropertiesWithoutUndo();
  167. if (codeGenerateInfo.GetType() == type)
  168. {
  169. }
  170. else
  171. {
  172. DestroyImmediate(codeGenerateInfo);
  173. }
  174. if (generatePrefab)
  175. {
  176. if (!Directory.Exists(fullPrefabFolder))
  177. {
  178. Directory.CreateDirectory(fullPrefabFolder);
  179. }
  180. // bool isFinish = false; //两种方法都可以
  181. // PrefabUtility.SaveAsPrefabAsset(currentGameObject, fullPrefabFolder + "/" + currentGameObject.name + ".Prefab", out isFinish);
  182. // Debug.LogFormat("保存预制体【{0}】", isFinish ? "成功" : "失败");
  183. PrefabUtility.SaveAsPrefabAssetAndConnect(currentGameObject, fullPrefabFolder + "/" + currentGameObject.name + ".prefab", InteractionMode.AutomatedAction);
  184. }
  185. }
  186. else
  187. {
  188. serialiedScript.FindProperty("ScriptsFolder").stringValue = "Assets/Scripts";
  189. serialiedScript.ApplyModifiedPropertiesWithoutUndo();
  190. }
  191. AssetDatabase.Refresh();
  192. EditorPrefs.DeleteKey("Load");
  193. }
  194. }
  195. }
  196. public class ComponentDesignerTemplate
  197. {
  198. public static void Write(string name, string scriptsFolder, List<UIMarkInfo> uIMarkInfos)
  199. {
  200. var scriptFile = string.Format("{0}/{1}.Designer.cs", scriptsFolder, name);
  201. // if (File.Exists(scriptFile))
  202. // {
  203. // File.Delete(scriptFile);
  204. // }
  205. StreamWriter writer = File.CreateText(scriptFile);
  206. writer.WriteLine("\tusing UnityEngine;");
  207. writer.WriteLine();
  208. writer.WriteLine("\t//1.请在菜单编辑器扩展/NamespaceSetting 设置命名空间");
  209. writer.WriteLine("\t//2.命名空间更改后 生成代码后 需要吧逻辑代码文件(非Designer)的命名空间手动更改");
  210. writer.WriteLine($"\tnamespace {NamespaceSettingsData.Namespace}");
  211. writer.WriteLine("\t{");
  212. writer.WriteLine($"\t\tpublic partial class {name} ");
  213. writer.WriteLine("\t\t{");
  214. foreach (UIMarkInfo uiMarkInfo in uIMarkInfos)
  215. {
  216. writer.WriteLine($"\t\tpublic {uiMarkInfo.ComponentName} { uiMarkInfo.Name};");
  217. }
  218. writer.WriteLine();
  219. writer.WriteLine("\t\t}");
  220. writer.WriteLine("\t}");
  221. writer.Close();
  222. }
  223. }
  224. public class ComponentTemplate
  225. {
  226. public static void Write(string name, string scriptsFolder)
  227. {
  228. var scriptFile = string.Format("{0}/{1}.cs", scriptsFolder, name);
  229. if (File.Exists(scriptFile))
  230. {
  231. return;
  232. }
  233. StreamWriter writer = File.CreateText(scriptFile);
  234. //保证每次生成的东西都不一样 就会执行编译操作
  235. writer.WriteLine($"//Generate ID:{Guid.NewGuid().ToString()}");
  236. writer.WriteLine("\tusing UnityEngine;");
  237. writer.WriteLine("\tusing EditorExtension;");
  238. writer.WriteLine();
  239. writer.WriteLine("\t//1.请在菜单编辑器扩展/NamespaceSetting 设置命名空间");
  240. writer.WriteLine("\t//2.命名空间更改后 生成代码后 需要吧逻辑代码文件(非Designer)的命名空间手动更改");
  241. writer.WriteLine($"\tnamespace {NamespaceSettingsData.Namespace} ");
  242. writer.WriteLine("\t{");
  243. writer.WriteLine($"\t\tpublic partial class {name} : CodeGenderateInfo");
  244. writer.WriteLine("\t\t{");
  245. writer.WriteLine("\t\tvoid Start()");
  246. writer.WriteLine("\t\t{");
  247. writer.WriteLine("\t\t//Code here");
  248. writer.WriteLine("\t\t}");
  249. writer.WriteLine("\t\t}");
  250. writer.WriteLine();
  251. writer.WriteLine("\t}");
  252. writer.Close();
  253. }
  254. }
  255. public class UIMarkInfo
  256. {
  257. public string FindPath;
  258. public string ComponentName;
  259. public string Name;
  260. }
  261. public class NamespaceSettingsData
  262. {
  263. private readonly static string NAMESPACE_KEY = Application.productName + "@NAMESPACE";
  264. public static string Namespace
  265. {
  266. get
  267. {
  268. var retNamespace = EditorPrefs.GetString(NAMESPACE_KEY, "DefaultNamespace");
  269. return string.IsNullOrEmpty(retNamespace) ? "DefaultNamespace" : retNamespace;
  270. }
  271. set { EditorPrefs.SetString(NAMESPACE_KEY, value); }
  272. }
  273. public static bool IsDefaultNamespace => Namespace == "DefaultNamespace";
  274. }

 UIMark脚本 标记

  1. using UnityEngine;
  2. [AddComponentMenu("EditorExension/Mark")]
  3. public class UIMark : MonoBehaviour
  4. {
  5. public enum GetComponentType
  6. {
  7. Transform,
  8. MeshRenderer,
  9. RectTransform,
  10. Rigibody,
  11. BoxCollider,
  12. MeshCollider,
  13. }
  14. public GetComponentType componentType = GetComponentType.Transform;
  15. public string ComponentName
  16. {
  17. get
  18. {
  19. // if (GetComponent<MeshRenderer>())
  20. // {
  21. // return "MeshRenderer";
  22. // }
  23. return componentType.ToString();
  24. }
  25. }
  26. }

ViewMark  Gameobject必须挂载  ViewMark才能进行生成脚本

  1. using UnityEngine;
  2. public class ViewMark : MonoBehaviour
  3. {
  4. }

生成脚本的配置脚本 脚本路径 生成prefab 生成brefab的路径

  1. using UnityEngine;
  2. namespace EditorExtension
  3. {
  4. [ExecuteInEditMode]
  5. public class CodeGenderateInfo : MonoBehaviour
  6. {
  7. [HideInInspector]
  8. public string ScriptsFolder;
  9. [HideInInspector]
  10. public string PrefabFolder;
  11. [HideInInspector]
  12. public bool GeneratePrefab = false;
  13. private void Awake()
  14. {
  15. ScriptsFolder = "Assets/Scripts";
  16. PrefabFolder = "Assets/Prefabs";
  17. }
  18. }
  19. }

 修改挂载代码的脚本样式 依然放在Editor下

  1. using UnityEditor;
  2. using UnityEngine;
  3. namespace EditorExtension
  4. {
  5. [CustomEditor(typeof(CodeGenderateInfo), editorForChildClasses: true)]
  6. public class CodeGenerateInfoInspector : Editor
  7. {
  8. public override void OnInspectorGUI()
  9. {
  10. base.OnInspectorGUI();
  11. var codeGenerateInfo = target as CodeGenderateInfo;
  12. GUILayout.BeginVertical("box");
  13. GUILayout.Label("代码生成部分", new GUIStyle()
  14. {
  15. fontSize = 20,
  16. fontStyle = FontStyle.Bold
  17. });
  18. GUILayout.BeginHorizontal();
  19. GUILayout.Label("Scripts Generate Folder : ", GUILayout.Width(150));
  20. codeGenerateInfo.ScriptsFolder = GUILayout.TextField(codeGenerateInfo.ScriptsFolder);
  21. GUILayout.EndHorizontal();
  22. GUILayout.BeginHorizontal();
  23. GUILayout.Label("GeneratePrefab :", GUILayout.Width(150));
  24. codeGenerateInfo.GeneratePrefab = GUILayout.Toggle(codeGenerateInfo.GeneratePrefab, "Generete Perfab");
  25. GUILayout.EndHorizontal();
  26. if (codeGenerateInfo.GeneratePrefab)
  27. {
  28. GUILayout.BeginHorizontal();
  29. GUILayout.Label("Prefab Generate Folder : ", GUILayout.Width(150));
  30. codeGenerateInfo.PrefabFolder = GUILayout.TextField(codeGenerateInfo.PrefabFolder);
  31. GUILayout.EndHorizontal();
  32. }
  33. GUILayout.EndVertical();
  34. }
  35. }
  36. }

 

案例2最终效果如下:

 

案例3重启项目   下面有GIF演示图片

  1. using UnityEditor;
  2. using UnityEngine;
  3. public class ReopenProject
  4. {
  5. [MenuItem("编辑器扩展/3.(Alt+R)ReopenProject &R", false, 3)]
  6. static void DOReopenProject()
  7. {
  8. EditorApplication.OpenProject(Application.dataPath.Replace("Assets", string.Empty));
  9. }
  10. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/141647
推荐阅读
相关标签
  

闽ICP备14008679号