Я видел несколько видео и учебных пособий по созданию одноэлементных объектов в Unity, в основном для a GameManager
, которые, похоже, используют разные подходы к созданию и проверке синглтона.
Есть ли правильный, или, скорее, предпочтительный подход к этому?
Два основных примера, с которыми я столкнулся:
Первый
public class GameManager
{
private static GameManager _instance;
public static GameManager Instance
{
get
{
if(_instance == null)
{
_instance = GameObject.FindObjectOfType<GameManager>();
}
return _instance;
}
}
void Awake()
{
DontDestroyOnLoad(gameObject);
}
}
второй
public class GameManager
{
private static GameManager _instance;
public static GameManager Instance
{
get
{
if(_instance == null)
{
instance = new GameObject("Game Manager");
instance.AddComponent<GameManager>();
}
return _instance;
}
}
void Awake()
{
_instance = this;
}
}
Основное различие, которое я вижу между ними:
Первый подход будет пытаться перемещаться по стеку игровых объектов, чтобы найти экземпляр GameManager
которого, даже если это случается (или должно происходить только один раз), кажется, что это может быть очень неоптимизировано, так как сцены увеличиваются в размерах во время разработки.
Кроме того, первый подход помечает объект как не подлежащий удалению, когда приложение меняет сцену, что обеспечивает сохранение объекта между сценами. Второй подход, кажется, не придерживается этого.
Второй подход кажется странным, так как в случае, когда экземпляр является нулевым в получателе, он создаст новый GameObject и назначит ему компонент GameManger. Однако это не может быть выполнено без предварительного подключения этого компонента GameManager к объекту в сцене, поэтому это вызывает у меня некоторую путаницу.
Есть ли какие-либо другие подходы, которые будут рекомендованы, или гибрид двух вышеупомянутых? Существует множество видео и учебных пособий, касающихся синглетонов, но все они отличаются настолько, что трудно провести какие-либо сравнения между ними и, следовательно, сделать вывод о том, какой из них является наилучшим / предпочтительным подходом.
источник
GameManager
нужно делать, а в том, как обеспечить наличие только одного экземпляра объекта и как лучше это обеспечить.Ответы:
Это зависит, но обычно я использую третий метод. Проблема с методами, которые вы использовали, состоит в том, что в случае, если объект включен для начала, он не удалит их из дерева, и они все равно могут быть созданы путем создания слишком большого количества вызовов, что может привести к путанице.
Проблема обеих ваших реализаций заключается в том, что они не уничтожают объект, созданный позже. Это могло бы сработать, но в работу можно было бы добавить гаечный ключ, что могло бы привести к очень трудной отладке ошибок в будущем. Обязательно проверьте в Awake, существует ли уже экземпляр, и если да, уничтожьте новый экземпляр.
источник
OnDestroy() { if (this == _instance) { _instance = null; } }
, если вы хотите иметь разные экземпляры в каждой сцене.Instance
свойство стирается. Пример такого, который не может быть найден ни в одном из ответов ниже или wiki.unity3d.com/index.php/Singleton (хотя он может быть устаревшим, но, похоже, работает из-за моих экспериментов с ним)Вот краткое резюме:
Так что, если все, что вас волнует, это глобальный доступ, все три получают то, что вам нужно. Использование шаблона Singleton может быть немного двусмысленным в отношении того, хотим ли мы создать ленивый экземпляр, принудительную уникальность или глобальный доступ, поэтому обязательно тщательно продумайте, почему вы выбираете singleton, и выберите реализацию, которая обеспечивает правильность этих функций, а не чем использование стандарта для всех трех, когда вам нужен только один.
(например, если в моей игре всегда будет GameManager, может быть, мне плевать на ленивую реализацию - может быть, меня интересует только глобальный доступ с гарантированным существованием и уникальностью - в этом случае статический класс очень точно дает мне именно эти функции, без соображений загрузки сцены)
... но определенно не используйте метод 1, как написано. Поиск можно упростить с помощью метода Awake () в Method2 / 3, и, если мы будем держать менеджера в разных сценах, мы, скорее всего, захотим убить дубликаты, если мы когда-нибудь загрузимся между двумя сценами с менеджером, уже находящимся в них.
источник
Лучшая реализация общего
Singleton
шаблона для Unity, о котором я знаю, - это (конечно) моя собственная.Он может делать все , и делает это аккуратно и эффективно :
Другие преимущества:
OnApplicationQuit()
. (И делает это с одним глобальным флагом, вместо каждого отдельного типа, имеющего свой собственный)И потому что делиться заботой , вот оно:
источник
MonoBehaviour
, и я считаю, что любой класс, используемый Unity напрямую, вообще.SampleSingletonClass : Singleton
,SampleSingletonClass.Instance
возвращается сSampleSingletonClass does not contain a definition for Instance
.Singleton<>
класс. Вот почему универсальный является дочерним по отношению к базовомуSingleton
классу.Я просто хотел бы добавить, что может быть полезно позвонить,
DontDestroyOnLoad
если вы хотите, чтобы ваш синглтон сохранялся в разных сценах.источник
Другим вариантом может быть разделение класса на две части: обычный статический класс для компонента Singleton и MonoBehaviour, который действует как контроллер для экземпляра singleton. Таким образом, у вас есть полный контроль над конструкцией синглтона, и он будет сохраняться во всех сценах. Это также позволяет вам добавлять контроллеры к любому объекту, который может нуждаться в данных синглтона, вместо того, чтобы копаться в сцене, чтобы найти определенный компонент.
источник
Вот моя реализация одноэлементного абстрактного класса ниже. Вот как это соотносится с 4 критериями
У этого есть несколько других преимуществ по сравнению с некоторыми другими методами здесь:
FindObjectsOfType
который является убийцей производительностиЭто потокобезопасный
источник
OnApplicationQuitCallback
и ,OnEnableCallback
какabstract
вместо того , чтобы просто пустыеvirtual
методы? По крайней мере, в моем случае у меня нет никакой логики выхода / включения, а пустое переопределение кажется грязным. Но я могу что-то упустить.OnApplicationQuitCallback
иOnEnableCallback
: использование его в качестве виртуальных методов делает его менее очевидным. Может быть, немного странное мышление, но насколько я помню, это было моим разумом.На самом деле существует псевдо-официальный способ использования Singleton в Unity. Вот объяснение, в основном создайте класс Singleton и сделайте так, чтобы ваши скрипты наследовали от этого класса.
источник
Я буду бросать свою реализацию также для будущих поколений.
Для меня эта строка
Destroy(gameObject.GetComponent(instance.GetType()));
очень важна, потому что однажды я оставил одноэлементный скрипт на другом игровом объекте на сцене, и весь игровой объект был удален. Это уничтожит компонент, только если он уже существует.источник
Я написал одноэлементный класс, который позволяет легко создавать одноэлементные объекты. Это скрипт MonoBehaviour, так что вы можете использовать сопрограммы. Это основано на этом статье в Unity Wiki , и я добавлю возможность создать его из Prefab позже.
Таким образом, вам не нужно писать коды Singleton. Просто скачайте этот базовый класс Singleton.cs , добавьте его в свой проект и создайте его, расширяя его:
Теперь ваш класс MySingleton является синглтоном, и вы можете вызывать его по экземпляру:
Вот полный учебник: http://www.bivis.com.br/2016/05/04/unity-reusable-singleton-tutorial/
источник