Как я писал игру на конкурс, или чудесное превращение «Линий» в «Морской бой»

в 14:54, , рубрики: javascript, php, three.js, WebGL, Разработка веб-сайтов, разработка игр

Как я писал игру на конкурс, или чудесное превращение «Линий» в «Морской бой» - 1

Эта история о том, как я делал очередную 3D веб-игру. История терзаний и сомнений, история недосыпаний и лени. История о том, как все сделать в самый последний момент. В общем, чего тянуть кота за рога – перейду к рассказу. Но сперва – еще кое-что, чтобы покончить со всеми формальностями. «Мадам, вам кофе в постель?» «Нет, лучше в чашку». Кофе был моим ежедневным спасением из лап Морфея, особенно когда я хотел поработать над игрой с утра, перед всеми остальными дневными заботами. Надо отдать ему должное. Я просто не могу не упомянуть о нем, так как для меня это стало воистину одной из составляющих успеха, под коим я понимаю доведение игры до релиза. (Здесь могла быть ваша реклама кофе).

Конкурс

На самом деле, я вписался не в тот конкурс, для которого я бы мог что-то сделать. По его условиям требовалось создать игру под Windows, скачиваемую и запускаемую по exe-файлу. Я же люблю программировать под браузеры. Я не знаю C++ и C#, у меня даже нет Visual Studio. Но тут внезапно у меня появилась отличная идея игры, и я подумал – а какого черта! Буду просто делать игру. А получится ли соблюсти все условия конкурса или нет – не так важно. В конце концов, просто запущу ее в социальных сетях.

Нет предела совершенству

Моя предыдущая игра запускалась по php-файлу с сервера. На этот раз я решил пойти дальше. Мне захотелось, чтобы все работало не только в Интернете, но и из файловой системы, без локального веб-сервера совсем. Во-первых, автономной версии требовали условия конкурса, а, во-вторых, чтобы можно было хотя бы самому поиграть в пути, например, где нет Интернета. (Вообще, все, что я делаю, я делаю для себя. И сейчас играю в свою игру.) Но при необходимости – и с сервера тоже, с людьми, а не с ИИ, то есть, такой вариант тоже должен присутствовать. В общем, задача состояла в том, чтобы создать универсальную сборку со всеми скриптами, 3D моделями, текстурами и звуками для распространения как на странице в Интернете, так и в виде архива, который можно было бы скачать, распаковать и просто запустить игру по index.html. Конечно же, последний вариант имеет смысл только для однопользовательской версии.

По сути, вышеупомянутый локальный вариант представляет собой сохраненную локально веб-страницу с относительными путями. Загвоздка в том, что там содержится не только текст с картинками, но еще и 3D движок, а также, модели с текстурами. Впрочем, с самим движком нет никаких проблем. Это THREE.JS, он написан на JavaScript, весит 500 Кб и подключается просто тегом SCRIPT. Однако, движок не умеет загружать 3D модели в из локальной файловой системы, а хочет тянуть их ajax-ом с сервера. Пришлось допилить загрузчик для этого, чтобы модели тоже подключались из файлов скриптов. Обратите внимание на адресную строку.

Как я писал игру на конкурс, или чудесное превращение «Линий» в «Морской бой» - 2

Первоначально созданные мной 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 и даже создал работающий первый уровень. Вот, как это выглядело.

Как я писал игру на конкурс, или чудесное превращение «Линий» в «Морской бой» - 3

Смысл был в том, что игра работает в 3D, а мячи сами не появляются на поле, их туда нужно бросать и составлять в линии одного цвета. То есть, необходимо попадать в нужные лузы в решетке. После чего под мячами открываются створки в полу, и они проваливаются. Но, когда был готов первый уровень, и я сам в него сыграл, то я вдруг понял, что игра получилась не особо интересной. И тогда я решил оставить это до лучших времен, пока мне в голову не придет идея, как улучшить это творение, что, может быть, добавить. У меня появилась другая идея. Бросание мячей вызвало у меня ассоциацию с полетом пушечных ядер. И я решил быстро переделать эту игру в морской бой. Благо, на написание конкурсного проекта отводилось целых два месяца.

