[Перевод] Создание многопользовательской веб-игры в жанре .io

image


Вышедшая в 2015 году Agar.io стала прародителем нового жанра игр .io, популярность которого с тех пор сильно возросла. Рост популярности игр .io я испытал на себе: за последние три года я создал и продал две игры этого жанра…

На случай, если вы никогда раньше не слышали о таких играх: это бесплатные многопользовательские веб-игры, в которых легко участвовать (не требуется учётная запись). Обычно они сталкивают на одной арене множество противоборствующих игроков. Другие знаменитые игры жанра .io: Slither.io и Diep.io.

В этом посте мы будем разбираться, как с нуля создать игру .io. Для этого достаточно будет только знания Javascript: вам нужно понимать такие вещи, как синтаксис ES6, ключевое слово this и Promises. Даже если вы знаете Javascript не в совершенстве, то всё равно сможете разобраться в большей части поста.

Пример игры .io


Для помощи в обучении мы будем ссылаться на пример игры .io. Попробуйте в сыграть в неё!

umyqqjon22wmshrz8o8wtyeaxl0.png


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

1. Краткий обзор/структура проекта


Рекомендую скачать исходный код примера игры, чтобы вы могли следовать за мной.


В примере используется следующее:

  • Express — самый популярный веб-фреймворк для Node.js, управляющий веб-сервером игры.
  • socket.io — библиотека websocket для обмена данными между браузером и сервером.
  • Webpack — менеджер модулей. О том, зачем использовать Webpack, можно прочитать здесь.


Вот как выглядит структура каталога проекта:

public/
    assets/
        ...
src/
    client/
        css/
            ...
        html/
            index.html
        index.js
        ...
    server/
        server.js
        ...
    shared/
        constants.js


public/


Всё в папке public/ будет статически передаваться сервером. В public/assets/ содержатся используемые нашим проектом изображения.

src/


Весь исходный код находится в папке src/. Названия client/ и server/ говорят сами за себя, а shared/ содержит файл констант, импортируемый и клиентом, и сервером.

2. Сборки/параметры проекта


Как сказано выше, для сборки проекта мы используем менеджер модулей Webpack. Давайте взглянем на нашу конфигурацию Webpack: webpack.common.js:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: {
    game: './src/client/index.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
          },
          'css-loader',
        ],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
    }),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'src/client/html/index.html',
    }),
  ],
};


Самыми важными здесь являются следующие строки:

  • src/client/index.js — это входная точка клиента Javascript (JS). Webpack будет начинать отсюда и станет рекурсивно искать другие импортированные файлы.
  • Выходной JS нашей сборки Webpack будет располагаться в каталоге dist/. Я буду называть этот файл нашим пакетом JS.
  • Мы используем Babel, и в частности конфигурацию @babel/preset-env для транспиляции (transpiling) нашего кода JS для старых браузеров.
  • Мы используем плагин для извлечения всех CSS, на которые ссылаются файлы JS, и для объединения их в одном месте. Я буду называть его нашим пакетом CSS.


Вы могли заметить странные имена файлов пакетов '[name].[contenthash].ext'. В них содержатся подстановки имён файлов Webpack: [name] будет заменён на имя входной точки (в нашем случае это game), а [contenthash] будет заменён на хеш содержимого файла. Мы делаем это, чтобы оптимизировать проект для хеширования — можно приказать браузерам бесконечно кешировать наши пакеты JS, потому что если пакет изменяется, то меняется и его имя файла (изменяется contenthash). Готовым результатом будет имя файла вида game.dbeee76e91a97d0c7207.js.

Файл webpack.common.js — это базовый файл конфигурации, который мы импортируем в конфигурации разработки и готового проекта. Вот, например, конфигурация разработки:

webpack.dev.js

const merge = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'development',
});


Для эффективности мы используем в процессе разработки webpack.dev.js, и переключается на webpack.prod.js, чтобы оптимизировать размеры пакетов при развёртывании в продакшен.

Локальная настройка


Рекомендую устанавливать проект на локальной машине, чтобы вы могли следовать за этапами, перечисленными в этом посте. Настройка проста: во-первых, в системе должны быть установлены Node и NPM. Далее нужно выполнить

$ git clone https://github.com/vzhou842/example-.io-game.git
$ cd example-.io-game
$ npm install


и вы готовы к работе! Для запуска сервера разработки достаточно выполнить

$ npm run develop


и зайти в веб-браузере на localhost:3000. Сервер разработки будет автоматически пересобирать заново пакеты JS и CSS в процессе изменения кода — просто обновите страницу, чтобы увидеть все изменения!

3. Входные точки клиента


Давайте приступим к самому коду игры. Для начала нам потребуется страница index.html, при посещении сайта браузер будет загружать её первой. Наша страница будет довольно простой: index.html




  An example .io game
  


  
  
  













Этот пример кода слегка упрощён для понятности, то же самое я сделаю и со многими другими примерами поста. Полный код всегда можно посмотреть на Github.

У нас есть:

  • Элемент HTML5 Canvas (), который мы будем использовать для рендеринга игры.
  • для добавления нашего пакета CSS.