前言
2018的Unity中Prefab的显示会跳到另外的一个界面,在prefab的面板上有“Open Prefab”的按钮。这里用脚本实现这个按钮的功能。
效果
环境
脚本
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PreafabTest : EditorWindow
{
[MenuItem("Tool/PreafabTest")]
private static void Opne()
{
EditorWindow.GetWindow<PreafabTest>("Prefab界面测试");
}
private void OnEnable()
{
Selection.selectionChanged += SelectionChangeCallback;
}
private void OnDestroy()
{
Selection.selectionChanged -= SelectionChangeCallback;
}
private void OnGUI()
{
GUILayout.BeginHorizontal("helpbox");
GUILayout.Label(Selection.activeGameObject == null? "当前没有选中任何对象": "当前选中:" + Selection.activeGameObject.name, "box");
if (Selection.activeGameObject != null)
{
bool isPreviewSceneObject = EditorSceneManager.IsPreviewSceneObject(Selection.activeGameObject);
GUILayout.Label(isPreviewSceneObject ? "Prefab环境" : "非Prefab环境", "box");
}
GUILayout.EndHorizontal();
if (GUILayout.Button("Open Prefab"))
{
OpenPrefab();
}
if (GUILayout.Button("Close Prefab"))
{
OpenMain();
}
}
private void OpenPrefab()
{
GameObject uiPrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Prefab/UI.prefab");
AssetDatabase.OpenAsset(uiPrefab);
}
private void OpenMain()
{
StageUtility.GoToMainStage();
}
private void SelectionChangeCallback()
{
this.Focus();
}
}
技术点
- 进入Prefab界面并不是切换了一个场景,所以不要使用SceneManger的功能
- 在Prefab场景里获取的对象并不是预制体,所以使用PrefabUtility里面的函数进行判断会失败,要使用脚本中的EditorSceneManager。
- 判断是否在Prefab场景中直接判断GameObject,而不要用IsPreviewScene。因为真正的previeScene是SceneManager里面的私有对象。
题外
实现的时候一开始没想到这么简单的办法,用了反射调用OpenPrefabMode.OpenPrefab。功能是实现了,但是在Prefab的界面中编译的话,SceneView会报错。原因是里面会创建 StageNavigationManager的单例,这只是临时的对象,并不是Unity中真正的那个对象。所以重编译一切状态就都改变了。看了别的脚本,使用创建单例的办法的地方有很多。当在使用反射创建或改变状态时,编译导致异常的话,有可能就是这个原因。
我使用的是ILSpy反编译UnityEditor.dll得到的脚本,功能真的很强大,调用和引用都能看到。dll的路径:“本地Unity安装路径/Editor/Data/Managed”。