目录
前言与展示
灵感来源于MStudio老师的麦田物语教程中的ItemEditor
编辑器扩展的很方便,在项目中但是不够通用(需要在脚本中一个个数据绑定和回调)其实左边的ListView可以保留,右边直接用Unity默认的Inspector绘制就好了(需要用到IMGUIContainer组件),随后写好create asset和delete asset的对应方法,这样就可以管理不同的so和prefab资产。编辑器窗口见下图:
so资产的管理:
也可以用来管理prefab,双击左边的某一个物件可直接打开这个预制体,并显示这个预制体的monobehaviour脚本的监视器窗口。
这里展示一下其中部分源码
部分源码
IMGUIContainer调用Inspector绘制
protected virtual void ShowInspector(UnityEngine.Object uOjbect)
{
var container = rootVisualElement.Q<IMGUIContainer>();
container.Clear();
this.selection = uOjbect;
textField.value = uOjbect?.name;
if (uOjbect == null)
return;
Editor editor;
editor = Editor.CreateEditor(uOjbect);
container.onGUIHandler = () =>
{
if (uOjbect != null)
{
//editor.DrawDefaultInspector(); //Unity默认Inspector
editor.OnInspectorGUI(); //这个可以走Odin插件的绘制
}
};
}
创建ListView,绑定选中资产,打开预制体的方法
protected virtual void CreateListView<T>(List<T> resources) where T : UnityEngine.Object
{
if (resources == null || resources.Count == 0)
return;
var item = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/SugarzoTool/Editor/UIBuilder/Item.uxml");
Func<VisualElement> makeItem = () =>
{
return item.Instantiate();
};
Action<VisualElement, int> bindItem = (e, i) =>
{
if (i >= resources.Count || resources[i] == null)
{
listView.Remove(e);
return;
}
e.Q<Label>().text = resources[i].name;
};
listView.makeItem = makeItem;
listView.bindItem = bindItem;
listView.itemsSource = resources;
listView.selectionType = SelectionType.Single;
listView.onItemsChosen += obj =>
{
if (obj?.First() != null && AssetDatabase.CanOpenAssetInEditor((obj.First() as UnityEngine.Object).GetInstanceID()))
{
AssetDatabase.OpenAsset(obj.First() as UnityEngine.Object);
//如果当前是预制件模式
if (PrefabUtility.IsPartOfAnyPrefab(obj.First() as UnityEngine.Object) && PrefabStageUtility.GetCurrentPrefabStage() is PrefabStage prefabStage)
{
ShowInspector(prefabStage.prefabContentsRoot);
}
}
};
listView.onSelectionChange += obj =>
{
Selection.activeObject = obj.First() as UnityEngine.Object;
ShowInspector(obj.First() as UnityEngine.Object);
};
listView.Rebuild();
}
创建Asset资产(so和prefab)
public virtual UnityEngine.Object CreateAsset()
{
if (FileCheck() == false)
return null;
UnityEngine.Object obj = null;
if(useDefaultCreateFunction)
{
if (assetType == AssetType.ScriptableObject)
{
var so = ScriptableObject.CreateInstance(assetSo.GetType());
so.name = defaultName;
var createPath = $"{assetsFolderPath}/{so.name}.asset";
int tot = 0;
while (File.Exists(createPath) && tot++ < 1000)
{
so.name = defaultName + tot.ToString();
createPath = $"{assetsFolderPath}/{so.name}.asset";
}
AssetDatabase.CreateAsset(so, createPath);
obj = so;
}
if (assetType == AssetType.Prefab)
{
var newGo = Instantiate(assetGo);
newGo.name = defaultName;
var createPath = $"{assetsFolderPath}/{newGo.name}.asset";
int tot = 0;
while (File.Exists(createPath) && tot++ < 1000)
{
newGo.name = defaultName + tot.ToString();
createPath = $"{assetsFolderPath}/{newGo.name}.asset";
}
PrefabUtility.SaveAsPrefabAsset(newGo, assetsFolderPath + "/" + newGo.name + ".prefab");
obj = PrefabUtility.LoadPrefabContents(assetsFolderPath + "/" + newGo.name + ".prefab");
DestroyImmediate(newGo);
}
}
AssetDatabase.SaveAssets();
OnAssetCreate?.Invoke();
OnAssetChange?.Invoke();
return obj;
}
public virtual void DeleteAsset(string assetFilePath)
{
if (FileCheck() == false)
return;
if(useDefaultDeleteFunction)
{
AssetDatabase.DeleteAsset(assetFilePath);
AssetDatabase.Refresh();
}
OnAssetDelete?.Invoke();
OnAssetChange?.Invoke();
}
完整源码GitHub
GitHub - sugarzo/Unity_DataEditor: 使用UI Toolkit制作的Editor编辑器,管理项目指定类型的so和prefab资源