![image](https://genapilot.ru/wp-content/uploads/2016/12/horse-in-games-7.jpg)
Когда время заканчивается, разработчики выдохлись, а загадочные проблемы продолжают появляться, иногда требуются нестандартные решения. Когда вам любой ценой нужно завершить проект, то на кону стоит всё… В паре классических статей, изначально опубликованных в дружественном журнале Game Developer magazine, мы изучили несколько потрясающих примеров таких решений из реальной жизни. Эти нестареющие шедевры можно прочитать здесь (перевод на Хабре) и здесь.
Gamasutra ещё раз решила рассмотреть эту тему. Мы собрали со всей игровой индустрии необычные решения необычных проблем. Те, кто поделился с нами этими решениями, могут и не гордиться такими «исправлениями», но на самом деле гордиться им стоит. Им удалось выпустить игру, они ничего не испортили и, что важнее всего, никто ничего не заметил. По крайней мере, до этой статьи.
Насладитесь изобретательностью, подивитесь бесстрашию, научитесь на ошибках своих предшественников, и самое важное — выпускайте работающие игры, и тоже в срок.
Если вы хотите поделиться своими удивительными решениями, придуманными для выпуска игр, то мы с радостью о них узнаем! Присылайте свои грязные трюки в Gamasutra (с темой письма «dirty coding tricks») и, возможно, они будут представлены в следующей статье.
День, когда у Super Time Force сели батарейки
![](https://www.gamasutra.com/db_area/images/news/310570/ss_6f14d3d3de1e3d7ff3a22219f1e71d3264947b1c_1920x1080.jpg)
Может быть, этого и незаметно, но Super Time Force едва умещалась в пределы памяти Xbox 360. Из-за функции перемотки времени нам нужно было хранить всю информацию каждого активного объекта уровня в течение всей длительности перематываемой шкалы времени. Каждый новый игрок, враг, пуля, взрыв, платформа, куча мусора и оторванная часть тела отъедала память перемотки, и эта проблема отравляла весь процесс разработки игры.
На последнем этапе сертификации, после дотошной отладки идеального баланса каждого уровня и буфера перемотки мы получили от отдела контроля качества отчёт о новой ошибке:
«Начните любой уровень. Как можно быстрее нажимайте все кнопки на контроллере в течение двух минут. Перемотайте назад и повторите это ещё двадцать раз. Память исчерпана».
Быстрый «спамминг» кнопок съедал память перемотки быстрее, чем это ожидалось от ввода пользователя. Вместо того, чтобы возвращаться в самое начало и полностью менять баланс файлов уровней и размеров буферов, мы остановились на более простом решении: распознавать длительные интервалы неразумно быстрого нажатия кнопок и немедленно самоуничтожать игрока, а затем перематывать его обратно на начало уровня. Мы «притворились», что игрок при яростном нажатии на кнопки случайно включал функцию перемотки. Теперь баг превратился в фичу.
Несколько дней спустя мы получили ещё один отчёт об ошибке:
«Начните 199X уровень 2. Пройдите уровень, взрывая всё подряд и оставляя как можно больше обломков, непрерывно стреляя из пулемёта, пока не закончится время. Перемотайте назад и повторите так ещё двадцать раз. Память исчерпана».
Предел памяти перемотки оказалось можно достичь в неприлично редком случае появления на этом конкретном уровне определённого количества пуль и взрывов, создающих обломки. И снова, вместо изменения баланса файлов уровня и размеров буферов игры мы пришли к более простой идее: когда игра приближается к пределу памяти перемотки, мы просто ставим игру на паузу, выводим на экран огромный мигающий значок «низкого заряда батареи» и изящно выкидываем игрока в меню выбора уровня.
Нет, на самом деле у контроллера не разрядился аккумулятор. Нет, мы никому ничего не объясняли. Да, отдел контроля качества принял это исправление и мы прошли сертификацию.
Кеннет Юнг, технический директор Capy Games
Дополнительный тахометр
Я работал ведущим программистом гоночной игры для PS2 и PSP, параллельно разрабатываемой для PS3 и 360.
Отдел контроля качества жаловался, что управление автомобилем слегка отличалось от управления в других версиях игры. Оно ощущалось не очень естественным. Нам не удавалось найти проблему, поэтому мы пригласили одного из тестеров в наш офис, чтобы обсудить это. Он поиграл в игру у нас и подтвердил, что проблема не возникает в офисе, однако проявляется в сборке для отдела качества.
Мы попробовали сузить расхождения между сборкой для QA и нашей тестовой сборкой, и обнаружили, что различия в управлении были связаны со счётчиком частоты кадров, который мы выводили в углу экрана тестовой сборки. Отключив его, как в master-сборке, которую использовал отдел контроля качества, мы действительно почувствовали, что управление ощущается немного иначе. На самом деле, оно становится лучше. Мы потратили какое-то время на слепое тестирование (закрыли ту часть экрана, на которой выводился счётчик кадров и играли со включенным и выключенным счётчиком), чтобы самим убедиться, что дело было именно в этом. Разница казалась несущественной и её сложно было распознать. Одно было очевидно — вывод частоты кадров «исправлял» проблемы с управлением.
Мы потратили пару недель на поиск причин этой проблемы. Мы исследовали код физики, который нам передала команда, работавшая над другими версиями игры, искали неинициализированные переменные (на которые могло повлиять состояние стека поле процедуры печати шрифта) или возможные проблемы с таймингами. Мы пробовали инициализировать память. Но не нашли ни причины, ни решения.
Последнее, на что можно было надеяться — проверить, влияет ли перемещение счётчика частоты кадров за пределы экрана на управление машиной. Оказалось, что место вывода частоты кадров ничего не меняло, даже если счётчик находился за пределами экрана.
И только во время последнего теста, накануне сертификации игры мы догадались до решения проблемы — если не до её причины. Мы выпустили игру с постоянно включенным отладочным счётчиком частоты кадров, только выводили его слегка за правой границей экрана.
Мартин Тёртон, директор Clever Beans Ltd
Унесённые бе́лками
![](https://www.gamasutra.com/db_area/images/news/310570/tq7.jpg)
Самым бесспорно грязным трюком, запомнившимся из разработки Titan Quest, стало управление скриптингом событий. Технология квестов/событий имела серьёзную слабость — после срабатывания действия не было никаких способов его отложить. Поэтому если мы хотели, чтобы что-то произошло через пять секунд после того, как игрок пробежал через какой-нибудь ограничивающий объём, то мы никак не могли установить задержку. Действие всегда было мгновенным.
Уже близился конец разработки, поэтому было сложно просить введения дополнительных функций, разработчики и так уже изо всех сил пытались успеть сдать всё необходимое для следующего этапа. Один из тестеров отдела контроля качества начал помогать нам с работой над скриптингом, и выяснил, что на самом деле есть способ отложить срабатывание события с помощью изменения длительности анимации.
В результате он взял бе́лок, которые в игре были существами окружающей среды, и использовал их в качестве таймера анимации. Так они стали механизмом расчёта таймингов по умолчанию. Тестер создал невидимую версию бе́лки, которую располагал в нужных нам местах уровней, а затем привязывал весь отсчёт времени к длительности её анимации ожидания. Благодаря этому творческому решению проблемы в следующем проекте его повысили до дизайнера.
Артур Бруно, владелец/ведущий дизайнер Crate Entertainment
Рекламофобия
В последней версии нашей игры появилась новая функция, дававшая игрокам внутриигровую валюту за просмотр видеорекламы (что также повышало наши доходы). После выпуска игры мы обнаружили, что видеореклама запрашивалась неправильно, из-за чего за игровую сессию воспроизводилось всего одно видео — серьёзная неприятность.
В нашей игре использовалась инфраструктура на стороне сервера для выполнения различных действий в разных случаях, позволяющая нам расширить функционал игры после выпуска. Система проверяла правила, и если они выполнялись, то запускала заданные действия.
Правила оценивались по рефлексии. Например, при задании правила VideoAds.IsVideoAvailable = true с помощью рефлексии вызывалось это свойство и действие выполнялось, если свойство имело значение true.
К счастью для нас, эту систему можно было запросто взломать, поэтому мы добавили новой правило VideoAds.RefreshVideos = true. Это правило никогда не было равно true (поэтому действие никогда не выполнялось), но оно вызывало код, обновляющий видео, что позволило нам «заставить» систему использовать примитивный механизм исполнения удалённого кода. Проблема решена!
Лиор Тал, CEO Cyanogen
И… снято!
Мы работали над серьёзным обновлением для игры под Android за две недели до «выхода на золото». Отдел контроля качества сообщил нам, что на некоторых случайных устройствах после воспроизведения катсцены происходит сбой. Мой коллега потратил неделю, пытаясь изолировать ошибку или выяснить причину. Мы так её и не нашли. Но мы обнаружили, что при нажатии кнопки «назад» для пропуска видео сбой не происходит. Наш грязный маленький трюк состоял в том, чтобы поставить в катсцену таймер и за одну секунду до её завершения симулировать нажатие кнопки «назад». Мы использовали его как временное решение проблемы. Шесть месяцев спустя это «временное решение» по-прежнему было в коде.
Марлон Рувалкаба Муньос, Karaokulta
Чёрный лёд, белый шум
![](https://www.gamasutra.com/db_area/images/news/310570/black%20ice.jpg)
При работе над Black Ice я хотел создать небо, которое выглядело бы как бесконечная комната (как на скриншоте), но расположение сотен объектов в небе снижало производительность, а зеркала в играх с 90-х годов были не очень жизнеспособны. Поэтому я решил реализовать это с помощью частиц. Всё было довольно просто — я написал скрипт, чтобы расположить их в мире, но тут возникла проблема: частицы исчезали, когда игрок отворачивался от точки начала координат мира.
Мне понадобилось какое-то время на то, чтобы выяснить, что legacy-система частиц Unity отключала все частицы в системе, когда невидимый эмиттер частиц находился за пределами обзора камеры. (Все ведь знают, что такое отсечение по пирамиде видимости?) Я достаточно долго боролся с проблемой, но однажды ко мне пришло решение — я присоединил эмиттер к лицу игрока, примерно на шесть дюймов ниже. Таким образом игрок никак не мог бы отвернуться от эмиттера, в какую бы сторону не смотрел! Мне пришлось изменять испускание частиц на основе положения в мире и обновлять их при движении игрока, но это сработало!
На GIF ниже показано, как это выглядит в редакторе и в игре.
В редакторе
![](https://www.gamasutra.com/db_area/images/news/310570/blackice3.png)
В игре
Гарретт Купер, создатель игр, Super Duper Game Company
Отправляйся прямиком в тюрьму
Когда я работал в Backbone Entertainment, мы с Кевином Уилсоном работали над крайне напряжённым проектом по переносу аркадных игр Midway на PSN. Это было самое начало эпохи PS3. Кажется, среди первых одиннадцати доступных для загрузки игр были наши: Joust, Championship Sprint, Rampage World Tour, Rampart и Mortal Kombat 2, и ещё какая-то подобная дичь.
Backbone ранее выпустила эти игры в XBox Live Arcade, но они были разработаны не очень кроссплатформенно. Проект необходимо было сворачивать буквально за несколько недель, поэтому мы сделали то, что сделал бы любой с такой временно́й нагрузкой: частично реализовали Direct X на PS3. Последнюю неделю проекта я потратил на сокрытие следов.
Иэн Шерман, программист Other Ocean
DLL-it yourself
Клиент, очень озабоченный сокрытием своего «ноу-хау», передал нам несколько DLL только для наших целевых консольных платформ, то есть библиотеки в сущности оказались «чёрным ящиком». Нам упорно не давали никаких библиотек для PC, как бы мы ни упрашивали. Весь фронтэнд игры выполнялся на PC, а в коде была только заготовка движка, достаточная для запуска геймплея, но мы не могли протестировать работу настоящей игры на PC, и это не устраивало нас по множеству причин.
Мы прошли таким образом весь цикл разработки для PS3/X360. Затем, для следующей итерации игры мы перешли на Xbox One и PS4, получив обновлённые версии библиотек движка, но по-прежнему без версии для PC, что очень осложнило нашу работу, особенно на PS4.
Но случилось волшебство — библиотеки для Xbox One на самом деле оказались полностью рабочим 64-битным кодом для PC, и их можно было просто подключить к исполняемому файлу Windows. Достаточно было иметь PC с довольно новым ЦП, содержавшим те же расширения наборов инструкций, что и ЦП на Xbox. Мы радовались, как дети, когда эту систему удалось заставить работать.
Эпилог — на следующем цикле, когда мы делали версию для Steam, клиенты наконец-то расщедрились на настоящую библиотеку для PC, поэтому хак оказался ненужным.
Дэн Филнер
Мост слишком далеко?
![](https://www.gamasutra.com/db_area/images/news/310570/GrimDawn.jpg)
Это больше похоже на kit bash (прим. пер.: создание чего-то нового из стандартных заготовок, в том числе в трёхмерном моделировании), чем на программный трюк, но когда я начал работу над Grim Dawn, то практически работал в одиночку. Было несколько знакомых, которые помогали мне в свободное время (в основном бывшие коллеги по Iron Lore), но в полную силу работал я один. Несколько месяцев спустя ко мне присоединился программист, но до выхода на Kickstarter у нас не было собственного художника. В результате я потратил часть личных сбережений на найм художника, и одним из первых созданных мной объектов был деревянный мост. Он состоял из плоских деревянных досок, длинных скруглённых балок и металлических железнодорожных костылей, скрепляющих древесину, как гвозди.
Иногда в команду приходили волонтёры, оказывались слишком занятыми работой и семьёй, и потом пропадали. Я дошёл до этапа, на котором появлялось не так много новой графики. Я не художник, мои навыки ограничены созданием текстур из фотографий и простейшими основами «моделирования». На самом деле, у меня не было особого выбора, кроме как с переменным успехом изменять готовые объекты и исправлять UV-карты.
Но мне отчаянно было нужно больше объектов окружения, чтобы можно было продвигаться дальше в построении мира. Поэтому мне пришлось открыть в редакторе этот мост и использовать его отдельные части для создания новых деревянных строений. В результате у меня получилось из него достаточно много объектов. Другие мосты, выложенные из досок тропинки, входы в дома, заборы, кучи мусора, виселица, которую видно на начальном экране, указатели, стол, крыши домов… После выхода на Kickstarter, когда я смог нанять на полную ставку художников, часть этих объектов была переделана, но фрагменты этого первого моста до сих пор используются во многих предметах.
Артур Бруно, владелец/ведущий дизайнер Crate Entertainment
Звучит неплохо!
![](https://www.gamasutra.com/db_area/images/news/310570/843339-mega-man-legacy-collection-windows-screenshot-main-menu-screen.jpg)
Работая над Mega Man Legacy Collection для 3DS, я обнаружил «баг» со звуком, который никак не мог отследить. Любой первый воспроизводимый звук или искажался, или проигрывался неправильно.
Я сам писал слой воспроизведения звука, но он был основан на звуковом API Nintendo для 3DS. Система воспроизведения должна была поддерживать непрерывное потоковое проигрывание таких вещей, как фоновая музыка или эмуляция звука NES (последнюю писал не я), плюс короткие небольшие единоразовые звуки для таких действий, как эффекты UI и демонстрация начального логотипа.
Каждый из звуковых «каналов» 3DS передавал с собой структуру данных, содержащую различные флаги и информацию для отслеживания текущего состояния. Одним из них флаг, определяющий, является ли канал активным или воспроизводящимся. В официальной документации Nintendo говорилось, что флаг имеет значение true, если канал что-нибудь воспроизводит, и false в противном случае.
С этим у меня появилась пара багов, корневую причину которых мне не удалось найти из-за нехватки времени. Говоря попросту, в девяти из десяти случаев при запуске игры мелодия, сопровождавшая логотип Digital Eclipse [разработчика коллекции игр] по-разному искажалась — она заикалась или вообще не воспроизводилась. Это был самый первый звук в игре, и я выяснил, что ошибка всегда происходит с первым воспроизводимым звуком — последующие звуки проигрываются без проблем.
Когда я принялся за отладку, то выяснилось, что в некоторых случаях этот флаг «воспроизведения» имел значение true, даже когда ничего не проигрывалось! Очевидно было, что мы не можем выпустить проект в таком состоянии, а у меня уже закончились все умные идеи. Так каким же стало моё решение?
При загрузке игры, перед воспроизведением этой первой мелодии, я проигрывал секунду тишины. И в таком состоянии проект был выпущен.
Кит Кэйзершот, программист Digital Eclipse