Pull to refresh
25
0
Максим Савенков @MaxEdZX

Разработчик компьютерных игр

Send message

Спасибо за уточнение по терминологии. На первый взгляд, Mini-Tower меня тоже устроит. Хотя, тут коллеги в другом месте предложили взять полноразмерный корпус и приторичть к тачке двухколёсной для повышения мобильности, тоже интересная идея :) :)

Предложение, которое меня заинтересовало, было вот в таком корпусе: https://www.fractal-design.com/ru/products/cases/torrent/torrent-nano/black-rgb-tg-light-tint/ Кажется, он заметно больше... Вообще, он уже, похоже, близок к нормальному миди-тауэру, и тогда не совсем понятно нафига :)

Я вот тоже подумываю следующий комп может мини взять, потому что надо ездить между несколькими местами летом, но у меня всё интереснее - у меня 100% игры, точнее, 90% разработка игр, и 10% просто игры. Поэтому дискретная видеокарта просто неизбежна.

Однако, некоторые конторы вроде бы готовы собрать в корпусе чуть больших, но всё же переносных размеров вроде бы что-то с GeForce 4070/4080... Я, правда, не знаю, верить им, или нет - собрать-то они соберут, а вот что там будет с охлаждением - это интересный вопрос (может сразу ставят водяное? Мне кажется, в маленьком корпусе с горячим процом и видеокартой воздух не справится, но я вообще ничего не понимаю в сборке ПК).

Атласы - для скорости, сжатые атласы - для памяти (и все ещё скорости).

На консолях last gen (PS4/XBox One) по меркам современного PC-гейминга очень мало памяти (по статистике Стима сейчас чаще всего 16Гб стоит + 4-6Гб на GPU; на PS4 примерно 4.5Гб CPU+GPU), вот и приходится крутиться. Тем более что на PC если ты выжрал всю память - Windows сначала что-нибудь в swap скинет, и может быть даст тебе пик проскачить (ценой подтормаживания), а на консоли - сразу падение.

В столице, например, стоят все компаньоны разом, а это 12 переодеваемых персонажей, по 3 атласа на каждого (дифьюз, нормали, маски). Тут уже приходится оптимизировать хоть как-то (в идеале, конечно, переписать всё на какой-то стримминг, но поскольку первая игра изначально делалась под PC, да и в целом Unity и стримминг совместимы с большим трудом, то трудозатраты на это пока что неподъёмны).

Хм, да, согласен насчёт объединения мипов, сработает пожалуй.

На GPU было бы здорово сделать, я читал что-то от NVidia (кажется) тогда на эту тему, но у нас был свободный generalist (я), а свободного граф. программиста не было, поэтому я пошёл тем путём, который понимаю без долгого въезжания в тему. Нас скорость пока устраивает (пара секунд на фоне общей загрузки большого уровня погоды не делают), но буду держать в этот вариант в уме, на случай если когда-нибудь время появится.

Интересное решение.

Мы решали немного другую, но схожую задачу в Pathfinder: Wrath of the Righteous. У нас атлас изначально собирается из несжатых текстур, и кроме того атласы бывают разного размера (в зависимости от настроек качества графики), поэтому по такой технологии как у вас их вроде бы трудно будет собрать.

Поэтому мы ограничились сжатием в рантайме в DXT как раз, портировав на Burst StbDxtSharp. То есть сначала атлас собирается в рендертекстуру (плюс там ещё всякая покраска хитрая, что тоже мешает из заранее сжатых текстур атлас собрать), потом мы из неё GPU Readback'ом читаем результат и сжимаем его (асинхронно), после окончания сжатия (на PC и консолях оно получается типа 25мс на 1024 текстуру) - удаляем несжатую версию.

Я всё собираюсь нашу версию DXT-сжатия выложить в открытый доступ, но руки не доходят оформить всё удобно.

