未调用 ScriptableObject 的 OnEnable 函数

OnEnable function from of ScriptableObject not being called

在下面的脚本中,如何获取脚本在 Assets 文件夹中的路径?

using UnityEngine;
using System.Reflection;
using System.IO;
using UnityEditor;

[InitializeOnLoad]
public class MyWindow : ScriptableObject
{
    static string pathToScript;

    [MenuItem("Window/My Window")]
    static void Open()
    {
        // Do something with `pathToScript`
    }

    // This function is NOT called when the object is loaded.
    protected void OnEnable()
    {
        var script = MonoScript.FromScriptableObject( this );
        pathToScript = AssetDatabase.GetAssetPath( script );
    }
}

问题是 OnEnabled 它没有被调用,而且似乎获取脚本路径的唯一方法是通过 AssetDatabase.GetAssetPath,这需要一个实例。

Unity 中的版本是 5.5.0b3。

要从ScriptableObject继承时调用OnEnable()函数,您必须从ScriptableObjectclass.[=18调用CreateInstance()函数=]

[InitializeOnLoad]
public class MyWindow : ScriptableObject
{
    static string pathToScript;
    static MyWindow windowInstance;

    [MenuItem("Window/My Window")]
    static void Open()
    {
        Debug.Log("Open:" + pathToScript);

        //Do something with `pathToScript`

        if (windowInstance == null)
            windowInstance = ScriptableObject.CreateInstance<MyWindow>();

    }

    protected void OnEnable()
    {
        Debug.Log("Enabled!");
        var script = MonoScript.FromScriptableObject(this);
        pathToScript = AssetDatabase.GetAssetPath(script);
    }
}

另一种使用 ScriptableObject.CreateInstance 的方法是从另一个脚本调用它。

[InitializeOnLoad]
public class MyWindow : ScriptableObject
{
    static string pathToScript;

    [MenuItem("Window/My Window")]
    static void Open()
    {
        Debug.Log("Open:" + pathToScript);

        //Do something with `pathToScript`
    }

    protected void OnEnable()
    {
        Debug.Log("Enabled!");
        var script = MonoScript.FromScriptableObject(this);
        pathToScript = AssetDatabase.GetAssetPath(script);
    }
}

测试:

public class Test : MonoBehaviour
{
    public MyWindow myWindow;
    public void OnEnable()
    {
        if (myWindow == null)
            myWindow = Object.FindObjectOfType<MyWindow>();

        if (myWindow == null)
            myWindow = ScriptableObject.CreateInstance<MyWindow>();
    }
}

根据我的经验,仅当活动场景组件引用 SO 的实例时,才会调用脚本对象 (SO) 上的所有“事件方法”(OnEnable、Awake 等)。仅仅创建一个实例是不够的。这与“SO 生活在场景之外”的说法相反。

在编辑器中特别混乱。一个可以例如在项目的资产中创建一个 SO 的实例,它看起来就像您期望的那样调用 OnEnable、Awake...。但是一旦你在编辑器之外构建和 运行 游戏,如果 SO 实例没有分配给活动场景对象或由脚本以另一种方式加载,这些方法将不会再被调用,但只存在于资产中。

此外,我无法确定编辑器何时决定加载或 re-load 仅存在于资产中的 SO 实例。根据我的经验,这是非常不一致和不可靠的。

我读到在 2018 年版本的 Unity 之前,有更多的错误导致这些方法与 SO 一起发出,现在它更可靠,但 documentation on SOs is still inaccurate 今天会产生误导。