Та-дам! Легким движением руки «Линии» превращаются… превращаются… превращаются… В элегантный «Морской бой!» И да, я просто не мог не создать «Черную жемчужину». Какой же морской бой без грозы морей.

Как я писал игру на конкурс, или чудесное превращение «Линий» в «Морской бой» - 4

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 графики в браузерах.

Конкурс я не выиграл, но зато получил бесценный опыт решения, как мне казалось ранее, не решаемых задач. Теперь я уверен, что ничего невозможного нет.

Как я писал игру на конкурс, или чудесное превращение «Линий» в «Морской бой» - 5

Что ж, пойдем дальше, и будем выкладывать веб-вариант. После окончания конкурса я написал сервер на php. На это ушло около месяца свободных вечеров.

Да, кстати, сервер

Опрашивать сервер на обычном http хостинге слишком часто не получится. Поэтому будем опрашивать его раз в 10 секунд. На клиенте создается очередь из действий игрока, таких как движение корабля из точки А в точку Б, выстрел и т.д. И в подошедший момент времени отправки данных эта очередь уходит на сервер. Соперник ее читает и у него формируется очередь уже для проигрывания. Все то же: движение, выстрел и т.д., только, с его точки зрения, с кораблями оппонента. Таким образом, у каждого из двух игроков есть две очереди – одна для отправки информации на сервер, другая – для проигрывания действий противника. Тут, конечно, не будет никакой синхронизации, но, так как игра пошаговая, то она и не нужна. Главное – чтобы корабль противника стрелял в итоге из нужной точки, пришедшей с сервера. А маршрут до нее строит программа на клиенте, и в эту точку перемещает корабль.

Весь серверный скрипт на php, если его представить одной строкой, получился вот таким:

Как я писал игру на конкурс, или чудесное превращение «Линий» в «Морской бой» - 6

2. Фейсбук

Вообще, выкладывать что-либо в Фейсбук довольно бессмысленно, если ты не компания, специализирующаяся на ААА-играх. Заработать там на внутриигровых покупках простому смертному, назовем так программиста, работающего за идею, довольно сложно, а рекламу сторонних баннерных сетей Фйсбук не разрешает. Только разоришься на хостинге. Есть, правда, специальный список партнеров, преимущественно американских, через которых допускается размещать рекламу в своем приложении. Но для этого надо через их сайт отправлять им письмо с разъяснением того, чего ты от них хочешь и т.д. Не факт, что они согласятся работать с приложением какого-то парня из России. Да и на большинстве их сайтов, к тому же, я ни слова не обнаружил про Фейсбук… Тоже мне, партнеры. А еще вопрос уплаты налогов, как в США, так и в России. В общем, пробовать с ними договариваться мне как-то сразу расхотелось. И я просто сверстал свой небольшой баннер с названием игры и разместил в нижней части экрана. Его можно отключить, пожертвовав автору некоторую сумму через систему внутриигровых покупок.

3. ВКонтакте.

Модерация в ВК длилась несколько суток. И игру добавили, как обычно, в самый низ каталога. Зато в ВК можно сразу и без проблем подключать рекламный баннер. Схема монетизации такая же, как в Фейсбуке – отключение баннера. Надо отметить, что рекламная система в ВК очень удобная, простая и понятная. Личный кабинет – выше всяких похвал. Вот только заработать на рекламе там можно очень немного. К тому же, ВК платит только за клики, а не за показы. И в некоторые дни на примерно 200 показов получаешь просто 0 рублей. Мало, кто вообще кликает по рекламе, видимо.

Итог

Отмечу, чего я для себя достиг. Теперь я могу писать однопользовательские игры с использованием графики WebGL, запускающиеся по html-файлу как с сервера, так и из локальной файловой системы. Работает все это в обоих вариантах в Windows, Android и должно работать в iOs и Linux – но эти ОС у меня нет возможности проверить. Также, я могу делать из той же html версии более «тяжелые» сборки с исполняемыми файлами под Windows и iOs (в web2exe есть такая возможность). Весь код пишется один раз на JS и работает во всех вышеперечисленных вариантах. Ну разве что для онлайн варианта для соц.сетей нужно добавить еще серверный скрипт и клиентские обращения к api.

Как я писал игру на конкурс, или чудесное превращение «Линий» в «Морской бой» - 7

Автор: Kempston

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js