#c# #unity3d #unity5
#c# #unity-игровой движок
Вопрос:
В следующем скрипте, как я могу получить путь к скрипту в папке 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.
Ответ №1:
Чтобы OnEnable()
функция вызывалась при наследовании от ScriptableObject
, вы должны вызвать CreateInstance()
функцию из ScriptableObject
класса.
[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>();
}
}
Ответ №2:
По моему опыту, все «методы событий» (OnEnable, Awake, …) для скриптовых объектов (SO) вызываются только тогда, когда на экземпляр SO ссылается активный компонент сцены. Простого создания экземпляра недостаточно. Это противоречит утверждениям о том, что «SOs живут вне сцены».
Это особенно сбивает с толку в редакторе. Можно, например, создать экземпляр SO в ресурсах проекта, и это будет выглядеть так, как будто OnEnable, Awake, … вызывается, как вы и ожидали. Но как только вы создаете и запускаете игру вне редактора, эти методы вообще больше не будут вызываться, если экземпляр SO не был назначен активному объекту сцены или загружен скриптом другим способом, а просто существует в ресурсах.
Кроме того, я не смог выяснить, когда редактор решает загрузить или повторно загрузить экземпляр SO, который существует только в ресурсах. По моему опыту, это было очень непоследовательно и ненадежно.
Я читал, что было больше ошибок, из-за которых эти методы запускались с помощью SOs до версий Unity 2018 и что сейчас это более надежно, но документация по SOs по-прежнему неточна и вводит в заблуждение сегодня.
Ответ №3:
Как упоминал @Vinz, для активации SO должен соответствовать одному из следующих параметров:
- На нее ссылается MonoBehaviour или другой SO, который есть.
- Быть проверенным в редакторе
Что касается второго варианта, кажется, что при проверке один раз они рассматриваются active
для этого сеанса unity, но это очень непоследовательно.
Мое решение состоит в том, чтобы иметь MonoBehaviour, единственной задачей которого является ссылаться на скриптовые объекты. Когда это происходит в сцене и ссылается на ваш SOs, они будут последовательно вызываться в режиме редактирования и для сборок.
using UnityEngine;
public class ScriptableObjectActivator : MonoBehaviour
{
public ScriptableObject[] scriptableObjects;
void Awake() => DontDestroyOnLoad(gameObject);
}