赞
踩
持续更新中。。
- using (new EditorGUILayout.VerticalScope("box")) 加个框
- type = (enumType)EditorGUILayout.EnumPopup("枚举", type);
复合元素 要显示在面板使用[serializable]
比如一个类 就是这么简单,但加了之后就不能为Null了
- [Serializable]
- public class TestClass
- {
- public enum TestType
- {
- a,
- b,
- }
- public TestType testType;
- public bool testBool = false;
- public float testFloat = 1;
- }
如果要重绘这个类...使用CustomPropertyDrawer,
- [CustomPropertyDrawer(typeof(UScript))]
- public class UScriptDrawer : PropertyDrawer
- {
- public override void OnGUI(Rect pos, SerializedProperty property, GUIContent label)
- {
- var targetObj = property.serializedObject.targetObject;
- var asset = targetObj as 持有他的对象类型(如Asset);
- }
-
- public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
- {
- //如有需要返回Height
- }
- }
用代码重新绘制了Inspector,并赋值,所以注意不能使用Ctrl+Z,要做Undo?...
如加个按钮
- [CustomEditor(typeof(UrScript))]
- public class UrScriptEditor : Editor
- {
- UrScript script;
-
- private void OnEnable()
- {
- script = (UrScript)target;
- }
-
- public override void OnInspectorGUI()
- {
- base.OnInspectorGUI();
- serializedObject.Update();
- EditorGUI.BeginChangeCheck();
- if (script.boolValue)
- {
- EditorGUI.indentLevel++;
- EditorGUILayout.LabelField("Label面板提示1");
- EditorGUILayout.HelpBox("HelpBox面板提示2", MessageType.Warning);
- EditorGUILayout.PropertyField(任意变量);
- EditorGUI.indentLevel--;
- }
- else
- {
- EditorGUILayout.LabelField("面板提示");
- 数组变量.arraySize = EditorGUILayout.IntField("Length", uscript.arraySize);
- for (int i = 0; i < 数组变量.arraySize; i++)
- EditorGUILayout.PropertyField(数组变量.GetArrayElementAtIndex(i));
- }
-
- if (GUILayout.Button("创建对象"))
- {
- TestScript myScript = (TestScript)target;
- Debug.LogError(myScript.self.gameObject.GetComponent<Light>());
- }
- if (EditorGUI.EndChangeCheck())
- UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
-
- serializedObject.ApplyModifiedProperties();
- }
- }
- Editor newEditor;
- public override void OnInspectorGUI()
- {
- serializedObject.Update();
-
- EditorGUI.BeginChangeCheck();
- EditorGUILayout.PropertyField(m_Prop, new GUIContent("套娃对象"));
- if (EditorGUI.EndChangeCheck() || assetEditor == null)
- {
- newEditor= CreateEditor(m_Prop.objectReferenceValue);
- }
- newEditor.OnInspectorGUI();
-
- serializedObject.ApplyModifiedProperties();
- }
选择层
FindProperty("xx1").FindPropertyRelative("xx2").intValue = UnityEditorInternal.InternalEditorUtility.ConcatenatedLayersMaskToLayerMask(EditorGUILayout.MaskField("", UnityEditorInternal.InternalEditorUtility.LayerMaskToConcatenatedLayersMask(xx2), UnityEditorInternal.InternalEditorUtility.layers));
发现了自定义更简洁的方法 参考Odin插件,
新增LabelText标签。可以放到属性上,显示出中文
- public class LabelTextAttribute:PropertyAttribute
- {
- public string label;
- public string showCondition;
- public string editorCondition;
-
- public LabelTextAttribute(string label, string showCondition = null, string editorCondition = null)
- {
- this.label = label;
- this.showCondition = showCondition;
- this.editorCondition = editorCondition;
- }
- }
还可以针对一些非Unity类
- using UnityEditor;
- using UnityEngine;
-
- [CustomPropertyDrawer(typeof(LabelTextAttribute),false)]
- public class LabelDrawer : PropertyDrawer
- {
- public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
- {
- var attr = attribute as LabelTextAttribute;
- label.text = attr.label;
-
- // 如果字段为false则不显示
- if (!string.IsNullOrEmpty(attr.showCondition))
- {
- var field = property.serializedObject.FindProperty(attr.showCondition);
- if (!field.boolValue)
- return;
- }
-
- // 是否能编辑
- var notEdit = false;
- if (!string.IsNullOrEmpty(attr.editorCondition))
- {
- if (attr.editorCondition == "false")
- notEdit = true;
- }
- if (notEdit)
- GUI.enabled = false;
- EditorGUI.PropertyField(position, property, label);
-
- if (notEdit)
- GUI.enabled = true;
- }
-
- //如果不显示返回没间隔
- public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
- {
- LabelTextAttribute labelAttr = (LabelTextAttribute)attribute;
- var showCondition = property.serializedObject.FindProperty(labelAttr.showCondition);
- if (showCondition != null)
- {
- bool show = showCondition.boolValue;
- if (!show)
- return -EditorGUIUtility.standardVerticalSpacing;
- }
- return EditorGUI.GetPropertyHeight(property, label);
- }
- }
场景:[CustomEditor(typeof(UnityEditor.SceneAsset))]
txt/byte : TextAsset
模型 : ?
文件夹和一些unity不支持的文件类型:[CustomEditor(typeof(UnityEditor.DefaultAsset))]
- public override void OnInspectorGUI()
- {
- string path = AssetDatabase.GetAssetPath(target);
- if (path.EndsWith(".bytes") && path.Contains("Animations"))
- {
- using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open)))
- {
- int length = reader.ReadInt32();
- EditorGUILayout.LabelField("长度:" + length);
- for (int i = 0; i < length; i++)
- {
- EditorGUILayout.LabelField("X:" + (reader.ReadInt32() / 10000f).ToString() +
- " Y:" + (reader.ReadInt32() / 10000f).ToString() +
- " Z:" + (reader.ReadInt32() / 10000f).ToString());
- if (i != 0 && (i + 1) % 10 == 0)
- EditorGUILayout.LabelField("----" + (i + 1) + "----");
- }
- }
- }
- else
- base.OnInspectorGUI();
- }
https://github.com/756915370/UnityEditorExtension
需要Rect、带输入、有默认间隔
不需要Rect、自动排布、不带输入、所以没有很大间隔、自定义间隔
一般结合BeginArea、BeginScrollView、BeginHorizontal、BeginVertical使用
带输入,EditorGUILayout会间隔比较大
包围框
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.EndVertical();
附加侧边小按钮
- Operation op = (Operation)EditorGUILayout.EnumPopup(GUIContent.none, op, "ShurikenDropdown");
- switch (op)
- {
- case Operation.one:
- break;
- case Operation.two:
- break;
- }
类似打快照一样
Undo - Unity 脚本 API
- //继承IHasCustomMenu
- public void AddItemsToMenu(GenericMenu menu) {
- menu.AddItem(new GUIContent("A"), false, () => { Debug.Log("A"); });
- }
- GUIStyle HelpStyle = new GUIStyle("IconButton");
- HelpStyle.normal.background = EditorGUIUtility.FindTexture("d__Help");
- void ShowButton(Rect position)
- {
- if (lockButtonStyle == null)
- lockButtonStyle = new GUIStyle();
- lockButtonStyle.normal.background = EditorGUIUtility.FindTexture("d__Help");
- if (GUI.Button(position, GUIContent.none, lockButtonStyle))
- {
-
- }
- }
分上下区域
- public class MyEditorWindow : EditorWindow
- {
- private float splitBarHeight = 5.0f; //拖动条的高度
- private float topPanelHeight = 300.0f; //上部分区域的初始高度
-
- [MenuItem("Window/My Editor Window")]
- static void ShowWindow()
- {
- EditorWindow.GetWindow(typeof(MyEditorWindow));
- }
-
- void OnGUI()
- {
- // 上部分区域
- Rect topPanelRect = new Rect(0, 0, position.width, topPanelHeight);
- GUILayout.BeginArea(topPanelRect, GUI.skin.box);
- GUILayout.Label("Top Panel");
- GUILayout.EndArea();
-
- // 拖动条区域
- Rect splitBarRect = new Rect(0, topPanelHeight, position.width, splitBarHeight);
- EditorGUIUtility.AddCursorRect(splitBarRect, MouseCursor.ResizeVertical);
- if (Event.current.type == EventType.MouseDown && splitBarRect.Contains(Event.current.mousePosition))
- {
- GUIUtility.hotControl = GUIUtility.GetControlID(FocusType.Passive);
- }
- if (GUIUtility.hotControl == GUIUtility.GetControlID(FocusType.Passive) && Event.current.isMouse)
- {
- topPanelHeight = Event.current.mousePosition.y;
- Repaint();
- }
- if (Event.current.rawType == EventType.MouseUp)
- {
- GUIUtility.hotControl = 0;
- }
- GUI.Box(splitBarRect, "");
-
- // 下部分区域
- Rect bottomPanelRect = new Rect(0, topPanelHeight + splitBarHeight, position.width, position.height - topPanelHeight - splitBarHeight);
- GUILayout.BeginArea(bottomPanelRect, GUI.skin.box);
- GUILayout.Label("Bottom Panel");
- GUILayout.EndArea();
- }
- }
画个横线
GUILayout.Label("", new GUIStyle { normal = new GUIStyleState { background = EditorGUIUtility.whiteTexture } }, GUILayout.Height(1));
Scene Mode | Prefab Mode | |
Hierarchy 里操作的对象本质 | Prefab Instance 实例 | Assets里的UnityEngine.Object文件 |
Apply 保存过程 | 从Instance写入到Asset里的Prefab文件 | 直接操作Assets里的Prefab文件 |
SetDirty 脚本修改Prefab上的对象 | EditorUtility.SetDirty(Object) | 暂无(目前U3D问答上很多人在问) |
设置场景Dirty | EditorSceneManager.GetActiveScene() | PrefabStageUtility.GetCurrentPrefabStage().scene) |
Apply时的回调 | PrefabUtility.prefabInstanceUpdated | PrefabStage.prefabSaving |
此外Project面板也分为one/two column也许也要写不同的代码?
Scene/Hierarchy (prefab mode场景会get source失败,因为操作的是Instance不是prefab所以在)
- Object source = PrefabUtility.GetCorrespondingObjectFromSource (TObject componentOrGameObject);
- string path = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(source);
Prefab Mode
string path = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage().prefabAssetPath;
Project (本质操作Asset)
string assetPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
组件(例如Aniamtor)
AssetDatabase.GetAssetPath(Object);
Selection.activeObject
直接修改Asset
使用AssetDatabase.LoadAssetAtPath后
直接操作:
①删Object使用GameObject.DestroyImmediate(go,true)
②改变脚本属性记得SetDirty否则保存可能无效
- static void MakePrefab()
- {
- string selectPath = AssetDatabase.GUIDToAssetPath(Selection.assetGUIDs[0]);
- var files = Directory.GetFiles(selectPath, "*.prefab", SearchOption.AllDirectories);
- foreach (var path in files)
- {
- GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
- GameObject delect = prefab.transform.Find("delect");
- if (delect != null)
- {
- GameObject.DestroyImmediate(delect, true);
- AssetDatabase.SaveAssets();
- AssetDatabase.Refresh();
- }
- }
- }
问题:使用Asset如果删除一些组件要使用DestroyImmediate,当目标是一个ParticleSystem时,Material不会一同被删除,使用实例化解决。
首先实例化要用↓
- GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
- GameObject go = PrefabUtility.InstantiatePrefab(prefab);//如果使用Instantiate会丢失链接 因为算是clone
go.GetComponentsInChildren<MonoBehaviour>().Any(mono => mono == null))
bool succe = PrefabUtility.SaveAsPrefabAsset(inst, prefabPath);
这个时候想要进行一些删除或者SetParent操作,会提示不允许。
要断链root,使用PrefabUtility.UnpackPrefabInstanceAndReturnNewOutermostRoots(go, PrefabUnpackMode.OutermostRoot);
prefab监听改变
如果想要添加代码 有人也遇到和我一样的问题 想使用SaveAsPrefabAsset改 但是发现不起效 链接
根据我蹩脚的英语理解 官方技术人员的意思大概就是这个delegate不对SaveAsPrefabAsset起效
要用SaveAsPrefabAssetAndConnect
习得Delay大发
- using UnityEditor;
- using UnityEngine;
-
- public class ApplyPrefab
- {
- [InitializeOnLoadMethod]
- static void StartInitializeOnLoadMethod()
- {
- PrefabUtility.prefabInstanceUpdated = delegate (GameObject instance)
- {
- //prefab保存的路径
- Debug.Log(PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(instance));
- };
- }
- }
- [UnityEditor.MenuItem("Tools/Apply Selected Prefabs")]
- static void ApplySelectedPrefabs(){
- //获取选中的gameobject对象
- GameObject [] selectedsGameobject= Selection.gameObjects;
- GameObject prefab = PrefabUtility.FindPrefabRoot (selectedsGameobject[0]);
- for (int i = 0; i < selectedsGameobject.Length; i++) {
- GameObject obj=selectedsGameobject[i];
- UnityEngine.Object newsPref= PrefabUtility.GetPrefabObject(obj);
- //判断选择的物体,是否为预设
- if(PrefabUtility.GetPrefabType(obj) == PrefabType.PrefabInstance){
- UnityEngine.Object parentObject = PrefabUtility.GetPrefabParent(obj);
- //string path = AssetDatabase.GetAssetPath(parentObject);//获取路径
- PrefabUtility.ReplacePrefab(obj,parentObject,ReplacePrefabOptions.ConnectToPrefab);//替换预设
- AssetDatabase.Refresh();//刷新
- }
- }
- }
- static void Scan()
- {
- ScanFolder(EditorUtil.GetSelectedFilePath());
- }
- static void ScanFolder(path)
- {
- DirectoryInfo folder = new DirectoryInfo(path);
- FileSystemInfo[] files = folder.GetFileSystemInfos();
- for(int i = 0;i<files.Length;i++)
- {
- if (files[i] is DirectoryInfo)
- ScanFolder(files[i].FullName);
- else
- ScanFile(files[i].FullName);
- }
- }
- static void ScanFile(path)
- {
- if(path.EndsWith("prefab"))
- {
- path = path.Substring(path.IndexOf("Assets"));
- GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
- }
- }
- [InitializeOnLoad]
- internal class PrefabExtension
- {
- //依赖Instance修改,直接修改Asset无效
- static PrefabExtension()
- {
- PrefabUtility.prefabInstanceUpdated += OnPrefabInstanceUpdate;
- }
- static void OnPrefabInstanceUpdate(GameObject instance)
- {
- EditorApplication.delayCall += delegate()
- {
- if (instance == null)
- return;
- var asset = PrefabUtility.GetCorrespondingObjectFromSource(instance);
- if (asset == null)
- return;
- var assetPath = AssetDatabase.GetAssetPath(asset);
- PrefabUtility.prefabInstanceUpdated -= OnPrefabInstanceUpdate;
- //Do something
- PrefabUtility.SaveAsPrefabAssetAndConnect(instance, assetPath, InteractionMode.UserAction);
- PrefabUtility.prefabInstanceUpdated += OnPrefabInstanceUpdate;
- };
- }
- }
-
- public class Example : AssetPostprocessor
- {
- void OnPostprocessPrefab(GameObject g)
- {
- Debug.LogError(g.name);
- }
- [InitializeOnLoadMethod]
- static void StartInitializeOnLoadMethod()
- {
- PrefabUtility.prefabInstanceUpdated = delegate (GameObject instance)
- {
- //prefab保存的路径
- var sourrce = PrefabUtility.GetCorrespondingObjectFromSource(instance);
- var path = AssetDatabase.GetAssetPath(sourrce);
- if (PrefabUtility.IsAnyPrefabInstanceRoot(instance))
- PrefabUtility.UnpackPrefabInstance(instance, PrefabUnpackMode.OutermostRoot, InteractionMode.AutomatedAction);
- //do something
- };
- }
- }
- [InitializeOnLoad]
- public class PrefabSaveListener : UnityEditor.AssetModificationProcessor
- {
- private static string[] OnWillSaveAssets(string[] paths)
- {
- // 在这里可以添加一些逻辑代码,比如检查预制的属性或组件等
-
- foreach (string path in paths)
- {
- // Example: 更新预制体的某个属性
- var asset = AssetDatabase.LoadAssetAtPath<GameObject>(path);
- if (asset != null)
- {
- // 修改预制体的属性
- }
- }
- return paths;
- }
- }
- public class SaveScene :UnityEditor.AssetModificationProcessor {
- static public void OnWillSaveAssets(string[]names)
- {
- foreach (string name in names)
- {
- if (name.EndsWith (".unity")) {
- Scene scene = SceneManager.GetSceneByPath (name);
- Debug.Log ("保存场景 :" + scene.name);
- }
- }
- }
- }
快捷键api参考:Unity - Scripting API: MenuItem
- public class testTools
- {
- [MenuItem("Tools/Hello %#a")]
- static void Hello()
- {
- Debug.Log("hello");
- }
-
- [MenuItem("Assets/Hello")] //如果放在Assets下右键文件夹也会出现
- static void Hello2()
- {
- Debug.Log("hello2");
- }
- }
-
- 快捷键
- % - CTRL
- # - Shift
- & - Alt
- LEFT/RIGHT/UP/DOWN - 光标键
- F1…F12
- HOME,END,PGUP,PDDN
- Example
- public static void ClearConsole()
- {
- Assembly assembly = Assembly.GetAssembly(typeof(SceneView));
- Type logEntries = assembly.GetType("UnityEditor.LogEntries");
- MethodInfo clearConsoleMethod = logEntries.GetMethod("Clear");
- clearConsoleMethod.Invoke(new object(), null);
- }
- //复制
- GUIUtility.systemCopyBuffer = "test";
- //粘贴 或者 Ctrl+V
- string str = GUIUtility.systemCopyBuffer;
SceneView.lastActiveSceneView.Repaint();
在Scene预览模型 例子:
- GameObject preview;
- void OnDrawGizmos()
- {
- if(!Application.isPlaying)
- {
- if(preview == null)
- Resources.Load<GameObject>("path");
- else
- {
- MeshFilter[] meshFilters = mPreview.GetComponentsInChildren<MeshFilter>();
- for(int i = 0; i < meshFilters.Length; i++)
- {
- Gizmos.DrawMesh(meshFilter[i].sharedMesh,
- transform.position + mPreview.transform.GetChild(i).position * scale,
- mPreview.transform.GetChild(i).rotation,
- transform.localScale)
- }
- }
- }
- }
- using UnityEngine;
-
- [CreateAssetMenu(fileName = "FileName", menuName = "ScriptableObjects/menuName", order = 1)]
- public class YourScriptObject : ScriptableObject
- {
- [Header("大小")]
- public int Size = 16;
- }
-
- public class ReflectionTools
- {
- public static void Call(string typeName, string methodName, params object[] args)
- {
- Call<object>(typeName, methodName, args);
- }
-
- public static T Call<T>(string typeName, string methodName, params object[] args)
- {
- System.Type type = System.Type.GetType(typeName);
- T defaultValue = default(T);
- if (null == type) return defaultValue;
-
- System.Type[] argTypes = new System.Type[args.Length];
- for (int i = 0, count = args.Length; i < count; ++i)
- {
- argTypes[i] = null != args[i] ? args[i].GetType() : null;
- }
- MethodInfo method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, argTypes, null);
- if (null == method)
- {
- Debug.LogError(string.Format("method {0} does not exist!", methodName));
- return defaultValue;
- }
- object result = method.Invoke(null, args);
- if (null == result)
- return defaultValue;
- if (!(result is T))
- {
- Debug.LogError(string.Format("method {0} cast failed!", methodName));
- return defaultValue;
- }
- return (T)result;
- }
- }
还可以把asmdef命名为内部internal 例如Unity.InternalAPIEditorBridge.001
这样可以直接访问
InternalsVisibleToAttribute Class (System.Runtime.CompilerServices) | Microsoft Learn
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。