【UnityEditor】通过PrefabStage监听打开/关闭Prefab编辑场景事件,通过PrefabStageUtility获取当前正在编辑的Prefab

957 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

可以用于扩展编辑器、制作关卡编辑器等工具。

实现步骤:

  • Editor下,通过PrefabStage监听打开/关闭Prefab编辑场景事件
  • 通过PrefabStageUtility获取当前正在编辑的Prefab
  • SceneView.duringSceneGui获取场景视图GUI
  • 在场景视图GUI中绘制自定义按钮,快捷操作Prefab

关键API:

  • 引入命名空间:Experimental.SceneManagement.PrefabStage
  • PrefabStage:包含场景的编辑环境。打开Scene场景时,PrefabStage里包含了所有当前打开的场景;打开Prefab时,PrefabStage里包含了一个预览场景,仅用于Prefab编辑。
  • PrefabStage.prefabStageOpened(PrefabStage prefabStage):PrefabStage打开回调;
  • PrefabStage.prefabStageClosing(PrefabStage prefabStage):PrefabStage关闭回调;
  • PrefabStageUtility.GetCurrentPrefabStage:获取当前打开的PrefabStage;
  • PrefabStage.prefabContentsRoot:加载PrefabAsset的根节点;
  • PrefabStage.scene:预览场景;
  • SceneView.duringSceneGui(SceneView sceneView):场景视图调用OnGUI的回调;

注意!PrefabStage是实验性接口,将来可能会被更改或删除,使用前务必先确认。

测试代码:

using UnityEngine;
using UnityEditor;
using UnityEditor.Experimental.SceneManagement;

public class LevelPrefabSceneExtension
{

    [InitializeOnLoadMethod]
    public static void Init()
    {
        //打开Prefab事件
        PrefabStage.prefabStageOpened += OnPrefabStageOpened;
        //关闭Prefab事件
        PrefabStage.prefabStageClosing += OnPrefabStageClosing;
    }

    private static void OnPrefabStageOpened(PrefabStage prefabStage)
    {
        //if(prefabStage.prefabAssetPath.StartsWith("Assets/···"))
        if(prefabStage.prefabAssetPath.EndsWith("Cube.prefab"))
        {
            //在场景视图绘制按钮
            SceneView.duringSceneGui -= DuringSceneGui;
            SceneView.duringSceneGui += DuringSceneGui;
        }
    }
    private static void OnPrefabStageClosing(PrefabStage prefabStage)
    {
        SceneView.duringSceneGui -= DuringSceneGui;
    }

    private static Rect buttonRect = new Rect(5,50,125,20);
    private static void DuringSceneGui(SceneView sceneView)
    {
        Handles.BeginGUI();
        if(GUI.Button(buttonRect,"仅在打开Cube时显示按钮",GUI.skin.box))
        {
            CheckPrefab();
        }
        Handles.EndGUI();
    }

    private static void CheckPrefab()
    {
        //获取当前打开的Prefab
        PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
        if(prefabStage == null)
            return;
        GameObject prefabRoot = prefabStage.prefabContentsRoot;
        if(prefabRoot == null)
            return;

        Debug.Log(prefabRoot);
    }
}

API扩展:

字段:

  • PrefabStage.prefabAssetPath:当前打开的Prefab所在的路径;
  • PrefabStage.prefabContentsRoot:当前加载Prefab的根节点;
  • PrefabStage.scene:PrefabStage的预览场景;
  • PrefabStage.stageHandle:PrefabStage对应的StageHandle。 函数:
  • PrefabStage.ClearDirtiness:清除脏标记;
  • PrefabStage.IsPartOfPrefabContents:GameObject是否是Prefab的一部分(即嵌套子节点)。 回调:
  • PrefabStage.prefabSaved:Prefab保存完成回调;
  • PrefabStage.prefabSaving:Prefab保存开始回调;
  • PrefabStage.prefabStageClosing:PrefabStage关闭回调;
  • PrefabStage.prefabStageDirtied:PrefabStage设置脏标记回调;
  • PrefabStage.prefabStageOpened:PrefabStage打开回调。