Если что — пишите мне, я постараюсь разобраться! Тулза может быть местами сыровата (часть проблем занесена в Issues уже), но надеюсь будет небесполезна.
Il2cpp в планах! Обязательно хочется его поддержать, и это одна из приоритетных задач.

Edit: можете следить за состоянием вот этого issue: github.com/OwlcatGames/OwlcatMonoProfiler/issues/20
Не могу обещать, что скоро добавлю возможность, но можно Issue создать. Я просто собаку завёл недавно (после того, как основную часть кода профайлера дописал), и сейчас ни на что времени не хватает :) Как всё устаканится, вернусь к задачам обязательно.
Да, наверное можно. Я почему не стал этого делать для Юнити — чтобы в рантайме не разбираться, что там включил разработчик — DirectX, OpenGL или Vulkan вообще. Возможно хорошим решением была бы какая-то система плагинов, которая бы для разных движков хукала разные функции самого движка (т.к. многие движки умеют разные рендереры) + отдельный режим без кадров.

EDIT: Если подумать, то вообще достаточно имя функции для перехвата в настройках, так-то…
В теории — можно, на практике пока нет. Проблема средних размеров, но её надо решить, прежде чем всё заработает: в произвольном Моно-проекте никаких кадров нет, и там надо бы группировать аллокации таки по времени с какой-то гранулярностью. Это потребует небольшой переделки DLLки профайлера, и чуть более геморойной — UI. Возможно, правильнее было бы сделать форк для «просто Mono», ну, или всё-таки отдельный режим. В общем, для меня лично это всё несколько out of scope по причине нехватки времени и сил, но пулл-риквесты приму :)
В целом мы храним тензор (или, точнее, N-мерную матрицу) в координатной форме, где значения — 64-битные int'ы, а координаты — 8-битные uint'ы (группами по N штук).
github.com/MaxSavenkov/drdestructo2 — вот мой пет-прожект, можно посмотреть. Это правда довольно старый код, сейчас я наверное смог бы уже лучше, но как пример можно оценить. Самый сок находится в файле github.com/MaxSavenkov/drdestructo2/blob/master/src/GameStateLevel.cpp — скромных 2051 строк. Код местами комментирован.

Общие идеи кода описаны тут: github.com/MaxSavenkov/drdestructo2/blob/master/docs/ReadMe_Source.txt, но в целом идея была в том, чтобы разбить код на Компоненты, которые почти ничего не делают, а только пассивно содержат данные, и Процессоры, которые обрабатывают Компоненты каждого типа в один проход (например, всю физику, потом всю графику, потом весь звук). А весь код, которые требует взаимодействия _между_ разными компонентами (в т.ч. копирование данных из компонента в компонент, т.к. они дублируют данные — иначе бы Процессорам пришлось принимать на вход более чем один тип компонентов), находится в GameStateLevel :)
Я думаю проблема в предметной области довольно большая. У игрового кода очень высокая связность между разными частями потому, что правила того требуют. Тут есть такая проблема, что игра не моделирует какую-то реальность (у которой есть логичные, и не очень изменчивые законы — даже у финансов), а фантазию дизайнера, поэтому у неё могут возникать самые неожиданные взаимодействия, причём внезапно. Вчера классу Персонаж ничего не надо было знать о классе Дерево, а завтра — они вдруг лучшие друзья с интимным доступом к кишкам друг друга. Потому что так веселее.

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

