【问题标题】:How to avoid the OnValidate method from being called in PREFAB MODE?如何避免在 PREFAB MODE 中调用 OnValidate 方法?
【发布时间】:2019-10-02 22:34:23
【问题描述】:

我的场景中有一个游戏对象作为实例预制件。我在 OnValidate 方法中添加了一个具有带有验证逻辑的单一行为的组件。但我注意到,当我处于预制模式时,也会调用 OnValidate 方法。

所以我希望只有在我的场景中处于编辑器模式时才验证实例预制件的某些变量,因为它们的值取决于场景中的其他对象。

所以我想知道如何避免在预制模式下调用 OnValidate 方法。是否嵌套。

所以我尝试从这里引用:https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs 编写我的方法,但是当预制件嵌套在另一个预制件中时它失败了。

class Helper
{
    //It doesn't work. It failed when the prefab is nested in another prefab.
    public static bool PrefabModeIsActive(Gameobject object)
    {
        UnityEditor.Experimental.SceneManagement.PrefabStage prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetPrefabStage (gameObject);
        if(prefabStage != null)
            return true;
        if(UnityEditor.EditorUtility.IsPersistent(gameObject))
        {
            return true;
        }

        return false;
    }
}

我的单一行为

class MyMonobehaviour : MonoBehaviour
{
    public MyScriptableObject entity;

# IF UNITY_EDITOR
    void OnValidate()
    {
        //So I expected that logic onvalidate is called only on instance prefab in my scene.
        if(!Helper.PrefabModeIsActive(gameObject) && entity == null)
        {
            entity = Resources.Load<MyScriptableObject>("MyAssetScene/" + SceneManager.GetActiveScene().name) as MyScriptableObject;
        }
    }
#endif
}

所以我希望 onvalidate 逻辑仅在我的场景中的实例预制上调用。

更新 1

另一种似乎可行的解决方案是检查游戏对象内场景中的一些值:

bool PrefabModeIsActive(Gameobject gameobject)
{
    return String.IsNullOrEmpty(gameObject.scene.path)
    && !String.IsNullOrEmpty(gameObject.scene.name);
}

但我不确定是否有一些案例研究表明这可能不是真的

【问题讨论】:

    标签: unity3d


    【解决方案1】:

    以下是我在所有项目中使用的几行代码以避免这个烦人的功能。

    #if UNITY_EDITOR
    using UnityEditor.Experimental.SceneManagement;
    using UnityEditor;
    #endif
    
    void OnValidate()
        {
    #if UNITY_EDITOR
            PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
            bool isValidPrefabStage = prefabStage != null && prefabStage.stageHandle.IsValid();
            bool prefabConnected = PrefabUtility.GetPrefabInstanceStatus(this.gameObject) == PrefabInstanceStatus.Connected;
            if (!isValidPrefabStage && prefabConnected)
            {
                //Variables you only want checked when in a Scene
            }
    #endif
            //variables you want checked all the time (even in prefab mode)
       }
    

    这有两件事。一,在预制模式下它不会检查变量,并且在预制模式有效之前它也不会检查变量。第二个好处你不会经常看到,但有时当你打开一个新项目,或删除你的库文件夹并需要重新导入资产时,你会在 preab 有效之前触发 OnValidate(),甚至只放置“isPrefabConnected”不会工作。

    【讨论】:

    • 第二个好处在与ExecuteAlwaysExecuteInEditMode 一起使用时非常有用。否则,当您打开项目时,位于文件夹中的所有预制件也会执行 OnValidate。仍然在每个 OnValidate 的开头添加如此多的代码使得很难跟踪 OnValidate 何时执行。不幸的是,当 Unity 扩展预制件编辑时,这是一个糟糕的设计。
    【解决方案2】:

    您可以尝试使用PrefabStageUtility's GetCurrentPrefabStage 方法。

    例如

        bool PrefabModeIsActive()
        {
            return UnityEditor.Experimental.SceneManagement.
                PrefabStageUtility.GetCurrentPrefabStage() != null;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-19
      • 1970-01-01
      • 2010-12-05
      • 2017-09-24
      相关资源
      最近更新 更多