簡體   English   中英

未調用 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()函數,您必須從ScriptableObject類調用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 實例沒有分配給活動場景對象或由腳本以其他方式加載,則這些方法將不再被調用,而只是存在於資產。

此外,我無法確定編輯器何時決定加載或重新加載僅存在於資產中的 SO 實例。 根據我的經驗,這非常不一致和不可靠。

我讀到有更多的錯誤導致這些方法在 2018 版 Unity 之前與 SO 一起發出,現在它更可靠,但關於 SO 的文檔今天仍然不准確和誤導。

正如@Vinz 提到的,SO 必須滿足以下條件之一才能被激活:

  1. 被 MonoBehaviour 或其他 SO 引用。
  2. 在編輯器中進行檢查

關於第二個選項,似乎一旦檢查它們被認為對該統一會話active ,但這是非常不一致的。

我的解決方案是擁有一個 MonoBehaviour,其唯一工作是引用 Scriptable Objects。 當它在場景中並引用您的 SO 時,它們將始終在編輯模式和構建中調用。

using UnityEngine;


public class ScriptableObjectActivator : MonoBehaviour
{
  public ScriptableObject[] scriptableObjects;
  void Awake() => DontDestroyOnLoad(gameObject);
}

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM