Использование HTML5 и Typescript в разработке
HTML5 хорош работой «из коробки», из окна браузера. Но со стороны разработки чистый JavaScript мне всегда не нравился. Хотелось иметь все те преимущества, которые дают те же C# и Visual Studio. Если вам интересен процесс обустройства рабочего пространства для создания HTML5-игр с использованием классов, полноценной отладки и внятного автодополнения — прошу под кат!
Рабочей средой станет редактор Visual Studio Code и браузер Chrome, который будет использоваться для отладки. Классами, строгой типизацией и абстракцией нас обеспечит Typescript — транспилируемый (т.е. преобразующийся в Javascript) язык от Microsoft. В качестве игрового HTML5-фреймворка выступает Phaser.
Начнём обустраиваться. Процесс первоначальной настройки не быстрый и не совсем легкий, но его нужно сделать только один раз. Все, что написано далее, я проверял на Windows 7 x64.
1. Устанавливаем необходимые программы.
Chrome
Visual Studio Code
NodeJS (подойдет как последняя, так и LTS версия)
2. Устанавливаем пакеты для NodeJS.
VS Code изначально готов к работе с NodeJS, так что нам остаётся только установить нужные пакеты. Включаем консоль (через Пуск — «Стандартные» -> «Командная строка»; я предпочитаю клавиши Win+R -> cmd). Возможно потребуется запустить консоль от имени администратора. Вводим следующие команды:
npm install -g typescript
npm install -g http-server
C Typescript всё ясно, а http-server нужен для запуска локального сервера, на котором мы и будем тестировать своё творение.
Дальнейшие действия я буду производить внутри VS Code на примере движка Phaser, но аналогично можно сделать для любого другого (или вообще не использовать готовый движок, но всё равно иметь преимущества перед чистым JS, которые я указал в начале статьи).
3. Для начала создадим костяк проекта
А. Создаём папку проекта, и внутри следующую структуру
bin/ — папка, которую впоследствии и будем выкладывать в интернет
bin/assets/ — ресурсы игры (звуки, картинки)
bin/js/ — в эту папку typescript будет транспилироваться в javascript
src/ — исходный код нашего проекта (на Typescript)
tsDefinitions/ — файлы аннотаций типов, нужны для автодополнения (см. далее)
Б. Интеграция движка Phaser в проект
Скачиваем Phaser. Теперь переносим соответствующие файлы в проект (файл phaser ---> файл проекта):
- phaser/build/phaser.js ---> bin/js/phaser.js
- phaser/typescript/box2d.d.ts ---> tsDefinitions/box2d.d.ts
- phaser/typescript/p2.d.ts ---> tsDefinitions/p2.d.ts
- phaser/typescript/pixi.d.ts ---> tsDefinitions/pixi.d.ts
- phaser/typescript/phaser.d.ts ---> tsDefinitions/phaser.d.ts
Первый файл — сам движок. Когда игра будет закончена, его можно заменить на phaser.min.js, для меньшего размера. Пока нам нужен именно этот файл, так как его удобнее использовать при отладке.
Далее четыре файла — это аннотации типов для phaser, который будет использовать typescript.
Аналогичные действия можно использовать для любого другого движка.
В. Создаём файл стартовую страницу игры (bin/index.html)
<!DOCTYPE html>
<html>
<head>
<title>Simple game</title>
<script src=«js/phaser.js»></script>
<script src=«js/game.js»></script>
</head>
<body>
<h1>Simple game</h1>
<div id=«content»></div>
</body>
</html>
Обратите внимание на теги script, включающие движок phaser.js и код нашей игры game.js, который уже скоро появится. :) Элемент div с идентификатором content будет при написании кода (пункт 6) использоваться как игровая область.
4. Конфигурация для Typescript
Теперь нам нужно указать редактору, как образом мы хотим преобразовывать Typescript-код в JS-код. Для этого создадим файл tsconfig.json:
{
«compilerOptions»: {
«target»: «es5»,
«sourceMap»: true,
«outFile»: «bin/js/game.js»
}
}
Здесь мы указываем, что все *.ts файлы в проекте нужно транспилировать в javascript версии ES5, и собрать в один файл, располагающийся в bin/js/game.js. Опция «sourceMap» нужна для создания карты исходных файлов, что позволит нам осуществлять отладку через файлы Typescript. Как непосредственно запустить транспиляцию мы узнаем позже.
5. Запуск локального сервера
Теперь нужно запустить локальный сервер из папки bin/. Для этого создадим «задачу» в VS Code, выполняющую простую команду в консоли. Выбираем из меню «Задачи» -> «Настроить задачи». В дереве проекта создастся файл .vscode/tasks.json, содержимое которого меняем на:
{
«version»: «2.0.0»,
«tasks»: [
{
«label»: «Run Server At \bin»,
«type»: «shell»,
«command»: «http-server ${workspaceFolder}\\bin»,
«problemMatcher»: []
}
]
}
Мы хотим, чтобы при выполнении задачи «Run Server At \bin», редактор запускал команду http-server в консоли, из папки bin/ нашего проекта. Запустить эту задачу (т.е. сервер) можно через «Задачи» -> «Запустить задачу» -> «Run Server At \bin». Зайти на сервер можно через браузер по ссылке «localhost:8080».
6. Наконец-таки код игры!
Напишем простую заглушку — код нашей игры. Программа будет выводить изображение в центре игровой области, на цветном фоне. Создадим файл src/Game.ts.
Не забудьте закинуть cat.jpg в bin/assets, так как код использует данный ресурс.
class SimpleGame
{
game: Phaser.Game;
constructor()
{
this.game = new Phaser.Game( 800, 600, Phaser.AUTO, 'content', { preload:this.preload, create:this.create} );
}
preload()
{
this.game.load.image( 'cat', «assets/cat.jpg» );
}
create()
{
this.game.stage.backgroundColor = 0xaa22ff;
let logo = this.game.add.sprite( this.game.world.centerX, this.game.world.centerY, 'cat' );
logo.anchor.setTo( 0.5, 0.5 );
}
}
// when the page has finished loading, create our game
window.onload = () => {
let game = new SimpleGame();
}
В Game.ts создаём класс SimpleGame для нашей игры, который при создании (constructor()) запускает движок в div элементе с идентификатором «content», устанавливает размер 800х600 пикселей, и указывает, какие функции выполнять при предзагрузке и первоначальном старте игры (preload() и create()).
В preload() мы загружаем ресурсы и производим первоначальную настройку. Загружаем файл «assets/cat.jpg» в движок под ключом «cat».
Create() вызывается один раз при запуске игры. Устанавливаем цвет фона. Выводим спрайт, загруженный под ключом «cat», в центре экрана.
В последних строках (window.onload) указываем, что делать при загрузке веб-страницы (она происходит ДО загрузки самой игры). В данном случае создаём экземпляр класса SimpleGame.
Теперь узнаем, как производить js-код и отладку.
7. Транспиляция кода
Время создать javascript — код! Для этого нажимаем Ctrl+Shift+B (в меню это «Задачи» -> «Запустить задачу сборки»). На основе нашего файла конфигурации tsconfig.json редактор предлагает нам два варианта — «сборка» и «отслеживание». Первый — единоразовая транспиляция. Все *.ts файлы будут переведены в js и собраны в один файл game.js, согласно файлу конфигурации. Второй вариант — такой же, только теперь при любом изменении и сохранении исходного кода сборка будет запускаться автоматически.
Теперь, запустив сервер, и перейдя в браузере по ссылке «localhost:8080» мы можем увидеть картинку и надпись «Simple game». :)
8. Отладка
Устанавливаем расширение — отладчик. Нажимаем Ctrl+Shift+X, что откроет менеджер расширений, ищем и ставим Chrome Debugger. Перезапускаем редактор.
По нажатию F5 в редакторе запускается отладка. В первый раз редактор не знает, какой именно инструмент для отладки использовать, поэтому мы должны сами указать ему. При первом нажатии F5 в проекте будет создан файл конфигурации .vscode/launch.json, содержимое которого меняем на:
{
«version»: «0.2.0»,
«configurations»: [
{
«name»: «Debug localhost»,
«type»: «chrome»,
«request»: «launch»,
«url»: «http://localhost:8080/»,
«webRoot»: «${workspaceRoot}\\bin»
}
]
}
Мы указываем, что будем использовать Chrome debugger, который запустит Chrome по адресу http://localhost:8080/, и подключится к браузеру. WebRoot указывает на корневую папку сервера и нужен для разрешения ссылок.
Теперь нам доступен весь функционал стандартного дебаггера! Можем устанавливать точки останова, использовать watch-выражения и тд из typescript-кода.
Пара советов
Если после транспиляции игра на странице сервера не обновилась, зажмите Shift и в браузере «Перезагрузить страницу», чтобы он не использовал кэшированную версию страницы.
Иногда при отладке не срабатывают точки останова, особенно если они находятся в начале выполнения кода (например, сразу после загрузки страницы) нужно обновить страницу в открывшемся браузере, так как дебаггер ещё не успел запуститься.
Используйте флаг «strict»: true в файле tsconfig.json. Строгий режим проверки кода спасет от незаметных ошибок.
Ctrl + Пробел в редакторе предлагает варианты автодополнения. Можно использовать при редактировании как файлов с исходным кодом, так и файлов конфигураций.
Вот так, с помощью нехитрых приспособлений...
После настройки типичный рабочий процесс будет выглядеть так:
- Создание typescript кода в папке src. Можно создавать несколько файлов, транспилятор преобразует все файлы в один — game.js.
- Спрайты, аудиофайлы и тд перемещаем в bin/assets.
- Запуск локального сервера через «Запуск задачи» -> «Run Server At \bin». За состоянием сервера можно следить в окне «Terminal» редактора.
- Транспиляция Typescript через Ctrl+Shift+B.
- Открытие страницы с игрой и подключение отладчика через нажатие F5.
- После завершения работы над проектом — публикация папки bin/.
Спасибо за внимание!
На основе этой статьи.
chrome — 63.0
vs code — 1.18
nodejs — 8.9.3
phaser — 2.9.3
typescript — 2.6.2
windows 7 x64
- 13 декабря 2017, 14:56
- 013
Создание игр с помощью кучи ненужных вещей, которые некогда делать. На дворе 2017.
Не совсем, зависит от платформы, по скорости в браузере и размеру браузерного билда - JS-движки делают все остальные.
Все остальные что? Не понял мысли.
Остальные движки
да, вот эти самые. Делают=уделывают
Щас бы сравнивать скорость в браузере того, что в браузере не запускается. При чём вообще браузер к играм? И чем HTML5-игры настолько лучше, что на них надо обращать внимание? Они же просто перенимают нишу флеш-игр - низкобюджетная помойка с рекламой, и очень изредка - годными индюшками. Ну ещё конечно есть Юнити-плагин для браузеров, но как бы при чём тут Typescript, Phaser и всё остальное. И Game Maker тоже компилирует (транспилирует, не важно) в HTML5+JS то, что написано по-человечески, а не через this.game.load.image( 'cat', "assets/cat.jpg" ); - мне предлагают руками менеджить все ассеты в проекте и писать вручную их загрузку? Поехавшие что ль?
Это простой пример для иллюстрации. В phaser есть загрузка паков ресурсов.
Так зачем показывать очередной скучный код? Намного важнее показать удобный инструментарий.
Да, пост про инструментарий.
Если это считается удобным, то я папа Карло.
Ну у кого-то математика для детей, у кого-то эрративный дизайн, у кого-то браузерки.
Давно уже нет. Есть тормозящий WebGL-экспорт вместо него.
Хз, возможно, я погорячился насчет GMS (или нет). Unity и UE4 используют под капотом Emscripten, на выходе получается тормозилка большого размера.
А чем их еще менеджить, как не руками? Наличие редактора с GUI придает работе другой вид, более удобный для одних проектов/пользователей и менее удобный - для других. Но работу делать все равно надо.
Ну назови мне тип проекта, в котором GUI для менеджмента ресурсов НЕ ускорил бы, что называется, пайплайн разработки?
Представь, что есть 100 наборов звуков. Каждый набор - это около 2-5 звуков, один из которых нужно проиграть по рандому. Предлагаешь все эти звуки прописать в редакторе и назначить им ID или как? Если есть возможность динамически подставить случайное число в имя файла и воспроизвести
Ну, то есть, очень мало игр имеют от этого преимущество, потому что очень мало игр реализуют подобную систему звуков относительно большинства.
Вывод - не делать игры с качественным преимуществом, а делать то же, что и большинство?
Почему же. Game Maker поддерживал такой тип подгрузки ресурсов версии где-то с шестой, года где-то с 2004 или около. Мы не об этом говорили. Когда я хочу работать с GUI, я хочу чтоб оно было. А когда не хочу, ну и не надо. Чаще всего это не пригождается.
Когда мне понадобится GUI для ассетов, я выберу движок с GUI для ассетов (или сделаю GUI для ассетов или куплю тулзу типа TexturePacker). Чаще всего это не пригождается. :-)
Ну тут речь о большинстве. Большинству эти разные звуки исторически нафиг не сдались.
Ну то есть standalone от толстого движка - это билд, в который помимо фич, которые нужны мне, еще вкомпилировали фичи, которые нужны большинству. И было бы ради чего. ;-)
Аж целый тяжёлый мегабайт, не то что жалкие 50 МБ Хромиума-обёртки.
Странно "на дворе 2017" слышать от поборника legacy-версии GameMaker. Но хотелось бы услышать варианты, подходящие по твоему мнению для 2017го.
Какого поборника, я использую Game Maker: Studio (но не вторую, она сырая). Просто старые проекты на старой версии, и сейчас не до того чтобы их обновлять. И можно подумать очередной %name%Script сделает подобное устаревание недоразумением прошлого?
Я бы использовал некое новое средство, которое абстрагируется от технологий больше чем язык гипертекстовой разметки, крикрученный гвоздями к серверу. Это всё слишком сложно и в развёртке (чтоб люди собственно играли) и в разработке.
Естественно в 2017 (в общем-то почти 2018) имеет смысл использовать Unity, Unreal Engine и Game Maker (кроме 3Д), если предполагается делать игры, которые будут доделаны и в них кто-то будет потом играть. Ну да, да, "Papers, Please!" была написана на Haxe, с OpenFL и всё такое. Каждому своё, я говорю о некоем среднем варианте для среднего разработчика.
Ведь и GMS теперь legacy, на него и в стиме и на yoyogames выйти сложно.
Если я тебя правильно понял, ты подразумеваешь развертку динамического сервера для игры? Вообще, после транспиляции нужен только стандартный http сервер (то есть статика), игра на клиенте выполняется, сервер нужен для хранения ассетов и их загрузки оттуда (чтобы избежать пресловутого XSS). Поэтому игру можно на itch.io и на подобные площадки кидать, и играть на том же итче с браузера.
Как раз typescript нужен для абстракции от js как язык программирования, а phaser (любой другой, тысячи их) - от html5 и webgl как игровой движок. В поле html5 это довольно существенная абстракция. Речь идёт именно об игре из браузера.
С этими стандартными вариантами ты конечно прав, но альтернативу никто не менял, как ты сам и подтвердил. :) Те же typescript и phaser довольно популярные и развивающиеся.
Ну вот видишь сколько сложностей получается. Stand-alone EXE-файл не надо хостить, у него есть нормальное управление полным экраном игры, а не "холстом" в окошечке неизвестного заранее браузера с не-pixel perfect масштабированием, и так далее. Какой итч? Я хочу играть в игры в своём пост-апокалиптическом бункере в полном радиомолчании. И чтобы в отдалённых районах Индии на дискетах играли.
Хорошо, если он абстрагирует что-то там лучше, но он ведь не гарантирует что через 10 лет я запущу в новом браузере (а где достать старый, на файлопомойках переменной надёжности?) то же самое и оно будет работать так же само?
Ну я понял, у нас с тобой разный взгляд на тенденции развития интерактивных приложений.
Подавляющее большинство браузерных игр мне ничего не внушает, чтобы пытаться их всерьёз рассматривать как "будущее" геймдева, хотя бы какой-то его части.
Надо, ты его хостишь в Стиме. Но не все категории игроков покупают что-то в Стиме, поэтому приходится идти им навстречу, на другие платформы.
Вот видишь, сколько сложностей получается. Растет бюджет на QA, это надо будет досконально проверить, что при игре в бункере не понадобится апдейт с исправлением критического бага.
Какой Стим? Я в 2005 прекрасно хостил игры на своём сайте. Которого, правда, уже нет.
Ну понятно, шутеечки шутим.
Шутеечки не смешные!
Я имел в виду, что его не надо динамически хостить. Перечитал - речь про статику. Допустим, но всё равно нужно хостить много ресурсов и качать их с сайта при игре. Это не стенд-элоун.
Также ты и js код у себя можешь хостить.
Я не про код, я про ассеты и их подгрузку.
Почему не FTP например?
Ты можешь запаковать всё в standalone и распространять на всех платформах.
Так а ключевой вопрос - зачем тогда HTML5+JS? В чём преимущество перед нативной компиляцией, или какой-нибудь Джавой-Сишарпом?
Работа из браузера. Мой ответ относился к твоей просьбе стэндалоуна.
Ну, то есть стэндалоун это браузер плюс игра. И было бы ради чего.
Если усреднять, то средний вариант для среднего разработчика - недоделанная игра.
А средний вариант для хорошего - не покупаемая игра. Увы.
Может быть такая статья и на Хабре была бы уместна, в чуть более развернутом виде. С примерчиками)
Я там не обитаю. А на гамине категория "программирование" присутствует.
К посту возможно скриншотов и правда не помешало бы добавить. Как критика появится или кто попробует по пунктам сделать, там и посмотрим.
Я, если что, не имел ввиду, что на Гамине ей не место, а наоборот - место и здесь, и может где-то на более технарском (лол) ресурсе типа Хабра)
Ок. :)
Более интересна часть насчёт "в более развернутом виде". Какие-то части сжаты или непонятны?
Я скорее имел ввиду, что может быть стоит привести какие-то примеры кода немного за гранью "Hello World", показать хоть немного какие-то возможности этой связки. Я вот, к примеру, как человек далекий от веба и от разных фреймворков типа Phaser, не до конца в курсе того что можно сделать. Хотя если цель статьи - просто описать удобную технологию разработки, то тогда всё в порядке, кто в курсе - тот в курсе.
Наверное заголовок с толку сбивает.
Я слышал, там нужно приглашение, чтоб зарегистрироваться, хотя может врут, но именно поэтому я даже не пробовал регистрироваться, а так, там статьи часто интересные попадаются)
Насколько я знаю, подобную статью на Хабре заминусуют.
Лол, читал комментарии к этой статье, двояко всё равно получается. Но и вправду не стоит - я не профессионал в инструментах, о которых пишу, а любитель. Искал возможность, как заставить связку из typescript + phaser заработать (также пробовал в visual studio, atom), и из разных руководств сделал одно.
Полезно, давно хотел попробовать Typescript.
Так давай же! Нужна статистика.
Статистика чего? :)
Бесполезности языков программирования общего назначения для геймдева.
Vendor lock-in крепчал...
Вообще-то нет, но какая разница, если вам (вот тебе и тому кто поставил меч) важнее не высокоуровневая профильная ориентированность инструментария, а эфемерная свобода от подножек разработчика, которых я не припомню, в отличие от Юнити всяких.
Тебе надо в евангелисты, будешь рассказывать, как операционные системы, драйверы и движки пишутся на "бесполезных" языках программирования
Не тот контекст. Когда надо будет писать драйвера, я буду агитировать за Си, скорее даже без плюсов, чем с. Просто игры ушли далеко вперёд. И вбок.
Из этого следует, что разработчики Game Maker делают бесполезную для геймдева работу.
Скриптовые языки нужны не потому что игры ушли вперед, а потому что разработчики не знают, что хотят сделать, и много раз переделывают. (а разработчики движков - тем более не знают, а если бы знали, то программировать разработчику игры было бы нечего)
Game Maker Language - язык не общего назначения, а предметно-ориентированный, так что ты тут не прав. Одновременно с этим он и скриптовый тоже. Плюс под него есть несколько IDE разной степени свободности и бесплатности. Другое дело, интересно ли кому-то высовывать нос из своего хвалёного болотца. (как и мне, хаха)
В отличие от того, на чем написан Game Maker. Так что ты тут не прав.
На чем они написаны? М?
Фанатизм гейммейкером настолько зашел, что бесполезными для геймдева стали почти все программы, которые используются для геймдева.
Какие-то вопросы уровня "без физики никакие ваши компьютеры не сделали бы, транзисторы бы никто не изобрёл". По-моему вполне логично, что меня не должна заботить вся эта цепочка, прекрасно известная мне начиная с уровня микрокоманд процессора. Заниматься этим некогда и не нужно.
Нет, программы полезные. Но не настолько.
"Начнём обустраиваться", проходит сто лет, и вот у тебя наконец пустой проект в котором каждый кирпич строится ещё сто лет. Прогресс!
Fixed.
Ну вы давайте-давайте, через 10 лет сравним сколько у кого, и каких игр.
Рано или поздно, ты должен был это сказать.
Практика важнее болтовни, но я даже в теории не понимаю зачем Typescript в геймдеве. Типа, микроскоп лучше телескопа для забивания гвоздей? Логично конечно.
Совсем непонятен твой ответ.
Пожалуйста, вот тебе практика - используй typescript, phaser и что-то делай (не конкретно ты).
А насчёт "у кого сколько игр" - здесь ассет-флипперы давно тебя опередили, но молодцами от этого не стали.
"и каких" как раз для этого приписано. Разных, хороших.
И тем самым ты докажешь, что gml лучше языков общего назначения?
¯\_(ツ)_/¯
На тот момент мне будет глубоко по барабану уже, но да, это будет означать что GML в сфере создания 2Д-игр под HTML5 (и другие свои целевые платформы) лучше некоторых других. В моих руках. То есть, в целом ничего не будет означать. Ага.
Xitilon.HD408, Умеешь создать движуху)
Свежо! Давненько не было у нас технических постов, мало что поняла, но спасибо - занятно! ^_^