Делать игру одному или целой большой командой? Это совсем не главный вопрос. Главное это понять, почему игра мечты не была доделана. Игры делать очень сложно, и умножив сложность на неправильную оценку своих ресурсов и возможностей это приводит к катастрофе. Таким же образом и целые компании не доделывают свои игры. Через год разработки окажется что забыли нанять необходимый отдел, а найм займет пол года. Например, маркетолога, или звуковика.
Делать маленькие игры это хороший треннинг для трезвой работы с ресурсами. Попробуйте запланировать игру за 1 неделю и примите решение какие фичи вы сделать не успеете, зато сделайте другие хорошо.
А ведь это любопытный маркер, когда начинаешь считать такой свитер упоротым, много мыслей сразу всплывает:
Как плюшка от компании он тебе нафиг не нужен, тк знаешь свою реальную зарплату и реальный рынок. Простые плюшки уже не впечатляют.
Не одеть его тоже не очень, тк легко перейти грань "Доктора Хауса" по токсичности, и отбиться от коллектива. Хотябы на общей фоточке засветиться на коропративе надо.
Свитера раздают в устаканившихся и больших организациях где мерч уже рассавлен на поток и значит вы застали такой коллектив и не отвалились на испытательных сроках и команда вас не выпилила.
При этом, чуство вкуса от выгорания не пропало, и свитер становится формой протеста.
А это точно open-source, то что вы имеете в виду? Кажется что если есть желание дать пользу исходным кодом проекта, то лучше сработает опубликованный как есть код и улучшение его через публичные пул-реквесты. Лицензии можно использовать разные.
А как вы предлагаете проверять что миграция работает? В примере выше сам код миграции выглядит очень опасным и хардкодным, так, что в самом нём ручную ошибку допустить легко. А то что он правильно мигрирует - никаких гарантий тем более нет. То что сохранено у вас в джейсонах не является тестируемыми данными, а только одним их частным случаем значений. Самый главный вопрос такого рода миграций, это не бизнесс логика мигрирования, а как раз свойство и ограничения данных, и их изменения в версиях. Примеры:
Раньше поле "Фамилия" было необязательно а стало обязательно.
Допустимые значения ресурсов изменились, тк вместе со структурой данных еще и конфигурация обновилась и стал выпадать новый ресурс из сундуков.
Раньше был филд - строка, а сейчас тот же филд и он же строка, но при этому код логики работает с этой строкой по другому.
Могу предложить хранить в коде сразу всю допустимость значений, и использовать эти данные (атрибуты, или генераторы вариантов) для генерации тест-кейсов, в которых все значимые варианты данных сгенерируются сразу. Это даст чуть болшее покрытие тестами, и от каких то банальных ручных ошибок мб избавит.
А вы пробовали на основе Playables сделать аналог BlendTree какого либо вида? Выглядит что это довольно муторно и сложно написать так чтобы не лупить все клипы в один миксер и потерять весь перфоманс на множественном семплинге.
Всё таки, переключить галочку на URP и попробовать ассеты из ассетстора это не "перейти на URP". Сам по себе URP имеет набор модифицируемых и комбинируемых слоёв, котоыре можно фасовать и заменять, в зависимости от нужд. И по скольку URP сделан на основе SRP API, то можно собрать свой пайплайн, подсмотрев что происходит в URP, его исходный код открыт.
Я соглашуть что URP слишком универсален, содержит множество багов и имеет плохую производительность, но в статье нет фактической аргументировации. Например, что именно даёт такой низкий fps в вашем случае? Дело ли в URP и в каком проходе именно узкое место? Дело только в одном месте в коде или в множестве? Что будет с выводами, если это одно место исправить или отключить (ведь не всем нужна вода в игре)?
По моему опыту, самую высокую производительность можно получить, взяв минимум из URP, собрав из него облегчённого франкенштейна на базе SRP, и рендерить только то что нужно в проекте, удалив ненужные буферы, шейдер-варанты, системы теней, мета-данные лайтмап и тд. Но уж ни как не со стандартным набором шейдеров выходить на мобильные устройства, разве что с Unlit-Diffuse картинкой.
Хочется дополнительно немного кинуть камней в сторону Unity, как фасилитатора кривого апи и некрасивой инициализации. Если не продумать модульность встраивания то каждой команде придётся писать её самой. Это речь и про порядок инициализации, это и про колбеки, которые почему то должны быть на префабах и про Unity врапперы у которых приватные конструкторы и сходи попробуй написать юнит-тесты. Было бы неплохо в движке легаси почистить, и вариантов выстрелить в чью то ногу у разработчика враппера станет меньше.
Привет. В таком подходе стоит обязать писать тесты со всеми старыми вариантами сигнатур, чтобы легче было вспомнить что вообще ранее было. А еще круче, использовать авто комбинаторику для таких данных, а в тесте делать NUnit.Assume(), чтобы проверить что миграция не отвалится на корнер кейсах.
Так можно делать не только с json, а с любым нетипизированным набором.
Жалко что вы не прошли чуть дальше по методу "Метод конического масштабирования". Кажется что математически такое пересечение и расположение камеры можно рассчитать, но только если объекты это сферы, а это как раз ваш случай. Может быть дело просто в сортировке, сортировать нужно по точкам-основаниям перпендикуляра от центральной линии камеры до центра сферы. А после того как порядок известен, опять же для сфер, можно рассчитать их масштаб так, чтобы сферы объектов не пересекались, но были максимально близко к Near Clipping Plane.
Но есть другая потенциальная проблема с "Методом конического масштабирования" в том что когда сферический объект очень близко к камере и находится сбоку, то перспективное искажение будет иметь разную силу, в зависимости от масштаба. По этому находясь камерой на очень низкой орбите небесного тела, это тело должно иметь фактические размеры из физического мира, чтобы картинка была реалистичной. Для небесных тел в нашей системе это подойдёт, но всё же имеет ограничения тоже.
UPD: Дополню что многослойный рендеринг очень дорогое занятие, и в случае с Deferred рендерингом ситуация будет еще хуже. На мобильных устройствах, да и на консолях иметь больше чем одну камеру расточительно, и из промежуточных буферов читать тоже очень дорого.
Вы молодец что стараетесь привнести в сообщество новые статьи. Хоть и полезность у этой статьи не очень высокая, но не останавливайтесь, продолжайте писать, копните в следующий раз глубже. Учтите просто что это профильное сообщество, которое способно сходить и почитать документацию.
Попробуйте использовать ChatGPT для изменения формулировок, и итеративно дополняйте от себя. Про Баку тоже было бы очень интересно получить информацию. Сознательный отказ от стереотипов и получение реальных мнений, это то что нужно сообществу, чтобы взвешивать самим и становиться более открытыми. Иначе вот складываются несбывшиеся ожидания, непонятно из чего.
А почему кстати при маппинге при увеличении числа время растёт? Маппинг ведь подразумевает расчёт указателя, верно? Если есть расчёт, то и файл не нужно читать с начала, а с произвольного индекса.
Дело не только в количестве сущностей. Вопрос практический - современные IDE подсвечивают стек вызовов методов между классами при дебаге, и сканируют использования методов для навигации по коду. В случае с EB я не видел примеров удобной навигации, большую кодовую базу поддерживать будет тяжело. Единственный пример использования аналога EB я могу представить только когда количество методов у класса на столько большое, что только у него в API накладные расходы на EB меньше, чем на написание большого кол-ва сигнатур методов руками.
ни разу не "размыли логику" или не "спрятали зависимости"
А какие аргументы то приведены? Выглядит так что если цепочка вызов увеличится, как это происходит в многослойном ООП, то сложно отследить кто вообще что вызвал и в каком порядке, и как это прервать.
Да, еще забыл сказать, необходимо мочь сериализовать всё, иначе результаты вычислений будут расходиться. Или, например, если игрок только подключился и у него совсем нет информации о мире. Если работать с сущностями по одной, то получится неконсистентность данных, если делать в лоб. Такой подход есть в Unreal, или в NetworkForGameObjects, но в играх так совсем уже не делают. В современных тайтлах всегда где нибудь да есть предсказание, или компенсация лага.
По коду сложно сказать достаточно или нет, тк сам контракт подразумевает что данные можно трактовать по разному. Тут ведь при синхронизации для данных нужен еще факт создания или удаления сущности, и какого она была типа (набора компонентов данных + набора логических систем + связей между объектами). Если бы вся информация об этом была гарантирована в данных, то было бы надёжнее. Ну или я просто не правильно представляю рабочие примеры, а не синтетические. Мне кажется что подход не полностью датаориентированный, тк тут замешаны ООП свойства, и я перечислил список частых проблем в недатаориентированных средах.
Функцией сериализации придется наделить либо все сущности, либо каким то образом шарить дополнительные детали из метода Compose() (о чём я писал выше). Это будет дороговато поддерживать, и в целом это доступ к рандомной памяти в куче, в большом количестве итераций. Например, файтинг или шутер, где нужно делать копию мира по 7-8 раз за кадр, так не сделать.
В именно этой реализации, данные и логика не отделены друг от друга полностью, а имеют важные детали в методе Compose(). И этот метод собственно деструктивно инициализирует данные и логику. Нельзя как в ECS взять тот же компонент, но от другой сущности, чтобы всё продолжило работать.
С точки зрения кода любой игровой объект состоит из данных и логики.
Это не очень хорошо. Когда данные и логика связаны то сущность теряет гибкость и тестируемость. Есть набор задач, которые в таком подходе сделать будет невозможно или как минимум дорого:
Сериализация состояния мира в больших масштабах.
Тестирование и воспроизведение конкретного кейса.
Декларирование порядка вызовов между атомарными объектами или внешнего кода.
Копирование объектов (сложно оценить как скопируются функции и эвенты)
Это и проблема многих ECS, где нет доступа к блокам памяти, или нельзя выделить размер в памяти нормально.
Делать игру одному или целой большой командой? Это совсем не главный вопрос. Главное это понять, почему игра мечты не была доделана. Игры делать очень сложно, и умножив сложность на неправильную оценку своих ресурсов и возможностей это приводит к катастрофе. Таким же образом и целые компании не доделывают свои игры. Через год разработки окажется что забыли нанять необходимый отдел, а найм займет пол года. Например, маркетолога, или звуковика.
Делать маленькие игры это хороший треннинг для трезвой работы с ресурсами. Попробуйте запланировать игру за 1 неделю и примите решение какие фичи вы сделать не успеете, зато сделайте другие хорошо.
>тот самый ублюдский свитер с оленями
А ведь это любопытный маркер, когда начинаешь считать такой свитер упоротым, много мыслей сразу всплывает:
Как плюшка от компании он тебе нафиг не нужен, тк знаешь свою реальную зарплату и реальный рынок. Простые плюшки уже не впечатляют.
Не одеть его тоже не очень, тк легко перейти грань "Доктора Хауса" по токсичности, и отбиться от коллектива. Хотябы на общей фоточке засветиться на коропративе надо.
Свитера раздают в устаканившихся и больших организациях где мерч уже рассавлен на поток и значит вы застали такой коллектив и не отвалились на испытательных сроках и команда вас не выпилила.
При этом, чуство вкуса от выгорания не пропало, и свитер становится формой протеста.
А это точно open-source, то что вы имеете в виду? Кажется что если есть желание дать пользу исходным кодом проекта, то лучше сработает опубликованный как есть код и улучшение его через публичные пул-реквесты. Лицензии можно использовать разные.
А вы не используете wave func collapse? Можно добиться большей неоднородности шумов, и добавить ручных вариантов.
А как вы предлагаете проверять что миграция работает? В примере выше сам код миграции выглядит очень опасным и хардкодным, так, что в самом нём ручную ошибку допустить легко. А то что он правильно мигрирует - никаких гарантий тем более нет. То что сохранено у вас в джейсонах не является тестируемыми данными, а только одним их частным случаем значений. Самый главный вопрос такого рода миграций, это не бизнесс логика мигрирования, а как раз свойство и ограничения данных, и их изменения в версиях. Примеры:
Раньше поле "Фамилия" было необязательно а стало обязательно.
Допустимые значения ресурсов изменились, тк вместе со структурой данных еще и конфигурация обновилась и стал выпадать новый ресурс из сундуков.
Раньше был филд - строка, а сейчас тот же филд и он же строка, но при этому код логики работает с этой строкой по другому.
Могу предложить хранить в коде сразу всю допустимость значений, и использовать эти данные (атрибуты, или генераторы вариантов) для генерации тест-кейсов, в которых все значимые варианты данных сгенерируются сразу. Это даст чуть болшее покрытие тестами, и от каких то банальных ручных ошибок мб избавит.
А вы пробовали на основе Playables сделать аналог BlendTree какого либо вида? Выглядит что это довольно муторно и сложно написать так чтобы не лупить все клипы в один миксер и потерять весь перфоманс на множественном семплинге.
Всё таки, переключить галочку на URP и попробовать ассеты из ассетстора это не "перейти на URP". Сам по себе URP имеет набор модифицируемых и комбинируемых слоёв, котоыре можно фасовать и заменять, в зависимости от нужд. И по скольку URP сделан на основе SRP API, то можно собрать свой пайплайн, подсмотрев что происходит в URP, его исходный код открыт.
Я соглашуть что URP слишком универсален, содержит множество багов и имеет плохую производительность, но в статье нет фактической аргументировации. Например, что именно даёт такой низкий fps в вашем случае? Дело ли в URP и в каком проходе именно узкое место? Дело только в одном месте в коде или в множестве? Что будет с выводами, если это одно место исправить или отключить (ведь не всем нужна вода в игре)?
По моему опыту, самую высокую производительность можно получить, взяв минимум из URP, собрав из него облегчённого франкенштейна на базе SRP, и рендерить только то что нужно в проекте, удалив ненужные буферы, шейдер-варанты, системы теней, мета-данные лайтмап и тд. Но уж ни как не со стандартным набором шейдеров выходить на мобильные устройства, разве что с Unlit-Diffuse картинкой.
Хочется дополнительно немного кинуть камней в сторону Unity, как фасилитатора кривого апи и некрасивой инициализации. Если не продумать модульность встраивания то каждой команде придётся писать её самой. Это речь и про порядок инициализации, это и про колбеки, которые почему то должны быть на префабах и про Unity врапперы у которых приватные конструкторы и сходи попробуй написать юнит-тесты. Было бы неплохо в движке легаси почистить, и вариантов выстрелить в чью то ногу у разработчика враппера станет меньше.
Привет. В таком подходе стоит обязать писать тесты со всеми старыми вариантами сигнатур, чтобы легче было вспомнить что вообще ранее было. А еще круче, использовать авто комбинаторику для таких данных, а в тесте делать NUnit.Assume(), чтобы проверить что миграция не отвалится на корнер кейсах.
Так можно делать не только с json, а с любым нетипизированным набором.
Жалко что вы не прошли чуть дальше по методу "Метод конического масштабирования". Кажется что математически такое пересечение и расположение камеры можно рассчитать, но только если объекты это сферы, а это как раз ваш случай. Может быть дело просто в сортировке, сортировать нужно по точкам-основаниям перпендикуляра от центральной линии камеры до центра сферы. А после того как порядок известен, опять же для сфер, можно рассчитать их масштаб так, чтобы сферы объектов не пересекались, но были максимально близко к Near Clipping Plane.
Но есть другая потенциальная проблема с "Методом конического масштабирования" в том что когда сферический объект очень близко к камере и находится сбоку, то перспективное искажение будет иметь разную силу, в зависимости от масштаба. По этому находясь камерой на очень низкой орбите небесного тела, это тело должно иметь фактические размеры из физического мира, чтобы картинка была реалистичной. Для небесных тел в нашей системе это подойдёт, но всё же имеет ограничения тоже.
UPD: Дополню что многослойный рендеринг очень дорогое занятие, и в случае с Deferred рендерингом ситуация будет еще хуже. На мобильных устройствах, да и на консолях иметь больше чем одну камеру расточительно, и из промежуточных буферов читать тоже очень дорого.
Вы молодец что стараетесь привнести в сообщество новые статьи. Хоть и полезность у этой статьи не очень высокая, но не останавливайтесь, продолжайте писать, копните в следующий раз глубже. Учтите просто что это профильное сообщество, которое способно сходить и почитать документацию.
Попробуйте использовать ChatGPT для изменения формулировок, и итеративно дополняйте от себя. Про Баку тоже было бы очень интересно получить информацию. Сознательный отказ от стереотипов и получение реальных мнений, это то что нужно сообществу, чтобы взвешивать самим и становиться более открытыми. Иначе вот складываются несбывшиеся ожидания, непонятно из чего.
А почему кстати при маппинге при увеличении числа время растёт? Маппинг ведь подразумевает расчёт указателя, верно? Если есть расчёт, то и файл не нужно читать с начала, а с произвольного индекса.
Дело не только в количестве сущностей. Вопрос практический - современные IDE подсвечивают стек вызовов методов между классами при дебаге, и сканируют использования методов для навигации по коду. В случае с EB я не видел примеров удобной навигации, большую кодовую базу поддерживать будет тяжело. Единственный пример использования аналога EB я могу представить только когда количество методов у класса на столько большое, что только у него в API накладные расходы на EB меньше, чем на написание большого кол-ва сигнатур методов руками.
А какие аргументы то приведены? Выглядит так что если цепочка вызов увеличится, как это происходит в многослойном ООП, то сложно отследить кто вообще что вызвал и в каком порядке, и как это прервать.
Да, еще забыл сказать, необходимо мочь сериализовать всё, иначе результаты вычислений будут расходиться. Или, например, если игрок только подключился и у него совсем нет информации о мире. Если работать с сущностями по одной, то получится неконсистентность данных, если делать в лоб. Такой подход есть в Unreal, или в NetworkForGameObjects, но в играх так совсем уже не делают. В современных тайтлах всегда где нибудь да есть предсказание, или компенсация лага.
По коду сложно сказать достаточно или нет, тк сам контракт подразумевает что данные можно трактовать по разному. Тут ведь при синхронизации для данных нужен еще факт создания или удаления сущности, и какого она была типа (набора компонентов данных + набора логических систем + связей между объектами). Если бы вся информация об этом была гарантирована в данных, то было бы надёжнее.
Ну или я просто не правильно представляю рабочие примеры, а не синтетические. Мне кажется что подход не полностью датаориентированный, тк тут замешаны ООП свойства, и я перечислил список частых проблем в недатаориентированных средах.
Функцией сериализации придется наделить либо все сущности, либо каким то образом шарить дополнительные детали из метода Compose() (о чём я писал выше). Это будет дороговато поддерживать, и в целом это доступ к рандомной памяти в куче, в большом количестве итераций. Например, файтинг или шутер, где нужно делать копию мира по 7-8 раз за кадр, так не сделать.
В именно этой реализации, данные и логика не отделены друг от друга полностью, а имеют важные детали в методе Compose(). И этот метод собственно деструктивно инициализирует данные и логику. Нельзя как в ECS взять тот же компонент, но от другой сущности, чтобы всё продолжило работать.
Это не очень хорошо. Когда данные и логика связаны то сущность теряет гибкость и тестируемость. Есть набор задач, которые в таком подходе сделать будет невозможно или как минимум дорого:
Сериализация состояния мира в больших масштабах.
Тестирование и воспроизведение конкретного кейса.
Декларирование порядка вызовов между атомарными объектами или внешнего кода.
Копирование объектов (сложно оценить как скопируются функции и эвенты)
Это и проблема многих ECS, где нет доступа к блокам памяти, или нельзя выделить размер в памяти нормально.