Недавно я создал новый сайт и закончил онлайн-игру Приключения пингвина Паскаля. Одна из самых уникальных особенностей этой игры заключается в том, что она написана на Rust и запускается в веб-браузерах благодаря WebAssembly. WebAssembly стала мейнстримом всего около года, поэтому не так много игр было создано подобным образом. Я хочу немного рассказать о своем пути к Rust: как я начал с ним и как дошел до этого момента.

Разработка игр была моим хобби долгое время. До середины 2015 года, когда был выпущен Rust 1.0, я занимался разработкой игр на Java с помощью LibGDX. Поскольку это было хобби, я выбрал технологии, которые мне нравились, но это не значит, что не было разочарований. Самым большим разочарованием, которое у меня было с Java, помимо ее многословности, было то, что я обнаружил, что вынужден выбирать между написанием идиоматического кода Java и написанием кода Java с приличной производительностью. Например, LibGDX API поощряет использование своих утилит для объединения объектов и специализированных реализаций массивов с изменяемым размером с общедоступными собственными массивами в качестве полей. Это не идиоматические практики Java, но они полезны для создания плавно работающей игры. Когда вам нужно поскупиться на создание объектов, я бы сказал, что пора найти новый язык.

Я изучил Rust, прочитав их онлайн-книгу, которая в то время выглядела совсем иначе. Тогда это было короче, больше похоже на учебник, чем на полную книгу. Было много вещей, которые мне нравились: абстракции с нулевой стоимостью, черты и обобщения с мономорфизацией, парадигма владения, гибкие перечисления в сочетании с сопоставлением с образцом, эргономичная обработка ошибок, эффективные с точки зрения памяти коллекции и т. Д. Но на фундаментальном уровне Rust является безопасный язык, то есть разработка на Rust не подвержена ошибкам, но при этом остается высокопроизводительным языком с предсказуемой производительностью. Я заметил, что когда я пишу код на Rust и дохожу до того, что мой код компилируется без сообщений об ошибках, он, вероятно, работает правильно и эффективно. Я думаю, это то, что делает язык привлекательным и расширяющим возможности для многих.

Также есть отличные инструменты для работы с Rust. Сам компилятор Rust выдает полезные предупреждения и сообщения об ошибках. Инструмент управления зависимостями Cargo удивительно прост и позволяет создавать воспроизводимые сборки. Центральный репозиторий crates.io может легко загрузить любой желающий. Сгенерированные html-документы API - самые полезные из тех, что я видел на любом языке, а документы для всех общедоступных ящиков создаются и размещаются на docs.rs.

Итак, я экспериментировал с разработкой игр на Rust, но не (изначально) с намерением запустить игру через веб-браузер. В то время существовал отличный туториал под названием ArcadeRS, который демонстрировал, как создать игру на Rust с помощью SDL2. К сожалению, это руководство устарело, и сайт был закрыт. Работая над проектом, я решил, что было бы неплохо извлечь многоразовый слой, специфичный для моих нужд, который отделял бы логику игры от управления ресурсами, рендеринга, звука и других интерфейсов, необходимых для игры. Я тоже решил сделать этот слой открытым, и он стал библиотекой Gate. Чтобы согласиться с этим, я создал краткий 2D-платформер с открытым исходным кодом, который с тех пор получил название Chirperjax.

Примерно в это же время я услышал о новой технологии под названием WebAssembly. Благодаря этому Rust можно было скомпилировать для работы в браузере и добиться почти нативной производительности. Я знал, что мне нужно попробовать, хотя он был более продвинутым, чем мне обычно хотелось бы работать. Одна из проблем, связанных с разработкой игр в качестве хобби, заключается в том, что люди, как правило, опасаются загружать и запускать исполняемые файлы на своих компьютерах, и это справедливо. Размещение игры, которая запускается в изолированной среде в браузере, позволяет большему количеству людей играть в игру. Моей первой попыткой было скомпилировать Chirperjax с использованием поддержки SDL2 в emscripten, но мне не удалось заставить его работать правильно. Итак, я просмотрел несколько руководств для цели Rust wasm32-unknown-unknown и узнал, как вызывать методы JavaScript из Rust и как вызывать методы Rust из JavaScript. Поскольку современный html сам по себе оборудован для создания интерактивного аудиовизуального опыта, мне не нужно было зависеть от SDL2 или других дополнительных библиотек, за исключением howler.js. Это облегчило все приложение и дало мне большой контроль.

Имейте в виду, что я делал это, когда инструментарий Rust WebAssembly был еще незрелым. Но мне удалось перенести сборку ворот в WebAssembly, и я опубликовал Chirperjax в Интернете в январе 2018 года. После этого и увидев, что людям нравится в нее играть, я решил создать более амбициозную игру с теми же инструментами. Это было началом «Приключений пингвина Паскаля», которые были завершены в декабре 2018 года. По сути, это был для меня проект, рассчитанный на год.

Таков был мой опыт вкратце. Конечно, я мог бы пойти по другому пути, например, изучить MonoGame или Unity. Но когда я впервые наткнулся на Rust, я почувствовал, что это именно то, что я хотел от языка программирования, и, поскольку я делал это просто для развлечения, я решил изучить его, а не более распространенные варианты разработки игр. У меня не было особых трудностей с изучением Rust. Конечно, было время, когда я, цитирую, «боролся с проверкой заимствований», но я узнал, что могу переупорядочить свои объектные модели и свое мышление, чтобы они работали более естественно с проверкой заимствований, что также улучшило качество моего кода. Если бы у меня были какие-то жалобы, это было бы отсутствие быстрого руководства и незрелых библиотек. Но в целом я был очень продуктивен с Rust, и я призываю других попробовать его.