BattleGIS — JavaScript-движок для игры в Танчики



    Танчики на денди — классический пример синдрома утёнка в плоскости видеоигр. Современные игры настолько круты, что сложно отличить скриншот от фотографии. Однако взрослые дядьки могут часами двигать по экрану восьмибитные пиксели, вспоминая счастливое детство.

    Хотелось сделать чего-нибудь эдакого, чтоб можно было собраться с коллегами в большой переговорке и за разного рода напитками весело провести время. Это должно было быть связано с профессиональной деятельностью: JavaScript`ом или вёрсткой, ведь чтобы погамать в Кваку или выехать на шашлыки, быть frontend-разработчиком совсем не обязательно.

    Так родилась идея сделать JavaScript AI-challenge.

    Увы, но большинство подобных платформ нам не подошли: обязательным условием была реальная, наблюдаемая состязательность и низкий порог вхождения. То есть искусственный интеллект должен писаться от 5 минут до 3 часов JavaScript-программистом любого уровня, а не несколько недель группой сишников, как, например, в AI Cup`ах от Mail или Google.

    Хотелось сражения, написания кода и соревновательности.

    Проект


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

    • Максимизация фана от игры,
    • и от использования новых технологий по ходу реализации проекта.
    • Нижайший порог вхождения написания ИИ.
    • Realtime-битва на большом экране.
    • Обновление «мозгов» на лету.
    • Кроссбраузерная поддержка последней версии хрома.

    С точки зрения фана альтернатив танчикам не было: это зрелищная realtime-игра с простой и знакомой всем механикой. Выбор танчиков отчасти удовлетворял и второе требование: в денди у вас есть всего пять кнопок: крестик и стрелять. Ровно столько базовых методов должно было быть в прототипе ИИ: это радикально снизило порог вхождения, и первое, что сделали большинство участников, написали рандомного бота:

    this.move(['left', 'up', 'right', 'down'][Math.floor(Math.random() * 4)]);
    this.fire();
    

    Ездить можно только по прямой, стрелять только куда едешь — это определяющие правила игры. Всё остальное (ускорения, заносы, отдача от стрельбы, накопление боезапаса) вводилось постепенно и с главным условием: влияние на геймплей и результат от каждой новой фичи должно быть минимальным.

    Реализация


    Для обсчета всей математики (положения, коллизии, попадания), на Node.js был написан движок. Довольно быстро возникла проблема дебага, решением которой стала клиентская Browserify-сборка, которая отлично отлаживается в DevTools Хрома.

    На раннем этапе «тонкий» клиент, сделанный для визуализации боев, ajax’ом запрашивал последние N кадров битвы и отрисовывал их dom-элементами (без шуток!). Было очень смешно, когда dom-снаряд, ударившись о цель, по диагонали улетал к другому танку и выстреливался вновь… в общем, вместе с шумом вентиляторов потеющих ноутбуков, к нам быстро пришло понимание, что без Canvas мы не обойдёмся (спасибо библиотеке PIXI).

    Для сетевого взаимодействия мы использовали Socket.io. Когда используешь вебсокеты, понимаешь, что 21 век наступил. Триггер события на одной машине, слушание этого события на другой, потоки… на сервере мы просто пишем в поток кадры, а на клиенте эти кадры слушаем. Никакой буферизации, проблем с памятью и рассинхроном.

    Кстати говоря, нам хотелось написать что-нибудь на фреймворке Meteor. «Чем-нибудь» стала наша клиентская часть. Модульность, высокоуровневые API, пакеты, изоморфность, Live Reload — хоть и избыточные в нашем случае, но очень приятные штуки.

    Самым интересным требованием, с точки зрения технологий, была замена игроков «на лету»: битва идёт, танк стреляет и ездит, а его «мозги» в любой момент могут полностью поменяться по желанию автора. Здесь не может быть премодерации: код в течение секунды после отправки должен начать исполняться на сервере.

    Сначала мы доверяли друг другу, поэтому new Function() вполне хватало. Но один хороший человек написал в своём боте process.kill(), и стало ясно, в OpenSource такой мультиплеер отдавать нельзя. Эффективно отлавливать регулярками всякие ужасы типа setTimeout(while (true)) не представляется возможным, и здесь бы нам на помощь могла придти абсолютно безопасная песочница, но мы хотели потрогать новомодную виртуальную машину.

    С виртуальной машиной Node.js всё оказалось просто, но интересно: например, в текущей реально стабильной ноде версии 0.10.36, в контекст-объекте, переданном в виртуальную машину, отваливается прототип (а ещё там внезапно нет MAX_SAFE_INTEGER). В 0.12.0 тоже не всё хорошо, плюс наши рабочие проекты, типа 2gis.ru, на ней пока не работают, из-за проблем со сборкой некоторых npm-пакетов. В этой связи мы теперь используем замечательный npm-пакет «n» для быстрого переключения версии ноды.

    Сама работа с виртуальной машиной проста: мы запускаем подготовленный eval-скрипт в контексте выбранного нами js-объекта. И у этого объекта нет setTimeout, console.log и прочих штук, которые есть в global-объекте. Кроме того, виртуальная машина позволяет ограничивать выполнение кода по времени: если код работает долго, он убивается, а его последний вздох ловит ближайший в стеке catch.

    В итоге


    Мы изучили вебсокеты и виртуальную машину Node.js, потыкали палочкой Meteor и PIXI, пописали ИИ, для многих первый в жизни, ну а главное — сразились друг с другом и получили много фана.

    Побочным эффектом Browserify-сборки стал синглплеер, который вы можете пройти уже сейчас: battle.2gis.ru. Посмотреть на сам движок можно здесь: github.com/2gis/Battlegis.

    В ближайшем будущем мы планируем сделать выделенный сервер с полноценным мультиплеером, где каждый желающий сможет потягаться силами с другими JavaScript-программистами; ну и, конечно, заняться багофиксом и кроссбраузерностью. Следите за новостями!
    2ГИС
    202,00
    Карта города и справочник предприятий
    Поделиться публикацией

    Комментарии 32

      0
      Что-то у меня в хроме вообще поле справа не отображается, а в Firefox-е танк не двигается
        0
        Все, теперь заработало =)
          0
          Что сделать надо, чтобы заработало?
            0
            У меня поначалу тоже не работало в Chrome. Отключил adblock на домене с танчиками и всё ожило.
              0
              Не, у меня адблока нет, достаточно просто обновить
              0
              я просто пару раз обновил вкладку
                0
                Аналогично (firefox)
          +4
          Хром — ни с adblock, ни без него — не работает.
          Uncaught Error: Texture Error: frame does not fit inside the base Texture dimensions [object Object]

          факап, господа
            +7
            Мужики, сори. Бага была связана с тем, что у нас сервер под боком и картинки загружаются мгновенно.
            Пофиксали, уже деплоим.
              0
              Поскольку код выполняется каждый тик, для экономии ресурсов рекомендуется использовать следующий паттерн...

              Хорошо бы иметь два поля вместо одного, как сейчас. Назвать их «init» и «tick», или взять классические названия – кажется, «setup» и «loop».
                0
                Да, обязательно будет.
                Сейчас можно воспользоваться ленью типа
                this.someMethod = this.someMethod || function() {
                    // some crazy stuff
                };
                
                0
                Котаны, а почему у вас уровни нумеруются странно: 11, 22, 33, ..., nn?
                Ну и в уровне 7(7) у меня почему-то сразу появилась надпись, что я победил (:
                  0
                  Это баг скорее всего. Тоже заметил.
                  0
                  Вы гении! Застрял на 8мом.
                    0
                    Круто! Сделайте возможность создавать новые файлы, и делать там что-то наподобие node-модулей. А затем подключать их в основной файл и использовать. Таким образом можно будет настроить их кеширование, дабы не загружать их каждый тик.

                    Также, надо ограничить количество команд. Попробуйте прописать в коде alert('smth'); и получите очень классный эффект. Ну или, банально, while(1){ }
                      0
                      Также, на учебном полигоне не сохраняются пройденные уровни. Я убил вкладку, т.к. устроил зацикливание. Теперь придется проходить все заново.
                        0
                        Это только в браузере так, там нет виртуальной машины и код считается trusted.
                        В мультиплеере будет ограничение на 10 мс, а с алерта он вообще упадёт, потому что это метод global-объекта, и в vm его не будет.
                          0
                          Отлично, ждем :)
                      +1
                      Не нашел лицензию кода…
                      Надеюсь она открытая?

                      Хорошая игрулька для привлечения школьников к JS
                        0
                        Что значит пройти 8 уровень? Всех убить? Но они постоянно появляются заново!
                          0
                          Там должна была быть онлайн комната) Но не успели, поэтому уровень бесконечный)
                          0
                          Помогите написать драйвер клавиатуры для игры. Вообщем мысль такая взять этот CANVAS и повесить на OnKeyboradPress вызов move('up') и будут обычные танчики ))) Как вам идейка?
                            0
                            Идейка на стадии реализации уже) Будет просто возможность вдвоем поиграть в танчики)
                            0
                            Liver Reload

                            Я, конечно, знаю, что указывать на опечатки — моветон, но «перезагрузка печени» — это, кажется, даже смешно :)

                            А вообще — круто!
                              0
                              Никогда не задумывался почему колбаса ливерная. Спасибо! :)
                              +1
                              Посмотрел на название проекта и почему то подумал, что в следующей версии танчики должны будут кататься не просто по черному полю, а по карте Новосиба например :) С учетом улиц домов и т.д. и т.п.
                                0
                                Это в пять раз круче, чем codecademy!
                                  0
                                  Идея отличная. С удовольствием поиграл вечером.

                                  Даешь полноценную программерскую ММО-JS с путешествием по GIS карте, прокачкой и рейдами! :)
                                    +1
                                    Знакомый просит показать вот эту ссылку.

                                    obsuditor.ddns.net/ftt/

                                    //Видимо, это его реализация чего-то подобного.

                                    ///А вот тут он и просит: www.linux.org.ru/forum/talks/11357433?lastmod=1424945151947
                                      0
                                      Что-то там страница регистрации 502ю ошибку выдаёт
                                      –2
                                      Всё как обычно. Доступно только молодому поколению…
                                      Скрытый текст
                                      Opera/9.80 (X11; Linux i686; Edition Linux Mint) Presto/2.12.388 Version/12.16
                                        0
                                        О! Сделайте сборщик почт для оповещения о выходе мультиплейера, люди будут ждать!

                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                        Самое читаемое