Эта история о том, как я делал очередную 3D веб-игру. История терзаний и сомнений, история недосыпаний и лени. История о том, как все сделать в самый последний момент. В общем, чего тянуть кота за рога – перейду к рассказу. Но сперва – еще кое-что, чтобы покончить со всеми формальностями. «Мадам, вам кофе в постель?» «Нет, лучше в чашку». Кофе был моим ежедневным спасением из лап Морфея, особенно когда я хотел поработать над игрой с утра, перед всеми остальными дневными заботами. Надо отдать ему должное. Я просто не могу не упомянуть о нем, так как для меня это стало воистину одной из составляющих успеха, под коим я понимаю доведение игры до релиза. (Здесь могла быть ваша реклама кофе).
Конкурс
На самом деле, я вписался не в тот конкурс, для которого я бы мог что-то сделать. По его условиям требовалось создать игру под Windows, скачиваемую и запускаемую по exe-файлу. Я же люблю программировать под браузеры. Я не знаю C++ и C#, у меня даже нет Visual Studio. Но тут внезапно у меня появилась отличная идея игры, и я подумал – а какого черта! Буду просто делать игру. А получится ли соблюсти все условия конкурса или нет – не так важно. В конце концов, просто запущу ее в социальных сетях.
Нет предела совершенству
Моя предыдущая игра запускалась по php-файлу с сервера. На этот раз я решил пойти дальше. Мне захотелось, чтобы все работало не только в Интернете, но и из файловой системы, без локального веб-сервера совсем. Во-первых, автономной версии требовали условия конкурса, а, во-вторых, чтобы можно было хотя бы самому поиграть в пути, например, где нет Интернета. (Вообще, все, что я делаю, я делаю для себя. И сейчас играю в свою игру.) Но при необходимости – и с сервера тоже, с людьми, а не с ИИ, то есть, такой вариант тоже должен присутствовать. В общем, задача состояла в том, чтобы создать универсальную сборку со всеми скриптами, 3D моделями, текстурами и звуками для распространения как на странице в Интернете, так и в виде архива, который можно было бы скачать, распаковать и просто запустить игру по index.html. Конечно же, последний вариант имеет смысл только для однопользовательской версии.
По сути, вышеупомянутый локальный вариант представляет собой сохраненную локально веб-страницу с относительными путями. Загвоздка в том, что там содержится не только текст с картинками, но еще и 3D движок, а также, модели с текстурами. Впрочем, с самим движком нет никаких проблем. Это THREE.JS, он написан на JavaScript, весит 500 Кб и подключается просто тегом SCRIPT. Однако, движок не умеет загружать 3D модели в из локальной файловой системы, а хочет тянуть их ajax-ом с сервера. Пришлось допилить загрузчик для этого, чтобы модели тоже подключались из файлов скриптов. Обратите внимание на адресную строку.
Первоначально созданные мной 3D модели для веб-версии хранились в файлах вида model.json, однако, я обнаружил, что при подключении их тегом SCRIPT все работает в Firefox, но в Chrome выдает ошибку, связанную с политикой безопасности. Решение оказалось простым: переименовываем json в js – и никаких проблем. Ну, наверно, можно было бы принудительно поставить нужный content-type, но кто знает, какие, там, в будущем еще появятся политики безопасности в браузерах. Вдруг они все равно не будут разрешать загружать скрипты из файлов, называющихся иначе, чем *.js, из локальной файловой системы. А так, js – и никаких вопросов. Загружай скрипт и не выпендривайся. Загрузка 3D модели:
var el=document.createElement("script");
el.type="text/javascript";
el.src=url+'.json.js'; el.async=true;
document.getElementsByTagName("head")[0].appendChild(el);
Также из-за политики безопасности браузера текстуры моделей, которые прекрасно вели себя в версии с сервером, наотрез отказались подключаться из своих файлов png и jpg, расположенных локально, поэтому пришлось их конвертировать в base64 и оформить тоже в виде скриптов, с именами файлов типа texture.png.js. Ну а эти скрипты подключать старым добрым тегом SCRIPT, динамически создаваемым. Это очень просто!
var image = document.createElement( 'img' );
image.onload = function() {
var tex = new THREE.Texture( image );
tex.needsUpdate = true;
tex.wrapS = tex.wrapT = THREE.RepeatWrapping;
tex.anisotropy = 5;
};
image.src="data:image/gif;base64,"+imagedata.replace(/^data:image/(png|jpg);base64,/, "");
Работает так: мой парсер модели находит в ее файле ссылки на изображения, эти ссылки добиваются окончаниями .js, динамически подключаются скрипты с картинками текстур, картинки переводится из base64 и накладываются на модель. А для того, чтобы уж наверняка, железно, определить момент окончание загрузки скрипта, я каждый такой скрипт дополнил в конце вызовом функции, сигнализирующей основной программе о том, что он загружен и с содержащимся в нем изображением или моделью теперь можно работать дальше.
Средства разработки
Итак, теперь, когда загрузчик моделей и текстур нормально заработал с файловой системой, без какого-либо сервера, я начал писать сам игру. Да, я программирую на чистом JavaScript. Многие на этом месте покрутили пальцем у виска. Я не использую никаких библиотек (кроме 3D движка), даже JQuery не использую. ООП не использую тоже. Прототипы – в редких случаях, только тогда, когда, на мой взгляд, это действительно необходимо. Люблю минимализм и ничего лишнего. И никакого лишнего кода, в котором я не понимаю, что делает каждая строчка!
Открою страшную тайну. Я также не разбираюсь в новомодных менеджерах для сборки проектов, не пользуюсь гитхабом и ни разу не открывал никакое Visual Studio. Доктор, что со мной? Из средств программирования я использую только продвинутый блокнот. Я, наверно, псих.
Однако, мне кажется, что это очень просто – подключить на страницу скриптовую 3D библиотеку, работающую с WebGL, и создать сцену. Кто-нибудь еще сегодня подключает скрипты тегом SCRIPT и создает HTML разметку вручную? Кто-нибудь сегодня вообще нажимает на кнопки пальцами и смотрит в монитор глазами? Этими вот пальцами – по этим кнопкам? Этими вот глазами – в этот монитор? Дикость какая! Ладно, шучу. Но сегодня прикоснуться к HTML или, не дай бог, к чистому JavaScript – это как дотронуться до змеи. Лучше навернуть поверх несколько слоев. И после конвертировать код уже десятью этапами в JavaScript, недоумевая, почему в итоге ни черта не работает. Я никого не осуждаю, просто, мне кажется, что в веб-разработке наблюдается некоторый не совсем здоровый перекос в сторону использования многочисленных средств, менеджеров и библиотек. Надеюсь, мой рассказ не вызовет ни у кого приступ когнитивного диссонанса.
Техзадание? Чего? Самому себе? Диздок? Да ну, вот еще, тратить драгоценные минуты своей жизни на эту чушь. Единственное, о чем я пожалел – что сразу не нарисовал блок-схему алгоритма серверной части многопользовательской версии. В итоге, она заработала неправильно. Но, когда я все же нарисовал на бумажке блок-схему, то сразу увидел все свои ошибки и исправил их.
Творчество
Что мне нравится в индии-разработке, так это творческий процесс. Вообще-то изначально в рамках конкурса, я задумал написать вариацию на тему Color Lines и даже создал работающий первый уровень. Вот, как это выглядело.
Смысл был в том, что игра работает в 3D, а мячи сами не появляются на поле, их туда нужно бросать и составлять в линии одного цвета. То есть, необходимо попадать в нужные лузы в решетке. После чего под мячами открываются створки в полу, и они проваливаются. Но, когда был готов первый уровень, и я сам в него сыграл, то я вдруг понял, что игра получилась не особо интересной. И тогда я решил оставить это до лучших времен, пока мне в голову не придет идея, как улучшить это творение, что, может быть, добавить. У меня появилась другая идея. Бросание мячей вызвало у меня ассоциацию с полетом пушечных ядер. И я решил быстро переделать эту игру в морской бой. Благо, на написание конкурсного проекта отводилось целых два месяца.
Та-дам! Легким движением руки «Линии» превращаются… превращаются… превращаются… В элегантный «Морской бой!» И да, я просто не мог не создать «Черную жемчужину». Какой же морской бой без грозы морей.
3D графика – это, конечно, не моя стихия. Корабли сделал, как мог. С целью снижения нагрузки для определения столкновений я использовал невидимые коллайдеры вокруг каждого корабля. На один корабль — один коллайдер, примерно повторяющий форму.
Таким образом, получился пошаговый морской бой, но в 3D и с возможностью перемещать корабли в любую точку игрового поля. Смысл в том, чтобы, правильно настраивая углы поворота и наклона пушек, попадать ядрами в корабли противника.
Способы поделиться со всем миром
1. Конкурс.
Во-первых, конечно, конкурс. В процессе выяснилось, что организаторов конкурса не устраивает запуск игры по html-файлу и нужен непременно exe. Что там у нас со сборкой экзешников из js? Сначала я попробовал было Electron. Однако, там для меня все оказалось слишком сложно. Требовалось установить кучу каких-то менеджеров с гитхаба и произвести десятки манипуляций по настройке и сборке всего этого. Я так понял, что Electron хочет меня увести на путь стандартной веб-разработки. У меня не было времени с этим разбираться, так как шел последний день отведенного на создание конкурсной игры срока. Нет, это не годится. И тут я наткнулся на утилиту web2exe. Все очень просто – запускаешь ее, тыкаешь в файл html, она даже сама качает node-webkit, и получаешь на выходе сборку с exe-файлом. Что мне не понравилось – так это то, что файл оказался очень большой, 105 Мб. М-да… В то время, как сама игра весит всего 15 Мб. Однако, я нашел упаковочную утилиту, при помощи которой сжал самый большой файл nw.dll. В итоге вся сборка стала весить 68 Мб, а в zip-архиве 43 Мб.
Кстати, web2exe не поддерживает сборку «эезешника» под Windows XP, а жаль. Моя html версия работает и в XP тоже. Только в этой операционке есть некоторые особые требования для WebGL графики в браузерах.
Конкурс я не выиграл, но зато получил бесценный опыт решения, как мне казалось ранее, не решаемых задач. Теперь я уверен, что ничего невозможного нет.
Что ж, пойдем дальше, и будем выкладывать веб-вариант. После окончания конкурса я написал сервер на php. На это ушло около месяца свободных вечеров.
Да, кстати, сервер
Опрашивать сервер на обычном http
Весь серверный скрипт на php, если его представить одной строкой, получился вот таким:
2. Фейсбук
Вообще, выкладывать что-либо в Фейсбук довольно бессмысленно, если ты не компания, специализирующаяся на ААА-играх. Заработать там на внутриигровых покупках простому смертному, назовем так программиста, работающего за идею, довольно сложно, а рекламу сторонних баннерных сетей Фйсбук не разрешает. Только разоришься на
3. ВКонтакте.
Модерация в ВК длилась несколько суток. И игру добавили, как обычно, в самый низ каталога. Зато в ВК можно сразу и без проблем подключать рекламный баннер. Схема монетизации такая же, как в Фейсбуке – отключение баннера. Надо отметить, что рекламная система в ВК очень удобная, простая и понятная. Личный кабинет – выше всяких похвал. Вот только заработать на рекламе там можно очень немного. К тому же, ВК платит только за клики, а не за показы. И в некоторые дни на примерно 200 показов получаешь просто 0 рублей. Мало, кто вообще кликает по рекламе, видимо.
Итог
Отмечу, чего я для себя достиг. Теперь я могу писать однопользовательские игры с использованием графики WebGL, запускающиеся по html-файлу как с сервера, так и из локальной файловой системы. Работает все это в обоих вариантах в Windows, Android и должно работать в iOs и Linux – но эти ОС у меня нет возможности проверить. Также, я могу делать из той же html версии более «тяжелые» сборки с исполняемыми файлами под Windows и iOs (в web2exe есть такая возможность). Весь код пишется один раз на JS и работает во всех вышеперечисленных вариантах. Ну разве что для онлайн варианта для соц.сетей нужно добавить еще серверный скрипт и клиентские обращения к api.
Автор: Kempston