Да и два одинаковых объекта с одинаковым набором приоритетов будут "проходить друг через друга". Представьте тех же персов, собранных из приоритетов, проходящих друг через друга. Ноги, руки, тело - все будет пересекаться между двумя персами, хотя они должны выглядеть как одно целое. В общем, для большинства кейсов такое не подходит
Можно добавить именованные слои. Каждый объект лежит на своем слое, а внутри слоя сортируется в порядке иерархии. В целом, это равносильно первоначальному обходу иерархии, просто проблемы локализуются на уровне слоев. Уже проще, но все же не идеально
Можно добавить именованные слои. Каждый объект лежит на своем слое, а внутри слоя сортируется в порядке иерархии. В целом, это равносильно первоначальному обходу иерархии, просто проблемы локализуются на уровне слоев. Уже проще, но все же не идеально
На мой взгляд самая правильная система - это комбинирование всех. В ней есть слои, и первоначально задан их порядок. Один слой ни при каких обстоятельствах не может "залезть" на другой слой. Затем по-дефолту все сортируется в порядке иерархии, тк в большинстве случаев это и нужно. И для отдельных кейсов задается числовой приоритет, который как бы "вытаскивает" объект из иерархии, и сортирует в рамках слоя в зависимости от его приоритета. У дефолтных объектов приоритет 0, таким образом можно что-то сделать ниже, а что-то выше
Однако у такой системы получается серьезный минус - сложность. Все нужно держать в голове, кто от кого наследуется, какой приоритет, слой и тд.
У меня уже давно была идея сделать два режима отображения иерархии в сцене: реальная иерархия и очередь отрисовки. Собственно, почему бы не вывести дерево очередности отрисовки камер, слоев и объектов там? К тому же, через drag'n'drop это очередность можно будет редактировать. Захотел поменять слой - перетащил объект в нужный слой. Захотел чтобы он был в подиерархии другого объекта - просто перетащил. И мгновенно увидел результат, дерево с порядком отрисовки сразу поменялось и ты видишь актуальный результат
При этом все так же можно редактировать и обычную иерархию сцены, и слои, и приоритеты. Просто теперь есть специальное место, где явно задается порядок отрисовки сцены. То что нужно было держать в голове - теперь на экране
У меня уже давно была идея сделать два режима отображения иерархии в сцене: реальная иерархия и очередь отрисовки. Собственно, почему бы не вывести дерево очередности отрисовки камер, слоев и объектов там? К тому же, через drag'n'drop это очередность можно будет редактировать. Захотел поменять слой - перетащил объект в нужный слой. Захотел чтобы он был в подиерархии другого объекта - просто перетащил. И мгновенно увидел результат, дерево с порядком отрисовки сразу поменялось и ты видишь актуальный результат
При этом все так же можно редактировать и обычную иерархию сцены, и слои, и приоритеты. Просто теперь есть специальное место, где явно задается порядок отрисовки сцены. То что нужно было держать в голове - теперь на экране
Окошко еще не финальное, но уже вполне получается проверить концепцию.
Цветом выделены разные батчи, цифра справа - числовой приоритет, если задан. В руте показаны камеры (на скрине не видно), под каждой камерой - список слоев, которые она рендерит. В слое объекты и их дети. Выглядит все просто и понятно. А главное drag'n'drop интуитивен: ты хочешь чтобы объект рисовался в определенном месте - просто перетаскиваешь его туда
Цветом выделены разные батчи, цифра справа - числовой приоритет, если задан. В руте показаны камеры (на скрине не видно), под каждой камерой - список слоев, которые она рендерит. В слое объекты и их дети. Выглядит все просто и понятно. А главное drag'n'drop интуитивен: ты хочешь чтобы объект рисовался в определенном месте - просто перетаскиваешь его туда
Расскажу о демке и о том, над чем сейчас работаю уже в течение последних 3х месяцев
Сейчас я интегрирую о2 в чужой движок.
Для чего это вообще нужно? Допустим, у вас есть проект, работающий на кастомном С++ движке. Проект живой, зарабатывает денег, и выкинуть на помойку истории его нельзя. При этом свое решение уже обросло костылями, оно становится совсем не удобным, и что-то исправть все сложнее и сложнее. При этом перелезть на Unity или другой движок не реально. Нужно переписывать проект с нуля некогда, нужно переучивать команду, да и вообще не факт что с перфомансом все будет в порядке.
Обычно студиям в такой ситуации не остается ничего, как пытаться улучшить свой движок, добавив в него хоть какие-то редакторы, ускоряющие разработку. Но по факту там тратятся человеко-годы, и получается все равно "не Unity".
В этом как раз моя идея, интегрировать о2 в эти движки, добавляя нужный функционал в старые проекты. По-сути это то, чем я занимался в Playrix в команде VSO (это внутренний движок) - мы прокачали старые проекты новыми тулзами, похожими на Unity. В итоге это дало буст разработки на всех проектах в разы, сохраняя старый код и перфоманс в игре
Для чего это вообще нужно? Допустим, у вас есть проект, работающий на кастомном С++ движке. Проект живой, зарабатывает денег, и выкинуть на помойку истории его нельзя. При этом свое решение уже обросло костылями, оно становится совсем не удобным, и что-то исправть все сложнее и сложнее. При этом перелезть на Unity или другой движок не реально. Нужно переписывать проект с нуля некогда, нужно переучивать команду, да и вообще не факт что с перфомансом все будет в порядке.
Обычно студиям в такой ситуации не остается ничего, как пытаться улучшить свой движок, добавив в него хоть какие-то редакторы, ускоряющие разработку. Но по факту там тратятся человеко-годы, и получается все равно "не Unity".
В этом как раз моя идея, интегрировать о2 в эти движки, добавляя нужный функционал в старые проекты. По-сути это то, чем я занимался в Playrix в команде VSO (это внутренний движок) - мы прокачали старые проекты новыми тулзами, похожими на Unity. В итоге это дало буст разработки на всех проектах в разы, сохраняя старый код и перфоманс в игре
Собственно сейчас я работаю над интеграцией о2 в чужой движок. На самом деле он уже интегрирован и сейчас идет работа над оптимизацией. Оптимизация довольно интересная, как и тот продукт, над которым я работаю. Это - гемблинг, игровые автоматы проще говоря, на стареньком железе с 10-ти летним 32битным ARM, линуксом под капотом и ультра-дерьмовой видеокартой.
Сейчас все на этапе эксперимента, попробовать интегрировать о2 в их движок и добиться приемлемого перфоманса на их железе. Это позволит им делать игры быстрее, верстать графику в редакторе. А скрипты на JS помогут в портировании игр под WEB. В общем, почти мгновенная прокачка тулсета студии за счет внедрения о2
Сейчас все на этапе эксперимента, попробовать интегрировать о2 в их движок и добиться приемлемого перфоманса на их железе. Это позволит им делать игры быстрее, верстать графику в редакторе. А скрипты на JS помогут в портировании игр под WEB. В общем, почти мгновенная прокачка тулсета студии за счет внедрения о2
Этап интеграции прошел относительно быстро. Пришлось научить все компилироваться вместе, разрулить зависимости в CMAKE, да и собственно перевести о2 на CMAKE. Поддержать платформенные API под линукс и OpenGLES. Поправить ошибки gcc (скажите мне про кросс-компиляемость С++ ага). Основная работа связана со специфичным железом, компиляцией под него и значительной переделкой рендера.
Видюха там и правда слабая и привередливая. Например, очистка стенсил-буффера, который ты даже не юзаешь, может дать +20 FPS. До сих пор идет поиск всех крупиц, неочевидно съедающих перфоманс. Правильная запись в буффер вершин, сжатие DXT, все что угодно может влиять. Отличный способ прокачать свои знания в графике
И, как говорится, все в кассу. В целом эта работа дала понять как именно идет процесс интеграции в сторонний движок. Так скажем собраны самые первые грабли. Все улучшения применимы ко всем платформам, и улучшая что-то одно, улучшаешь везде. Да и просто интересно повозиться с такими интересным железом
Видюха там и правда слабая и привередливая. Например, очистка стенсил-буффера, который ты даже не юзаешь, может дать +20 FPS. До сих пор идет поиск всех крупиц, неочевидно съедающих перфоманс. Правильная запись в буффер вершин, сжатие DXT, все что угодно может влиять. Отличный способ прокачать свои знания в графике
И, как говорится, все в кассу. В целом эта работа дала понять как именно идет процесс интеграции в сторонний движок. Так скажем собраны самые первые грабли. Все улучшения применимы ко всем платформам, и улучшая что-то одно, улучшаешь везде. Да и просто интересно повозиться с такими интересным железом
Кажется что это может быть неплохим способом раскрутить движок. Можно найти несколько таких проектов, интегрировать о2 в их движки, и работать как команда движка на аутсорсе. Владельцам проектов выгодно - они получают полноценную движковую команду за небольшую сумму, готовую быстро решить технически проблемы, и большой буст эффективности разработки засчет Unity-like подхода. Для развития о2 тоже выгодно - он будет применяться в реальных задачах, оттачивать и тестироваться
В этом время можно продвигать движок на открытых площадках. Он будет открытый, бесплатный, и проверенный реальными задачами. И если все пойдет крайне удачно, можно монетизировать набранную аудиторию через условно-платные сервисы в виде модулей для движка: система покупок, аналитика и тп. Думаю сейчас серьезный движок для мобильных 2D игр вполне может откусить 10% от рынка: https://www.linkedin.com/pulse/game-engines-market-2023-size-professional-survey/
Так что если интересно пописать двигло - велкам, заняться можно чем хочешь ;)
В этом время можно продвигать движок на открытых площадках. Он будет открытый, бесплатный, и проверенный реальными задачами. И если все пойдет крайне удачно, можно монетизировать набранную аудиторию через условно-платные сервисы в виде модулей для движка: система покупок, аналитика и тп. Думаю сейчас серьезный движок для мобильных 2D игр вполне может откусить 10% от рынка: https://www.linkedin.com/pulse/game-engines-market-2023-size-professional-survey/
Так что если интересно пописать двигло - велкам, заняться можно чем хочешь ;)
Linkedin
Game Engines Market 2023: Size, Professional Survey, and Forecast to 2030
The global game engines market was valued at $2.8 billion in 2020 and is expected to reach $5.
image_2023-08-16_19-36-49.png
19.9 KB
когда рефакторишь какое-нибудь serious shit
o2 dev
image_2023-08-16_19-36-49.png
Пару слов о "грандиозном рефакторинге". Его целью была переработка системы слоев в движке. Эта итак большая задача зацепила еще одну большую задачу - переработка ивентов акторов и компонент, по типу OnStart, Awake из юнити.
Казалось бы, что в них сложного. Особенно, когда пользуешься Unity3D, они воспринимаются как что-то нативное и само собой разумеющееся. Ну просто есть эти функции, их можно использовать.
Но когда сам реализуешь все эти ивенты, становится понятно какая работа происходит "под капотом", и чего стоят эти простые методы. На самом деле у них есть нюансы: OnStart вызывается на первом Update, раньше всех Awake. Всякие OnDestroy, OnEnabled/Disabled тоже имеют свои нюансы.
Рассмотрим такую последовательность вызовов во времени жизни актора/компоненты на сцене:
OnInitialized -> OnAddToScene -> OnEnabled -> OnStart -> OnUpdate -> OnDisabled -> OnRemoveFromScene -> OnDestroy
Но когда сам реализуешь все эти ивенты, становится понятно какая работа происходит "под капотом", и чего стоят эти простые методы. На самом деле у них есть нюансы: OnStart вызывается на первом Update, раньше всех Awake. Всякие OnDestroy, OnEnabled/Disabled тоже имеют свои нюансы.
Рассмотрим такую последовательность вызовов во времени жизни актора/компоненты на сцене:
OnInitialized -> OnAddToScene -> OnEnabled -> OnStart -> OnUpdate -> OnDisabled -> OnRemoveFromScene -> OnDestroy
В какой момент какой вызывать? Окей, начнем с простого, OnInitialized. "Ну это просто, из конструктора вызвал да и все" - можно подумать. А теперь рассмотрим подробнее.
Есть базовый класс Actor, от него наследуется, например, Widget. При конструировании Widget, сначала вызовется конструктор базового класса, Actor'а. Из которого мы попытаемся вызвать OnInitialized. Но проблема в том, что в это время класса Widget все еще нет, тк в данный момент конструируется класс Actor. В итоге перегружать OnInitialized нет смысла, тк объект просто не готов. Значит его нужно как-то вызвать "извне".
То же самое и с OnDestroy. Если его вызывать из деструктора ~Actor, то в этот момент части класса Widget уже попросту нет, и ничего там задестроить не получится.
Выход таков - копить во внешнем контейнере список создавшихся и удаляемых акторов. Сама сцена отлично подходит, и в ней есть метод Update, в котором можно перебрать список и вызвать OnInitialized/OnDestroy перед вызовом Update у иерархии акторов.
Окей, поехали дальше - OnStart. Тут тоже не прокатит вызвать в OnInitialized, тк мы держим в голове правило "OnStart вызывается всегда после OnInitialized". Делаем так же, храним отдельный список, формируем его сразу же из списка OnInitialized и так же вызываем перед апдейтом всей сцены
Есть базовый класс Actor, от него наследуется, например, Widget. При конструировании Widget, сначала вызовется конструктор базового класса, Actor'а. Из которого мы попытаемся вызвать OnInitialized. Но проблема в том, что в это время класса Widget все еще нет, тк в данный момент конструируется класс Actor. В итоге перегружать OnInitialized нет смысла, тк объект просто не готов. Значит его нужно как-то вызвать "извне".
То же самое и с OnDestroy. Если его вызывать из деструктора ~Actor, то в этот момент части класса Widget уже попросту нет, и ничего там задестроить не получится.
Выход таков - копить во внешнем контейнере список создавшихся и удаляемых акторов. Сама сцена отлично подходит, и в ней есть метод Update, в котором можно перебрать список и вызвать OnInitialized/OnDestroy перед вызовом Update у иерархии акторов.
Окей, поехали дальше - OnStart. Тут тоже не прокатит вызвать в OnInitialized, тк мы держим в голове правило "OnStart вызывается всегда после OnInitialized". Делаем так же, храним отдельный список, формируем его сразу же из списка OnInitialized и так же вызываем перед апдейтом всей сцены
С остальными - OnAddToScene/RemoveFromScene; OnEnabled/OnDisabled - просто очень осторожно и аккуратно делаем логику вызовов. Накосячить с несовпадением пары вызово OnEnabled/Disabled довольно легко, нужно быть довольно внимательным
А што там со слоями? Ну, они как раз таки опираются на эту систему ивентов. У компоненты есть примерно такой же список ивентов. Для слоев самыми значимыми являются OnEnabled/Disabled и OnAddToScene/RemoveFromScene. В них происходит "регистрация" и "разрегистрация" объекта из списка отрисовки.
При регистрации проверяется логика наследования слою родителя. Если наследуется, значит регистрируемся в списке родителя, и родитель при своей отрисовке вызовет отрисовку дочернего объекта, унаследовавшего слой
Если же явно указан слой и индекс сортировки, то объект помещается в общий список, который сортируется по этим индексам.
Звучит все просто, но делал полтора месяца :D
Осталось довести до ума окошко с порядком отрисовки, чтобы оно работало без багов и поддерживало drag'n'drop.
При регистрации проверяется логика наследования слою родителя. Если наследуется, значит регистрируемся в списке родителя, и родитель при своей отрисовке вызовет отрисовку дочернего объекта, унаследовавшего слой
Если же явно указан слой и индекс сортировки, то объект помещается в общий список, который сортируется по этим индексам.
Звучит все просто, но делал полтора месяца :D
Осталось довести до ума окошко с порядком отрисовки, чтобы оно работало без багов и поддерживало drag'n'drop.
И я, конечно же, не мог пройти мимо ситуации с Unity3D 💩
Если кто-то не в курсе, они ввели "комиссию за установки". То есть если твоя игра превышает некое количество установок, то за каждую новую ты отсаливаешь сколько-то центов. Цифры офигенные, для Unity Technologies. Но печальные для всех ее пользователей...
Дело в том что такая система монетизации движка просто убивает монетизацию некоторых типов игр, где на один доллар приходится много-много установок. Получается так, что просто весь свой "навар" ты будешь отдавать за движок.
Реки говна хлынули мгновенно, и юнитеки, за что им похвала, сначала дали заднюю, а теперь и вовсе признают свою ошибку и придумывают как же задобрить всех обратно.
Почему так получилось? Столько лет плодотворного сотрудничества, и вот такое... Что ж, столько лет и разработка движка была убыточной. Да, они на пике заработка, у них 2млрд в год. Однако отчет за отчетом они показывают крупные убытки. И все это - разработка движка. Если рекламная часть бизнеса дешева и стабильно приносит высокий доход (более половины от всего), то за движок они получают меньшую часть, при этом тратя огромное количество денег на разработку. Вот они и решили что "нужно больше золота".
Однако, камон, 3000 инженеров? Хм, я вроде бы немного разбираюсь в разработке движков, делал в плейрикс, свой вот делаю... Но я искренне не понимаю что там делает 3000 человек, при том что по факту в движке годами не меняются ключевые проблемы и подходы. Это голословно, однако я для своих проектов на работе мог бы взять версию 7ми летней давности, и практически ничего не потерять из новых версий.
Этот дисбаланс и пытаются покрыть юнитеки, вместо того чтобы подумать головой и потратить меньшее количество людей на достижение большего результата
Если кто-то не в курсе, они ввели "комиссию за установки". То есть если твоя игра превышает некое количество установок, то за каждую новую ты отсаливаешь сколько-то центов. Цифры офигенные, для Unity Technologies. Но печальные для всех ее пользователей...
Дело в том что такая система монетизации движка просто убивает монетизацию некоторых типов игр, где на один доллар приходится много-много установок. Получается так, что просто весь свой "навар" ты будешь отдавать за движок.
Реки говна хлынули мгновенно, и юнитеки, за что им похвала, сначала дали заднюю, а теперь и вовсе признают свою ошибку и придумывают как же задобрить всех обратно.
Почему так получилось? Столько лет плодотворного сотрудничества, и вот такое... Что ж, столько лет и разработка движка была убыточной. Да, они на пике заработка, у них 2млрд в год. Однако отчет за отчетом они показывают крупные убытки. И все это - разработка движка. Если рекламная часть бизнеса дешева и стабильно приносит высокий доход (более половины от всего), то за движок они получают меньшую часть, при этом тратя огромное количество денег на разработку. Вот они и решили что "нужно больше золота".
Однако, камон, 3000 инженеров? Хм, я вроде бы немного разбираюсь в разработке движков, делал в плейрикс, свой вот делаю... Но я искренне не понимаю что там делает 3000 человек, при том что по факту в движке годами не меняются ключевые проблемы и подходы. Это голословно, однако я для своих проектов на работе мог бы взять версию 7ми летней давности, и практически ничего не потерять из новых версий.
Этот дисбаланс и пытаются покрыть юнитеки, вместо того чтобы подумать головой и потратить меньшее количество людей на достижение большего результата
Что это значит для всех остальных? Все по классике, "не стоить класть все яйца в одну корзину". Я всегда говорил чисто юнити-программистам, что не стоит быть в рамках одной технологии. Текущие события - тому подтверждение. Внезапно, технология, оказавшееся монополистом, может одновременно всем причинить боль. Внезапно огромный остров стабильности может крякнуть и начать разваливаться.
Я бы в этой ситуации посоветовал быть более униварсальным. Посмотреть на другие технологии и движки. Если это геймдев - то обязательно С++. Это уже давно стандарт индустрии, и все серьезные дядьки на нем сидят.
Даже если с юнити все будет окей (а я думаю что все будет окей, никто не хочет убивать дойную корову), то весьма полезно будет узнать плюсы, OpenGL, и вообще понять как там "под капотом".
Ну и продолжаем наблюдать дальше как разворачиваются события с Unity3D и кушать поп-корм 🍿
Я бы в этой ситуации посоветовал быть более униварсальным. Посмотреть на другие технологии и движки. Если это геймдев - то обязательно С++. Это уже давно стандарт индустрии, и все серьезные дядьки на нем сидят.
Даже если с юнити все будет окей (а я думаю что все будет окей, никто не хочет убивать дойную корову), то весьма полезно будет узнать плюсы, OpenGL, и вообще понять как там "под капотом".
Ну и продолжаем наблюдать дальше как разворачиваются события с Unity3D и кушать поп-корм 🍿
Долго вынашивал идею, как-то применить GPT для массовых задач в кодинге. Одна из таких идей - документация. Бесячая ведь вещь, писать тонну текста. Другая идея - применить GPT для какого-то рефакторинга кода. Бывает ведь так, что нужно что-то отрефакторить, по сути простое, но муторное. Как раз с движком подвернулась такая задача.
Я сейчас перевожу сырые указатели на умные, а точнее на свою версию интрузивного шареного указателя (с опциональным сборщиком мусора для дебага). И вот это капец какая тупая работа: нужно прошерстить весь код, заменить сырые указатели на шаблонную обертку, и поменять места взаимодействия. Иногда нужно использовать слабые ссылки, когда ссылка идет "наверх" к паренту, овенру и т.п. В общем, много рутины, при этом напрягается две извилины мозга.
И вот я решил поизучать openai API, чтобы попробовать автоматизировать эту рутину. И закинул в него 10 баксов. Посмотрим что осталось...
Я сейчас перевожу сырые указатели на умные, а точнее на свою версию интрузивного шареного указателя (с опциональным сборщиком мусора для дебага). И вот это капец какая тупая работа: нужно прошерстить весь код, заменить сырые указатели на шаблонную обертку, и поменять места взаимодействия. Иногда нужно использовать слабые ссылки, когда ссылка идет "наверх" к паренту, овенру и т.п. В общем, много рутины, при этом напрягается две извилины мозга.
И вот я решил поизучать openai API, чтобы попробовать автоматизировать эту рутину. И закинул в него 10 баксов. Посмотрим что осталось...