o2 dev
108 subscribers
49 photos
4 videos
25 files
54 links
About o2 engine development
加入频道
Да и два одинаковых объекта с одинаковым набором приоритетов будут "проходить друг через друга". Представьте тех же персов, собранных из приоритетов, проходящих друг через друга. Ноги, руки, тело - все будет пересекаться между двумя персами, хотя они должны выглядеть как одно целое. В общем, для большинства кейсов такое не подходит

Можно добавить именованные слои. Каждый объект лежит на своем слое, а внутри слоя сортируется в порядке иерархии. В целом, это равносильно первоначальному обходу иерархии, просто проблемы локализуются на уровне слоев. Уже проще, но все же не идеально
На мой взгляд самая правильная система - это комбинирование всех. В ней есть слои, и первоначально задан их порядок. Один слой ни при каких обстоятельствах не может "залезть" на другой слой. Затем по-дефолту все сортируется в порядке иерархии, тк в большинстве случаев это и нужно. И для отдельных кейсов задается числовой приоритет, который как бы "вытаскивает" объект из иерархии, и сортирует в рамках слоя в зависимости от его приоритета. У дефолтных объектов приоритет 0, таким образом можно что-то сделать ниже, а что-то выше
Однако у такой системы получается серьезный минус - сложность. Все нужно держать в голове, кто от кого наследуется, какой приоритет, слой и тд.

У меня уже давно была идея сделать два режима отображения иерархии в сцене: реальная иерархия и очередь отрисовки. Собственно, почему бы не вывести дерево очередности отрисовки камер, слоев и объектов там? К тому же, через drag'n'drop это очередность можно будет редактировать. Захотел поменять слой - перетащил объект в нужный слой. Захотел чтобы он был в подиерархии другого объекта - просто перетащил. И мгновенно увидел результат, дерево с порядком отрисовки сразу поменялось и ты видишь актуальный результат

При этом все так же можно редактировать и обычную иерархию сцены, и слои, и приоритеты. Просто теперь есть специальное место, где явно задается порядок отрисовки сцены. То что нужно было держать в голове - теперь на экране
Окошко еще не финальное, но уже вполне получается проверить концепцию.

Цветом выделены разные батчи, цифра справа - числовой приоритет, если задан. В руте показаны камеры (на скрине не видно), под каждой камерой - список слоев, которые она рендерит. В слое объекты и их дети. Выглядит все просто и понятно. А главное drag'n'drop интуитивен: ты хочешь чтобы объект рисовался в определенном месте - просто перетаскиваешь его туда
Расскажу о демке и о том, над чем сейчас работаю уже в течение последних 3х месяцев
Сейчас я интегрирую о2 в чужой движок.

Для чего это вообще нужно? Допустим, у вас есть проект, работающий на кастомном С++ движке. Проект живой, зарабатывает денег, и выкинуть на помойку истории его нельзя. При этом свое решение уже обросло костылями, оно становится совсем не удобным, и что-то исправть все сложнее и сложнее. При этом перелезть на Unity или другой движок не реально. Нужно переписывать проект с нуля некогда, нужно переучивать команду, да и вообще не факт что с перфомансом все будет в порядке.

Обычно студиям в такой ситуации не остается ничего, как пытаться улучшить свой движок, добавив в него хоть какие-то редакторы, ускоряющие разработку. Но по факту там тратятся человеко-годы, и получается все равно "не Unity".

В этом как раз моя идея, интегрировать о2 в эти движки, добавляя нужный функционал в старые проекты. По-сути это то, чем я занимался в Playrix в команде VSO (это внутренний движок) - мы прокачали старые проекты новыми тулзами, похожими на Unity. В итоге это дало буст разработки на всех проектах в разы, сохраняя старый код и перфоманс в игре
Собственно сейчас я работаю над интеграцией о2 в чужой движок. На самом деле он уже интегрирован и сейчас идет работа над оптимизацией. Оптимизация довольно интересная, как и тот продукт, над которым я работаю. Это - гемблинг, игровые автоматы проще говоря, на стареньком железе с 10-ти летним 32битным ARM, линуксом под капотом и ультра-дерьмовой видеокартой.

Сейчас все на этапе эксперимента, попробовать интегрировать о2 в их движок и добиться приемлемого перфоманса на их железе. Это позволит им делать игры быстрее, верстать графику в редакторе. А скрипты на JS помогут в портировании игр под WEB. В общем, почти мгновенная прокачка тулсета студии за счет внедрения о2
Этап интеграции прошел относительно быстро. Пришлось научить все компилироваться вместе, разрулить зависимости в CMAKE, да и собственно перевести о2 на CMAKE. Поддержать платформенные API под линукс и OpenGLES. Поправить ошибки gcc (скажите мне про кросс-компиляемость С++ ага). Основная работа связана со специфичным железом, компиляцией под него и значительной переделкой рендера.

Видюха там и правда слабая и привередливая. Например, очистка стенсил-буффера, который ты даже не юзаешь, может дать +20 FPS. До сих пор идет поиск всех крупиц, неочевидно съедающих перфоманс. Правильная запись в буффер вершин, сжатие DXT, все что угодно может влиять. Отличный способ прокачать свои знания в графике

