Search
Write a publication
Pull to refresh
1
0

Пользователь

Send message
Я думаю нет единого лучшего способа маштабирования все зависит от задач, но растягивания/сжатия по двум осям конечно лучше избегать.
Да да да. Поэтому всегда стараюсь разделять по возможности хранение данных и сигналетоны исполнители.
Просто когда вижу недоработанные сигналетоны где попало это вгоняет в уныние. А многие копируют код из статей.

Спасибо за продуктивную дискуссию.
Да но для таких случаев я не использую mono signaleton а предпочитаю другие реализации.
Остальное чисто эстетические соображения, больше связанные с конкретными решениями задач и архитектурой))
В любом случае эта реализация нравится гораздо больше чем у автора статьи.
9. По этой причине я почти полностью отказался от варианта создания ссылки если исходный объект не найден.
Либо объект есть на сцене либо это ошибка. Это решает почти все проблемы которые рассмотрены нами.
Кончено если нам не требуется отложенная инициализация, что как я думаю бывает редко.
6. Согласен мой косяк вычислял в голове забыл один пункт приведения обобщенных типов все верно прошу прощения.)
9. Я имею ввиду другое допустим у нас есть класс ScoreCollector на сцене он одиночка и подсчитывает очки.
В него сериализуемы настройки конкретного уровня по стоимости и тд.
Есть класс которому для начала работы нужны данные из одиночки в Awake.
Когда создается объект вызывается его метод Awake и порядок их вызова не определен (если не указать, что есть зло).
Он запросит данные раньше чем объект присутствующий на сцене пропишет себя (порядок вызова Awake не определен) и будет создан объект одиночки с данными по умолчанию.
Объект получает неправильные данные по умолчанию и работает некорректно.
Далее исходный объект одиночка чистит ссылку.
А программисты ищут несколько часов в чем фаил и только потом задумаются об одиночке.

Если что пример надуманный важна его суть.)

2. Кстати для локальных и глобальных одиночек у меня два разных базовых класса.
В моей абстракции тут нет связи является.
5. В этом пункте возможен фаил при использовании стороннего кода)
6. Кончено реализация Pure c# мне известна, я просто говорю, что нет случая когда неявное приведение вызовет исключение и в 51 строчке класса одиночке не требуется использовать оператор as.
9. Да помрет. Но может привести к ошибочным данным по умолчанию в классе вызвавшем ссылку при инициализации в Awake. А поиск ошибки виновного после 20к кода дело не простое.
Да я это и говорю, что операция == для System.Object (я сделал явное приведение) значительно быстрее чем метод Get и вызов кода движка. Поэтому можно убрать дополнительную переменную и так код будет читабельные.

Ну это мое скромное мнение)
Кстати по поводу ссылки в 7 Transform это класс, думаю можно убрать дополнительную переменную флаг.
Время доступа к Transform значительно превысит операции вида ((System.Object)transform == null).
Точнее сказать можно по результатам теста.
Большинство вопросов сводится, а если 10 — й программист с недосыпа нахалтурит)
Кстати бывает часто, а ловить такие ошибки бывает сложно.

1. Специально уничтожать его ни кто не будет. Просто это может привести к сложно диагностируемой ошибке.
2. Да я знаю DontDestroyOnLoad(gameObject). Но в этой реализации его нет и я бы предпочел возлагать такую ответственность не на программиста реализующего наследника, а на себя.
3. По возможности я стараюсь обходится минимум тестов раинтайма, это медленнее и черновато ошибками.
Модульное тестирование на сцене в основном требуется для объектов с физикой и анимацией и редко когда встречал другие случаи. Но за это я плачу увеличением кода и тд.
4. Я имел ввиду если у нас несколько одинаковых объектов добавлены на сцену по ошибке)
5. Если реализация это позволяет, а проект большой как показывает практика это происходит.
6. Просто если мы используем подход class Test = Signaleton <>, то у нас нет необходимости _instance = this as T,
а можно _instance = this.
7. Спасибо огромное ознакомлюсь. Если сильно важна производительность можно делать и без Одиночки.
Статик классы и ScriptableObjects могут гарантировать одну ссылку.
Конечно все зависит от задач все сделать и есть вещи которые они не покрывают.
8. Кстати под подобные вещи сделал отдельную библиотеку, чтоб при копировании не ошибаться)
9. Я имел ввиду ситуацию когда объект не наследник одиночки, а просто Mono в своём Awake затребует ссылку.
Конечно можно запретить это делать всем, но кто — то обязательно не удержится).
Например у нас менеджер звука и один объект на сцене хочет взять его параметры в Awake вместо Start.
10. Я имел в виду у нас добавлен на сцену один объект наследник Одиночки.
Он запускает Awake определенный вами и прописывает ссылку в _instance.
Объект на сцене обращается к методу get instance.
Так как флаг _instanceCreated не поставлен в true происходит тяжелый поиск на сцене по типу.

Огромное спасибо за ответ.
Еще забыл.

9. Что будет если кто — то попросит ссылку на одиночку в своем Awake до того как там пропишется наш объект?
10. После присваивание в Awake мы не ставим флаг создания ссылки в true, у нас будет повторный поиск объекта на сцене?