Плюс, в играх мало объектов со сложной собственной логикой, и много сложной логики, требующей доступа к нескольким объектам разных типов, которую трудно поместить в один из них, и приходится выносить в некий третий объект. По моему опыту, большая часть багов в играх того типа, когда все функции по отдельности работают вроде бы правильно, а вот когда их случайно вызывают в непредвиденной последовательности — всё идёт в ад.
А вот ни на какие обычно не делится. Для всего кода игровой механики, какой я видел, характерно было стремление к нескольким огромным классам, которые делали всё, что в эту механику было заложено, изредка делясь обязанностями с классами, у которых область действия была более очерченной (типа поиска пути). Мой личный более-менее удачный опыт был, когда я попробовал применить разбиение игровых объектов на компоненты a la Unity, но и он скатился, в конце концов, к тому, что взаимодействие _между_ компонентами — а это как раз самое интересное — было организованно в одном большом классе, называвшемся «логика уровня». В бОльших играх видел попытку организовать подсистемы («квестовая подсистема», «социальная подсистема»), но каждая из них в результате опять-таки оказывалась классом на 1000+ строк имплементации. То есть вот эта красивая картинка, где вся функциональность разбита на маленькие, легко тестируемые классы с небольшим количеством функций — она никак не получается. Но возможно я просто ни разу за 10+ лет не работал с хорошим архитектором (то что я сам плохой — я и так знаю).
Вот да, такую штуку я могу себе представить, и даже представлял (хотя сложностей с этим много, и реальной реализации почти ни разу не видел). А вот именно что юнит-тестирование — как-то не получается.
Вот у меня как раз возражения всегда на тему «не понимаю, как тестировать что-то сложное» и «понятия не имею, как будет выглядеть система, пока её не напишу (и не перепишу два раза)». Возможно это специфика области, разработка игр — у нас никогда не бывает чётких требований, всё кардинально меняется на лету, и компоненты системы совершенно отказываются изолироваться друг от друга, протягивая щупальца порой в совершенно неожиданные места. То есть вот скажем автоматические тесты для парсера скриптов, или для хитрого контейнера, или там для библиотеки конечных автоматов — это ОК, это я понимаю, но как тестировать что-то более высокоуровневое — игровую механику, рендер или UI — это уже за пределами моего понимания.
Геймдев-истории! Люблю такое.

Мы чуть случайно не стали вашими конкурентами, но начальство прототип про войну роботов зарезало, приказав сосредоточится на дрэг-рейсинге.

С рейсингом вышла история очень поганая в одном месте. Он был изначально чисто сингловый, и всё было хорошо. Но тут решили приделать всякий бэкэнд, и после некоторого раздумья выбрали для этого контору GameSparks, чтобы самим писать поменьше. Какой ошибкой это оказалось! Их C++ SDK начал вызывать у меня лёгкие вопросы ещё при первом знакомстве, когда я увидел, что они удаляют первый элемент из вектора через последовательность std::reverse + std::pop_back + std::reverse. Поправив в их SDK несколько подобных косяков, всё-таки решили им пользоваться.

И вот приходит день и час, и мы выкатываем очередную версию на iOS. Выкатили. А она вешается на стартовом экране намертво у некоторых игроков. Подлость в том, что на всех имеющихся устройствах баг не воспроизводился вообще никак, но зато — воспроизводился на самом свежем по тем временам iPhone 6. Который, по счастью, обнаружился у инвестора, и мы у него его взяли на время отладки.

Дело, конечно же, оказалось в race condition. И что самое прекрасное — не у нас. А в этом самом GameSparks SDK, но даже и не в нём, а в его open source зависимости. Которую авторы GameSparks допилили кривыми добрыми руками (добавив поддержку HTTPS при помощи OpenSSL), конечно же, у себя в форке, не послав в исходный проект никаких пулл-риквестов, и не пройдя никаких проверок сообществом. А в результате у них там, кажется, звался pthread_join на хэндл уже умершего треда, и на этом всё зависало навсегда (очевидно, если тред успел умереть до того, что на более медленных устройствах не происходило).

Фикс состоял насколько я помню что-то около из одной строчки или двух, но пока мы обнаружили, что происходит что-то ненормальное, пока оторвались от других платформ (для нас тогда в приоритете был Windows Phone, т.к. приносил больше всего денег — там у нас не было конкурентов) — все пользователи, какие у нас были на iOS разбежались, да так уже и не вернулись.
Справедливости ради, тут случилось стечение 3х инструментов, два из которых имеют экспериментальные фичи (CMake Server и поддержка внешних CMake в Android Studio). Так что в некотором роде я ССЗБ.

Information

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