Моя фабрика создает экземпляры на основе свойств ScriptableObject ("SO").
Мне бы не хотелось добавлять в Factory каждую новую созданную мной SO. Так что в идеале что-то вроде каждого SO, регистрирующегося на фабрике при пробуждении, было бы замечательно.
Я исследовал два подхода, один из которых имеет фабрику , а не быть MonoBehaviour:
public class ThingFactory
{
private static ThingFactory instance = null;
public static ThingFactory Instance
{
get
{
if (instance != null)
{
return instance;
}
else
{
instance = new ThingFactory();
return instance;
}
}
private set
{
instance = value;
}
}
public ThingFactory()
{
}
public void RegisterThing(ThingType thingType)
{
GameObject newThing = MonoBehaviour.Instantiate(thingType.prefab, Camera.main.transform);
newThing.SetActive(true);
newThing.GetComponentInChildren<Text>().text = thingType.name;
newThing.GetComponent<Image>().sprite = thingType.sprite;
}
}
public abstract class ThingType: ScriptableObject
{
public GameObject prefab;
public Sprite sprite;
#if UNITY_EDITOR
#else
public void OnEnable()
{
Debug.Log("Enabling ThingType of type: " + this.name);
ThingFactory.Instance.RegisterThing(this);
}
#endif
}
[CreateAssetMenu(menuName = "Things/ThingA")]
public class ThingAType : ThingType
{
}
Три проблемы с этим подходом.
Во-первых, OnEnable вызывается из редактора, я справился с этим с помощью if UNITY_EDITOR.
Вторая проблема заключается в том, чтоэтот OnEnable вызывается только тогда, когда сцена имеет MonoBehaviour, ссылающийся на этот актив ScriptableObject, что не всегда так. Даже сейчас, когда я воспроизвожу поведение в небольшом проекте, я не могу точно определить требования для вызова OnEnable.
Третья проблема заключается в том, что яполучая это исключение:
Некоторые объекты не были очищены при закрытии сцены. (Вы породили новые GameObjects из OnDestroy?) Изображение prefabOfThing (clone)
Я не понимаю это исключение, для меня имеет смысл, что если OnEnable вызывается до загрузки сцены, а затем SO уничтожаетсяпри загрузке сцены.
Второй подход заключается в том, чтобы фабрика была моно-поведением и делала магию отражения.
В пробуждении есть что-то вроде:
var thingTypes = Assembly.GetAssembly(typeof(ThingType)).GetTypes().Where(thingType => thingType.IsClass && !thingType.IsAbstract && thingType.IsSubclassOf(typeof(ThingType)));
Но теперь я застрял - у меня есть классы для ThingTypes, например, ThingAType, но не отдельные SO.
И еще одной проблемой является то, что OnEnable вызывается до пробуждения моей фабрики, поэтому он еще не инициализирован. Порядок выполнения скрипта не улучшает ситуацию.
Я не знаю хорошего способа создания заводских предварительных пробуждений, я подумал об использовании чего-то вроде следующего. Но проблема с этим подходом состоит в том, что экземпляр MonoBehaviourFactory не будет иметь ссылки, извлеченные из инспектора, такие как someInspectorText.
public static MonoBehaviourFactory Instance
{
get
{
if (instance != null)
{
return instance;
}
else
{
instance = /*SomeRandomGameObject*/.AddComponent<MonoBehaviourFactory>();
return instance;
}
}
private set
{
instance = value;
}
}
private void Awake()
{
if (instance != null && instance != this)
{
Destroy(this.gameObject);
}
else
{
instance = this;
}
}
public Text someInspectorText = null;
Как я могу использовать OnEnable для объектов ScriptableObject, чтобы заполнить мою фабрику типамиэто обойдется?