Еще раз спасибо за уделенное время.
Посмотрел реализацию по ссылке возникло несколько вопросов.

1. Что произойдет если кто — то уничтожит объект одиночки и _instanceCreated created будет true?
2. При смене сцен точно произойдет уничтожение объекта, но так как у нас класс статический будет то же, что в 1.
3. Как быть с модульными тестами (с 5.3 они не работают в плей моде)?
4. В методе Awake будут уничтожены все повторные копии, это не приводило к сложно диогностируемым ошибкам?
5. Как боретесь с проблемой утечки памяти, когда кто — то повесил ссылку на одиночку в кеше?
6. Вы используете одиночку не только в контексте наследования (зачем _instance = this as T если этот awake только у прямых потомков и у нас произойдет стандартное неявное приведение ссылочного типа потомка к родителю)?
7. Какой прирост производительности даёт этот способ над сравнением при переопределенной операции ==?
8. Была ли ситуации когда == был BottleNeck?

Заранее спасибо за ответ и уделенное время.)
К сожалению данная реализация ни как не защищает от удаления.
А значит это произойдет по чей — то ошибке.
При закрытии приложения объекты будут уничтожаться в произвольном порядке.
И тут при данной реализации можно получить опять не предсказуемую работу приложения.
Если быть точным я говорил только про случай когда на наш сигналетон есть ссылки из других объектов.

Еще раз проверил этот факт в юнити 5.4 и создал два скрипта Mono.
Первый с полем public MonoBehaviour testObject и Destroy(testObject) по нажатию кнопки.
После чего в билде смотрел вывод до и после уничтожения выражений

testObject == null
(System.Object)testObject == null и
!testObject.

До уничтожения объекта вывод false false false.
После удаления вывод true false true.
Так что все сказанное о сторонних ссылках и проверке верно и для билда. Юнити уничтожает внутреннее представление объекта из пула,
а так как у нас есть ссылка на объект GC не помечает объект подлежащий сбору мусора. В результате имеем мемори лик.
И это справедливо не только для редактора.

Если вы это имели ввиду.
Ну статья про то, как сделать работу геим дизанера проще, я думаю он работает в редакторе.
А не очевидная логика работы в редакторе прилагается 100 процентов.
Не за что.
Если будет возможность поправите код.
И хорошо будет отметить, что код if (!_instance) равноправен (_instance == null) с теми же оговорками о перегрузке.

Удачи. Еще раз спасибо за внимание)
Хочу добавить некоторые замечания.

1.Проверка ссылки на null в юнити дял UnityEngine.Object перегружена и вернет будет true даже если объект существует.
Если не брать это во внимание возможна утечка памяти (удалили одиночку, создали, а ссылки повисли в других объектах).

2. Если использовать Unity Test Tools с версии 5.3, то тесты проводятся на той же сцене,
что открыта в текущий момент и возможны серьезные проблемы при тестировании.

3. Для статических объектов геим дизайнеру совсем не обязательно лезть в код. Все зависит от того, как будут храниться данные.
Можно сделать отдельный сериализуемый класс данных и EditorWindow с любыми изысками в GUI. И по моему мнению для работы с подсистемами Editor Windows более удобны (не нужен лишний хлам на сценах).

4. В данной реализации Одиночки дважды запускается тяжелые функции FindObjectsOfType(typeof(T)) и FindObjectOfType(typeof(T)),
хотя достаточно первой из них.

5. Использовать в Одиночке Awake таким образом очень опасно.
Если порядок вызова Awake не определен, то кто — то может запросить Одиночку,
до того как там пропишется объект со сцены => гарантированный еррор.
Дочерний класс может захотеть иметь свой Awake.
Код получения ссылки дублирует код Awake.
Достаточно вместо тяжелого GetComponent написать this.

6. В качестве базы для одиночки всегда следует рассмотреть ScriptableObject. Получить две копии одного и того же объекта по моей памяти невозможно + он не тянет хлам в виде трансформа и тд.

Спасибо за внимание)
Данный метод несмотря на свою простоту имеет явные недостатки.
1. Низкая производительность.
2. Для добавления новых меток надо создавать новые сферы (лишний хлам в префабах).
3. Добавление новых типов меток и их фильтров для различных игроков сильно затруднено.
4. Для смены внешнего вида метки необходимо создавать меш!
5. Лишние объекты на каждой сцене => лишняя сложность => сложнее разработка и поддержка.
6. Сложно тестировать => больше возможных багов (с учетом 3).

По моему мнению нужно сразу избегать подобных решений.
Как вариант делаем Mono скрипт MiniMap с возможностью добавления и удаления Mono объектов типа MapMarker.
MiniMap отслеживает координаты MapMarker`s и основываясь на внутренней логике возвращает относительные координаты объектов.
За прорисовку карты отвечает третий скрипт который не входит в систему мини карты (GUI отделено от логики).

Более подробного описания сделать сложно. Точный вид классов сильно зависит от задачи решаемых разработчиком.

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity