编辑器扩展总结
工欲善其事必先利其器
引言: 在项目开发中,编辑器扩展为开发者提供了开发自定义工具的功能,让开发者更加便利地使用编辑器开发项目。如若博客中存在错误,还请不吝赐教。所有参考的博客或者视频来源将在文末展示。
开发版本: Unity 2019.4.9f1
相关博客传送门
一、编辑器开发入门
八、EditorPrefs、ScriptableObject、Undo
EditorPrefs、ScriptableObject、Undo
EditorPrefs的简单使用
Unity编辑器为开发者提供了类似PlayerPrefs的数据保存方式EditorPrefs。EditorPrefs是适用于编辑器模式,而PlayerPrefs适用于游戏运行时。
EditorPrefs提供了四种数据的保存:int,float,string,bool
通过Set方法保存下数据,下次则通过Get方法来获取数据,HasKey方法可以判断是否存在该数据的保存,删除数据调用DeleteKey方法即可。
示例:
using UnityEngine;
using UnityEditor;
public class WindowExample2 : EditorWindow
{
private static WindowExample2 window;//窗体实例
private string tempMsg;
//显示窗体
[MenuItem("MyWindow/Second Window")]
private static void ShowWindow()
{
window = EditorWindow.GetWindow<WindowExample2>("Window Example");
window.Show();
}
private void OnEnable()
{
if (EditorPrefs.HasKey("TempMsg"))
{
tempMsg = EditorPrefs.GetString("TempMsg");
}
}
private void OnGUI()
{
tempMsg = EditorGUILayout.TextField("Temp Msg", tempMsg);
if (GUILayout.Button("Save"))
{
EditorPrefs.SetString("TempMsg", tempMsg);
}
}
}
注意:需要谨慎调用EditorPrefs.DeleteAll()方法,因为该方法还可能会删除Unity编辑器自身存储的一些数据,给开发者带来不必要的麻烦。
ScriptableObject
创建ScriptableObject
只需要继承自ScriptableObject,然后在类中定义需要的数据即可。
在类前可以添加CreateAssetMenu属性,方便开发者在Project面板右键Create创建该资源。
using UnityEngine;
[CreateAssetMenu(fileName = "MyData", menuName = "Custom/MyDataAsset", order = 1)]
public class MyData : ScriptableObject
{
public int id;
public string objName;
public float value;
public bool isUsed;
}
也可以通过方法调用来创建资源,最终得到的资源是一样的,该脚本需要放在Editor文件夹中。
using System.IO;
using UnityEditor;
using UnityEngine;
public class DataEditor
{
public static void CreateAsset()
{
//生成一个实例对象
MyData asset = ScriptableObject.CreateInstance<MyData>();
//创建资源
AssetDatabase.CreateAsset(asset, Path.Combine(Application.dataPath, "MyData.asset"));
//保存资源
AssetDatabase.SaveAssets();
}
}
使用ScriptableObject
可以将创建的资源放在Resources文件夹中,通过动态的方式加载。
using UnityEngine;
public class Test : MonoBehaviour
{
private MyData myData;
private void Start()
{
myData = Resources.Load<MyData>("MyData");
Debug.Log(myData.id);
Debug.Log(myData.objName);
Debug.Log(myData.value);
Debug.Log(myData.isUsed);
}
}
数据不能保存的情况
如果遇到ScriptableObject数据不能正常保存的情况,可以尝试使用EditorUtility.SetDirty方法,标记该ScriptableObject为“脏”,然后就能正常保存了。
Undo
Undo用于编辑器模式下的撤销操作,这里介绍几种常用的API。
Undo.RegisterCreatedObjectUndo : 记录新建的对象状态,可以撤销新建的对象
Undo.RecordObject:记录对象的状态,需要在修改之前调用
Undo.AddComponent:可以撤销新挂载的组件
Undo.DestroyObjectImmediate:可以撤销删除对象的操作
Undo.SetTransformParent:可以撤销修改父对象的操作
示例:
using UnityEditor;
using UnityEngine;
public class UndoTest
{
[MenuItem("Tools/Create Obj")]
private static void CreateObj()
{
GameObject newObj = new GameObject("Undo");
Undo.RegisterCreatedObjectUndo(newObj, "CreateObj");
}
[MenuItem("Tools/Move Obj")]
private static void MoveObj()
{
//获取选中的场景对象
Transform trans = Selection.activeGameObject.transform;
if (trans)
{
Undo.RecordObject(trans, "MoveObj");
trans.position += Vector3.up;
}
}
[MenuItem("Tools/AddComponent Obj")]
private static void AddComponentObj()
{
//获取选中的场景对象
GameObject selectedObj = Selection.activeGameObject;
if (selectedObj)
{
Undo.AddComponent(selectedObj,typeof(Rigidbody));
}
}
[MenuItem("Tools/Destroy Obj")]
private static void DestroyObj()
{
//获取选中的场景对象
GameObject selectedObj = Selection.activeGameObject;
if (selectedObj)
{
Undo.DestroyObjectImmediate(selectedObj);
}
}
[MenuItem("Tools/SetParent Obj")]
private static void SetParentObj()
{
//获取选中的场景对象
Transform trans = Selection.activeGameObject.transform;
Transform root = Camera.main.transform;
if (trans)
{
Undo.SetTransformParent(trans, root, trans.name);
}
}
}