И, как говорится, все в кассу. В целом эта работа дала понять как именно идет процесс интеграции в сторонний движок. Так скажем собраны самые первые грабли. Все улучшения применимы ко всем платформам, и улучшая что-то одно, улучшаешь везде. Да и просто интересно повозиться с такими интересным железом
Кажется что это может быть неплохим способом раскрутить движок. Можно найти несколько таких проектов, интегрировать о2 в их движки, и работать как команда движка на аутсорсе. Владельцам проектов выгодно - они получают полноценную движковую команду за небольшую сумму, готовую быстро решить технически проблемы, и большой буст эффективности разработки засчет Unity-like подхода. Для развития о2 тоже выгодно - он будет применяться в реальных задачах, оттачивать и тестироваться

В этом время можно продвигать движок на открытых площадках. Он будет открытый, бесплатный, и проверенный реальными задачами. И если все пойдет крайне удачно, можно монетизировать набранную аудиторию через условно-платные сервисы в виде модулей для движка: система покупок, аналитика и тп. Думаю сейчас серьезный движок для мобильных 2D игр вполне может откусить 10% от рынка: https://www.linkedin.com/pulse/game-engines-market-2023-size-professional-survey/

Так что если интересно пописать двигло - велкам, заняться можно чем хочешь ;)
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
В какой момент какой вызывать? Окей, начнем с простого, 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.
И я, конечно же, не мог пройти мимо ситуации с Unity3D 💩

Если кто-то не в курсе, они ввели "комиссию за установки". То есть если твоя игра превышает некое количество установок, то за каждую новую ты отсаливаешь сколько-то центов. Цифры офигенные, для Unity Technologies. Но печальные для всех ее пользователей...

Дело в том что такая система монетизации движка просто убивает монетизацию некоторых типов игр, где на один доллар приходится много-много установок. Получается так, что просто весь свой "навар" ты будешь отдавать за движок.

Реки говна хлынули мгновенно, и юнитеки, за что им похвала, сначала дали заднюю, а теперь и вовсе признают свою ошибку и придумывают как же задобрить всех обратно.

Почему так получилось? Столько лет плодотворного сотрудничества, и вот такое... Что ж, столько лет и разработка движка была убыточной. Да, они на пике заработка, у них 2млрд в год. Однако отчет за отчетом они показывают крупные убытки. И все это - разработка движка. Если рекламная часть бизнеса дешева и стабильно приносит высокий доход (более половины от всего), то за движок они получают меньшую часть, при этом тратя огромное количество денег на разработку. Вот они и решили что "нужно больше золота".

Однако, камон, 3000 инженеров? Хм, я вроде бы немного разбираюсь в разработке движков, делал в плейрикс, свой вот делаю... Но я искренне не понимаю что там делает 3000 человек, при том что по факту в движке годами не меняются ключевые проблемы и подходы. Это голословно, однако я для своих проектов на работе мог бы взять версию 7ми летней давности, и практически ничего не потерять из новых версий.

Этот дисбаланс и пытаются покрыть юнитеки, вместо того чтобы подумать головой и потратить меньшее количество людей на достижение большего результата
Что это значит для всех остальных? Все по классике, "не стоить класть все яйца в одну корзину". Я всегда говорил чисто юнити-программистам, что не стоит быть в рамках одной технологии. Текущие события - тому подтверждение. Внезапно, технология, оказавшееся монополистом, может одновременно всем причинить боль. Внезапно огромный остров стабильности может крякнуть и начать разваливаться.

Я бы в этой ситуации посоветовал быть более униварсальным. Посмотреть на другие технологии и движки. Если это геймдев - то обязательно С++. Это уже давно стандарт индустрии, и все серьезные дядьки на нем сидят.

Даже если с юнити все будет окей (а я думаю что все будет окей, никто не хочет убивать дойную корову), то весьма полезно будет узнать плюсы, OpenGL, и вообще понять как там "под капотом".

Ну и продолжаем наблюдать дальше как разворачиваются события с Unity3D и кушать поп-корм 🍿
пару слов о том, как классная идея может классно зафейлиться.
Долго вынашивал идею, как-то применить GPT для массовых задач в кодинге. Одна из таких идей - документация. Бесячая ведь вещь, писать тонну текста. Другая идея - применить GPT для какого-то рефакторинга кода. Бывает ведь так, что нужно что-то отрефакторить, по сути простое, но муторное. Как раз с движком подвернулась такая задача.

Я сейчас перевожу сырые указатели на умные, а точнее на свою версию интрузивного шареного указателя (с опциональным сборщиком мусора для дебага). И вот это капец какая тупая работа: нужно прошерстить весь код, заменить сырые указатели на шаблонную обертку, и поменять места взаимодействия. Иногда нужно использовать слабые ссылки, когда ссылка идет "наверх" к паренту, овенру и т.п. В общем, много рутины, при этом напрягается две извилины мозга.

И вот я решил поизучать openai API, чтобы попробовать автоматизировать эту рутину. И закинул в него 10 баксов. Посмотрим что осталось...