[Из песочницы] Браузерная 3D WebGL игра с возможностью установки в IndexedDB
Запаситесь попкорном — я поведаю вам интересную историю… В общем, это будет одно из тысячи сочинений на тему «Как я написал свою игру». Сначала я планировал осветить как можно больше технических деталей, но потом понял, что их слишком много для одной статьи и она получится огромной. Поэтому «первая серия» будет, скорее, обзорной. Если будет интересно, то продолжу. Итак.
Идея!
Мой опыт программирования ограничивался парой приложений под социальные сети, когда мне в голову пришла идея воссоздать игру типа «Монополии», в 3D. В детстве у нас с друзьями было что-то вроде клуба любителей настольных экономических игр, коих в общей сложности в нашем арсенале насчитывалось порядка десяти. А теперь, когда они ушли каждый в свои дела или вовсе куда-либо разъехались, а объединяет нас только Интернет, я захотел создать электронную версию по мотивам, так сказать, разных экономических игр. Но раз уж это виртуальная реальность, то все должно выглядеть, как в реальном мире: на поле должны возводиться дома, а вместо фишек у игроков должны быть личные автомобили, которые нужно приобретать в автосалоне…
Я предположил, что моя идея не нова и погуглил (а также пояндексил — это не реклама, просто — ради справедливости). К своему удивлению, я обнаружил, что большинство 3D версий подобных игр сводится к вращающимся трехмерным доскам с трехмерными, но, опять же, просто фишками и привычными карточками предприятий. Только на XBox существовало некое подобие 3D города, но концепция самой игры там была, вроде бы, далека от классической, впрочем, я не играл. Еще я нашел очень старый 3D клон «Монополии» под Windows. Да в одной соц.сети работала нормальная 3D «Монополия». Но в той был вид сверху-сбоку-издалека, в изометрической проекции. Мне же хотелось прокатиться по улицам городка и узреть предприятия глазами героя игры.
Забегая вперед, сказано — сделано. Между этими событиями прошло 10 месяцев. Не так уж и много, учитывая то, что я работал практически в одиночку. Сразу предупреждаю, что, поскольку я во всем разбирался самостоятельно, то графика в игре весьма далека от идеала, а код крайне вреден для просмотра профессиональным программистам. Я не использовал ООП, поскольку, во-первых, плохо им владею, а во-вторых, не вижу смысла его применять в JavaScript. Поэтому — только функции, только хардкор. В разработке применялся шаблон КВГ — костыли, велосипеды, грабли. А по поводу 3D… Например, о том, что такое wuv-mapping (как это правильно перевести на русский?) в 3D редакторе, я узнал только спустя примерно 4 месяца после начала работы… И еще, какая фраза относительно велосипеда хороша, лишь произнесенная впервые?
Мне помогал только «2D дизайнер», который нарисовал забавных человечков. К сожалению, в первой версии игры не будет 3D персонажей. И это — задача на будущее.
Смысл игры, как несложно догадаться, сводится к тому, чтобы по очереди «ходить» (то есть ездить на автомобиле) по «полю» (то есть по городу) и строить свои дома-фирмы. Экономика была слегка изменена и усовершенствована относительно других подобных игр. В банке можно брать кредит, а на бирже — покупать акции. Можно спекулировать товарами, а также сжигать здания конкурентов. В игре есть полиция, суд и тюрьма. Промелькнула еще мысль дать возможность самим игрокам играть за представителя правопорядка. А также ввести еще такого персонажа, как «ночная бабочка»… Видимо, эта идея была навеяна длинными вечерами, занятыми программированием. Но играть в «Монополию» за полицейского или жрицу любви — это наверно уже тема для следующей части или мода какого-нибудь… Поскольку игра планировалась к запуску в одной социальной сети, то валюта игры была негласно названа «котики».
Задачи
Вообще говоря, задачи с самого начала были поставлены весьма амбициозные.
1. 3D. Нужно было, чтобы все в итоге работало в 3D.
2. Кроссбраузерность и кроссплатформенность. Поскольку у моих друзей разные операционки, то нужно было, чтобы игра запускалась на любой ОС. Ну и в различных браузерах, естественно.
3. Установка. Чтобы можно было (по желанию пользователя) сохранять модели и текстуры в файловую систему — для уменьшения времени загрузки и экономии трафика при последующих запусках. А заодно и для экономии серверного трафика.
4. И без плагинов! Чтобы ничего не нужно было дополнительно скачивать и специально устанавливать, никаких там «веб-плееров». И даже Flash — ни-ни!
По сути, с переменным успехом (то есть, пока не на всех устройствах заводится в виду отсутствия в них поддержки новых технологий, но, думаю, очень скоро все изменится) это было реализовано. Вообще, почему именно браузерка? Браузер мне видится неким стандартом, объединяющим все операционные системы, этаким ключом к написанию действительно кроссплатформенных приложений, работающих независимо от того, какой процессор и ОС у пользователя, и без установки дополнительных модулей. Мне эта идея кажется очень интересной.
Кстати, лирическое отступление (И тут меня понесло...)
Сегодня написание кроссплатформанных приложений происходит следующим образом. Пишется что-то в какой-либо среде разработки, а затем сохраняются исполняемые модули под все три (или больше) операционные системы. Ну и эти сборки загружаются в соответствующие магазины. Фактически, это просто инструмент для сборки под разные платформы. Нет, все это тоже замечательно, но хочется большего. Чтобы, вот, написал код, и — вуаля, он заработал как есть под любой ОС, в единственной сборке, а все остальное – забота самой ОС.
Конечно, помимо интерпретатора JavaScript, существуют и другие виртуальные машины с соответствующими им языками программирования, но для них, во-первых, требуется отдельная инсталляция клиентского интерпретатора, во-вторых, существующего, возможно, не под каждую ОС, ну и главное — требуются некоторые телодвижения от пользователя с этой самой установкой, чего пользователь обычно делать страсть, как не любит. А веб-технологии, по-моему, движутся как раз в направлении некой общепринятой кроссплатформенности, без установки каких-либо дополнительных движков. Да, JavaScript и WebGL пока медлительны, но, думаю, скоро все изменится. К тому же, такое приложение, по идее, должно будет потом работать даже на еще не существующих пока ОС и браузерах.
Вот, например, системы Android еще не так давно и в помине не было, а теперь есть совершенно новая сверхпопулярная операционка. И, если в будущем появится еще нечто подобное новое (ОС), то там уж наверняка будет браузер с поддержкой всех современных фич. А значит, запустятся и все существующие веб-приложения. Ведь, согласитесь, глупо будет выпустить планшет без Интернета. Сеть диктует свой стандарт. И, если полностью перейти на программирование по веб-стандарту, то станет неважно, какая ОС установлена у пользователя. И, кстати, в дальнейшем, скорее всего, это приведет к тому, что начнут появляться всякие фирменные ОС или, там, ОС, заточенные под конкретные задачи, и т.д… Так, ладно, не отклоняемся от темы.
Разработка
В качестве языков программирования была выбрана незатейливая связка JavaScript + PHP. PHP — потому что он мне знаком и потому что в данном проекте не требовалось какого-то лютого реал-тайма на сервере: это не стрелялка и не гонки. В качестве 3D движка — библиотека THREE.JS. Последняя привлекла меня тем, что не требует от пользователя установки. И, если браузер и видеокарта игрока поддерживают WebGL, то игра запускается без лишних вопросов. Не нужен даже пресловутый флеш-плеер, который, кстати, у меня на планшете до сих пор не установлен, а моя игра работает. Да и попросить пользователя обновить, скажем, браузер не так неприлично, как предложить установить какой-нибудь не знакомый ему непонятный многомегабайтный сторонний движок, да еще не факт, что существующий под его ОС. Поддерживается эта «красота» (WebGL) во всех новых версиях браузеров, включая IE11. О, да, бросить вызов «Ослу»! Шучу, не ослом единым, конечно… Впрочем, в IE11 тоже работает, только FPS там заметно ниже, чем у конкурентов.
Для возможного хранения (по желанию пользователя) «тяжелых» моделей и текстур на клиенте я использовал IndexedDB. Я написал несложный менеджер, который позволяет выбрать вариант установки (минимальная, обычная, полная) и последовательно пишет файлы в браузерную БД. Эта база сохраняется даже после выключении устройства. А движок игры читает файлы оттуда, ну либо подгружает с сервера те файлы, установка которых не была произведена (или завершена). Естественно, присутствует и вариант удаления. Менеджеру просто скармливаются варианты установки и списки файлов. Назвал я это все WEB5, не знаю, по аналогии с HTML5 что ли. Надо же было как-то назвать.
И еще. Для целей программирования мне не потребовалась никакая особо «заумная» среда разработки. Все (html, php, js) было набрано в программе типа продвинутого блокнота с подсветкой синтаксиса. И примерно 1% кода был набран на работе в навороченном html-редакторе, просто потому что он там был. Отладка производилась при помощи консоли браузера.
В самом начале, переходя от задумки к работе, я занялся изучением документации по библиотеке THREE.JS, которая в основном представлена на английском языке, да и то весьма скудно. Поэтому в каких-то нюансах приходилось разбираться императивным путем на «испытательном полигоне» — отдельной сцене. Бывало так, что уходило несколько вечеров на то, чтобы методом экспериментов лишь додуматься до того, как сделать то или иное.
На основной же сцене очень медленно, но верно шло строительство игры. О том, как создавать территорию, я понятия не имел, поэтому я разбил поле на квадраты, создал для них несколько видов текстур – с различными поворотами дорог и травой. И просто программно расположил их в нужном порядке. Сейчас я понимаю, что есть и более изящные способы генерации территории, и это повод для будущего обновления. Благо оно возможно в любой момент времени и производится просто путем заливки новых файлов на сервер.
С 3D моделями — отдельная история бесчисленных экспериментов с форматами, способами загрузки в игру для обработки на js, съезжающими или вовсе не отображающимися текстурами и т.д. С этим я сильно намучился. К тому же, я до этого никогда раньше не работал с 3D-редакторами. Думаю, если бы я знал эту науку, то срок разработки игры сократился бы вдвое. В конце концов, я остановился на поддерживаемом 3D Max’ом и Blender’ом формате *.3ds и конвертации его в *.json при помощи конвертера Assimp2json. А json-модель уже в работающей игре спокойно грузится с сервера (или из IndexedDB) при помощи загрузчика из комплекта THREE.JS — AssimpJsonLoader (слегка допиленного мной, чтобы он умел работать также и с моим «менеджером» IndexedDB, то есть, мог бы грузить не только с сервера, но и из клиентской базы). И цвета сохраняются, и с текстурами все нормально. К тому же, json — родной формат JavaScript, что в дальнейшем еще сыграло свою положительную роль. Модели домов и прочую мелочевку делал сам, деревья и автомобили частично сделал сам, частично скачал из бесплатного 3D-арта и преобразовал в лоу-поли. Для того, чтобы не делать десятки разного вида, но одинаковых по конструкции домиков (а нужно для всех десяти возможных цветов игроков сделать по каждому из десяти типов предприятий каждого из 3-х этажей), я создал программную систему смены цвета и подгрузки нужной текстуры. А для табличек с адресами домов (а куда ж без них) программно создаются и применяются canvas-текстуры, которые в свою очередь компонуются из единого png-изображения, содержащего все названия улиц и номера домов.
Моей радости не было предела, когда на поле появился первый домик. Причем, такого цвета, какого было нужно, и в том месте, где было нужно. И с адресной табличкой. Затем я запрограммировал примерно то же самое для автомобилей, вспомнив при этом формулы движения из физики. А заодно и алгебру с геометрией. («Будет тебе и ванна, и кофэ. И какао с чаем».)
Теперь нужно было создать «отдаленные пейзажи» или попросту «задники». Как они делаются — до сих пор понятия не имею. Если подскажете, где об этом можно почитать, то буду признателен. Покопавшись в своих фотках, я нашел 4 пейзажа, из которых сделал текстуры (вид Петербурга с Финского залива, вид на Кронштадт, просто вид на залив и лес в Вологодской области). Программно натянул их на 4 плоскости и расположил их со всех сторон игрового поля. Но проблема была в том, что по причине бокового освещения сцены, на «небе» были видны границы этих плоскостей. Я посмотрел несколько примеров из пакета THREE.JS, но они мне не подошли. Огромная сфера с внутренней текстурой меня не устроила, поскольку мое поле квадратное, да и треугольников в той сфере было слишком много, что создавало тормоза. Куб с текстурой подходил только для интерьера, в экстерьере виднелись те же границы плоскостей. В итоге я просто сохранил текстуры в формате png с прозрачной альфой на месте «неба» (подобрав для каждой плоскости яркость) и задал сцене глобальный фоновый цвет под небо. Наверно, я сейчас пишу какие-то глупости, и нормальный 3D-дизайнер ужаснулся такому подходу.
Монетизация
Мне изначально не хотелось «драть» с игроков слишком много, но было бы очень желательно, чтобы окупились расходы на хостинг и на божественный напиток. Поэтому я предусмотрел три варианта покупки внутри игры: можно приобрети 1, 3 или 10 «слитков золота», каждый из которых дает возможность сыграть в игру один раз. Если выиграть, то вы получите все слитки этой игры. В случае, если у игрока остается менее двух слитков, то он теряет VIP-статус. Собственно, можно играть и без него, тогда становятся недоступными некоторые возможности, которые, в общем-то, не сильно влияют на игровой процесс.
Результат
Подведу итог. Чего в итоге удалось достичь.
1. 3D. Однако, пока есть проблемы с самой графикой, а именно, с запеканием текстур и прочими примочками и красивостями. Но я в свободное время занимаюсь изучением всего этого. Текстуры будут обновлены.
2. Кроссплатформенность. Игра работает во наиболее свежих версиях браузеров при установленных относительно новых драйверах видеокарты.
Что касается Windows, то без проблем запускается на планшете с Windows 8.1 (fps до 40), а также на компьютере с Windows 7 на всех новых версиях любых браузеров, включая IE11, только IE отличается довольно низким fps. На другой тестовой машине с Windows XP (P4 3GHz, Radeon R5 230) заработало только в Chrome не самых свежих версий в районе 28.0.1500.95 с отключенным автообновлением. Возможно, это связано с тем, что более новые браузеры требуют для работы с WebGL более новых версий драйверов видеоадаптера и просто блокируют WebGL, если установлены драйвера ниже определенной даты релиза. А в более старых браузерах, но уже начавших поддерживать WebGL, такого ограничения либо нет, либо оно ниже.
Под Android также работает в свежих браузерах. Если не хватает оперативки, то всегда можно использовать 2D-вариант.
И, наконец, на iOS тоже работает, однако, тестировалось только на iPhone-5 друга. Результат в 3D – fps 3 кадра в секунду. Но это всё-таки телефон… Тестирование на нём первый раз проводилось уже в самом конце работы над игрой и, честно говоря, я был даже удивлён, что всё заработало с первого раза и заработало вообще. iPad’ов для теста у меня нет, но, наверно, там будет явно лучше, чем на iPhone, то есть, сравнимо с планшетом на Windows.
В каких-то ещё, других, ОС не тестировалось.
3. Установка.
Я долго воевал с IndexedDB. В итоге получился фреймворк, которому можно скормить список файлов в виде ассоциативного массива, составленного определенным образом. Эти файлы последовательно загружаются и сохраняются в базе для дальнейшего использования off-line. Основная проблема заключалась в том, что невозможно проверить существование базы данных и ключей (таблиц и записей в них) в IndexedDB (то есть, проверить, установлена игра или нет), а можно только попытаться создать их и получить ответ в виде успеха или неуспеха этой операции. Неуспех — это, соответственно, если они уже существуют (ну или БД не поддерживается, но для проверки этого факта есть другая функция), иначе они создаются. В итоге, пришлось при каждом запуске игры задавать создание пустых таблиц и небольшого конфига в одной из них, куда, при успехе, пишется информация уже о том, что игра не установлена, ее варианты установки и т.д. При неудаче — значит, игра уже была установлена или создан пустой конфиг с записью о прогрессе установки. Впоследствии, при действиях пользователя, фреймворк берет сведения из этого конфига и изменяет его. С удалением данных я так до конца и не разобрался. Нет, все удаляется, я лишь не могу отловить событие завершения этого процесса. С установкой же — все в порядке. И еще следует учесть тот факт, что в каждом браузере – своя, отдельная база данных, и, установив игру в один браузер, вы не получите доступ к этой же установке через другой. Очистка истории браузера тоже может влиять и на IndexedDB.
4. Отсутствие необходимости установки пользователем сторонних клиентских библиотек, интерпретаторов, движков и т.д.
Ценой за это стала первоначальная загрузка с сервера каждый раз примерно 1,1 Мб javascript кода, включая движок THREE.JS, плюс 3,5 Мб изображений. Не так уж и много, ведь, в конце концов, это не просто сайт, а 3D игра. К тому же, все это сохраняется в кэше браузера. Ну а остальное (3D модели, изображения) может загружаться по ходу игры с сервера или из IndexedDB. Кстати, и те 3,5 Мб изображений тоже могут загружаться из IndexedDB. Но достигнута одна из целей — для игры не нужен никакой нативный (относительно ОС) движок. Можно, конечно, будет еще и часть скриптов покидать в базу и сделать их подгрузку оттуда. Подключение к Интернет, в любом случае потребуется, так как работает еще серверная часть для мультиплеера. Впрочем, есть идея еще выпустить полностью локальную версию с игрой против искусственного интеллекта, то есть, без сервера, и запускающуюся просто по html-файлу.
Публикация
Игра была одобрена модератором целевой социальной сети и опубликована в общем каталоге. Однако, к подтверждению была прикреплена оговорка, что игра не имеет возможности попасть в топ новых приложений. На мой вопрос почему, я пока ответа не получил. В итоге — 240-е место в «Экономических играх» и уж даже не знаю, какое — в общей выдаче. Тем не менее, за первые сутки – 85 установок. И плюс 40 покинувших игру. Покупок пока, конечно, нет. Нагрузка на серверную часть, при этом, за сутки составила 0.16 из 50 по CPU и практически 0 из 1000 по MySQL.
Будем продвигаться, улучшать игру и запускаться на других площадках и социальных сетях.