{"id":33243,"date":"2019-10-31T21:51:31","date_gmt":"2019-10-31T18:51:31","guid":{"rendered":"https:\/\/prohoster.info\/blog\/sozdanie-mnogopolzovatelskoj-veb-igry-v-zhanre-io\/"},"modified":"2019-10-31T21:51:31","modified_gmt":"2019-10-31T18:51:31","slug":"sozdanie-mnogopolzovatelskoj-veb-igry-v-zhanre-io","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/sozdanie-mnogopolzovatelskoj-veb-igry-v-zhanre-io","title":{"rendered":"Erstellung eines Mehrspieler-Webspiels im .io-Genre","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io\" src=\"\/wp-content\/uploads\/2019\/05\/1fdc9975537f507cde080df7787cb051.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u0412\u044b\u0448\u0435\u0434\u0448\u0430\u044f \u0432 2015 \u0433\u043e\u0434\u0443 <noindex><a rel=\"nofollow\" href=\"https:\/\/agar.io\" rel=\"noopener noreferrer\">Agar.io<\/a><\/noindex> \u0441\u0442\u0430\u043b\u0430 \u043f\u0440\u0430\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u0436\u0430\u043d\u0440\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.google.com\/search?q=.io+game\" rel=\"noopener noreferrer\"><strong>\u0438\u0433\u0440 .io<\/strong><\/a><\/noindex>, \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441 \u0442\u0435\u0445 \u043f\u043e\u0440 \u0441\u0438\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u0440\u043e\u0441\u043b\u0430. \u0420\u043e\u0441\u0442 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u0438 \u0438\u0433\u0440 .io \u044f \u0438\u0441\u043f\u044b\u0442\u0430\u043b \u043d\u0430 \u0441\u0435\u0431\u0435: \u0437\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0442\u0440\u0438 \u0433\u043e\u0434\u0430 \u044f <noindex><a rel=\"nofollow\" href=\"https:\/\/victorzhou.com\/about\/\">\u0441\u043e\u0437\u0434\u0430\u043b \u0438 \u043f\u0440\u043e\u0434\u0430\u043b \u0434\u0432\u0435 \u0438\u0433\u0440\u044b \u044d\u0442\u043e\u0433\u043e \u0436\u0430\u043d\u0440\u0430.<\/a><\/noindex>.<\/p>\n<p>\u041d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439, \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u0440\u0430\u043d\u044c\u0448\u0435 \u043d\u0435 \u0441\u043b\u044b\u0448\u0430\u043b\u0438 \u043e \u0442\u0430\u043a\u0438\u0445 \u0438\u0433\u0440\u0430\u0445: \u044d\u0442\u043e \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043b\u0435\u0433\u043a\u043e \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c (\u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c). \u041e\u0431\u044b\u0447\u043d\u043e \u043e\u043d\u0438 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044e\u0442 \u043d\u0430 \u043e\u0434\u043d\u043e\u0439 \u0430\u0440\u0435\u043d\u0435 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0431\u043e\u0440\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0438\u0433\u0440\u043e\u043a\u043e\u0432. \u0414\u0440\u0443\u0433\u0438\u0435 \u0437\u043d\u0430\u043c\u0435\u043d\u0438\u0442\u044b\u0435 \u0438\u0433\u0440\u044b \u0436\u0430\u043d\u0440\u0430 .io: <noindex><a rel=\"nofollow\" href=\"https:\/\/slither.io\" rel=\"noopener noreferrer\">Slither.io<\/a><\/noindex> \u0438 <noindex><a rel=\"nofollow\" href=\"https:\/\/diep.io\" rel=\"noopener noreferrer\">Diep.io<\/a><\/noindex>.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f, \u043a\u0430\u043a <strong>\u0441 \u043d\u0443\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u0433\u0440\u0443 .io<\/strong>. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u043d\u0430\u043d\u0438\u044f Javascript: \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u0432\u0435\u0449\u0438, \u043a\u0430\u043a \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.w3schools.com\/js\/js_es6.asp\" rel=\"noopener noreferrer\">ES6<\/a><\/noindex>, \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e <code>this<\/code> \u0438 <noindex><a rel=\"nofollow\" href=\"https:\/\/developers.google.com\/web\/fundamentals\/primers\/promises\" rel=\"noopener noreferrer\">Promises<\/a><\/noindex>. \u0414\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0432\u044b \u0437\u043d\u0430\u0435\u0442\u0435 Javascript \u043d\u0435 \u0432 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u0435, \u0442\u043e \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u043e\u0441\u0442\u0430.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0433\u0440\u044b .io<\/h2>\n<p>\n\u0414\u043b\u044f \u043f\u043e\u043c\u043e\u0449\u0438 \u0432 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043d\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/example-io-game.victorzhou.com\">\u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0433\u0440\u044b .io<\/a><\/noindex>. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0432 \u0441\u044b\u0433\u0440\u0430\u0442\u044c \u0432 \u043d\u0435\u0451!<\/p>\n<p><img decoding=\"async\" alt=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io\" src=\"\/wp-content\/uploads\/2019\/05\/d1748ba25f52583c2183f4c2899285a7.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u0418\u0433\u0440\u0430 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430: \u0432\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0435 \u043a\u043e\u0440\u0430\u0431\u043b\u0451\u043c \u043d\u0430 \u0430\u0440\u0435\u043d\u0435, \u0433\u0434\u0435 \u0435\u0441\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0438\u0433\u0440\u043e\u043a\u0438. \u0412\u0430\u0448 \u043a\u043e\u0440\u0430\u0431\u043b\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0442\u0440\u0435\u043b\u044f\u0435\u0442 \u0441\u043d\u0430\u0440\u044f\u0434\u0430\u043c\u0438 \u0438 \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0438\u0433\u0440\u043e\u043a\u043e\u0432, \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u0438\u0437\u0431\u0435\u0433\u0430\u044f \u0438\u0445 \u0441\u043d\u0430\u0440\u044f\u0434\u043e\u0432.<\/p>\n<h2>1. \u041a\u0440\u0430\u0442\u043a\u0438\u0439 \u043e\u0431\u0437\u043e\u0440\/\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p><\/p>\n<blockquote><p>\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/vzhou842\/example-.io-game\" rel=\"noopener noreferrer\"><strong>\u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434<\/strong><\/a><\/noindex> \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0438\u0433\u0440\u044b, \u0447\u0442\u043e\u0431\u044b \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0437\u0430 \u043c\u043d\u043e\u0439.<\/p><\/blockquote>\n<p>\n\u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/expressjs.com\/\" rel=\"noopener noreferrer\">Express<\/a><\/noindex> \u2014 \u0441\u0430\u043c\u044b\u0439 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f Node.js, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0438\u0433\u0440\u044b.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/socket.io\/\" rel=\"noopener noreferrer\">socket.io<\/a><\/noindex> \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 websocket \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/webpack.js.org\/\">Webpack<\/a><\/noindex> \u2014 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043c\u043e\u0434\u0443\u043b\u0435\u0439. \u041e \u0442\u043e\u043c, \u0437\u0430\u0447\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Webpack, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <noindex><a rel=\"nofollow\" href=\"https:\/\/victorzhou.com\/blog\/why-you-should-use-webpack\/\">\u0437\u0434\u0435\u0441\u044c<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>\n\u0412\u043e\u0442 \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<p><code><\/p>\n<pre>public\/\n    assets\/\n        ...\nsrc\/\n    client\/\n        css\/\n            ...\n        html\/\n            index.html\n        index.js\n        ...\n    server\/\n        server.js\n        ...\n    shared\/\n        constants.js<\/pre>\n<p><\/code><\/p>\n<h3>public\/<\/h3>\n<p>\n\u0412\u0441\u0451 \u0432 \u043f\u0430\u043f\u043a\u0435 <code>public\/<\/code> \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c. \u0412 <code>public\/assets\/<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043d\u0430\u0448\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f.<\/p>\n<h3>src\/<\/h3>\n<p>\n\u0412\u0435\u0441\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u0430\u043f\u043a\u0435 <code>src\/<\/code>. \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u044f <code>client\/<\/code> \u0438 <code>server\/<\/code> \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u0441\u0430\u043c\u0438 \u0437\u0430 \u0441\u0435\u0431\u044f, \u0430 <code>shared\/<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442, \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c, \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c.<\/p>\n<h2>2. \u0421\u0431\u043e\u0440\u043a\u0438\/\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\n\u041a\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435, \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 <noindex><a rel=\"nofollow\" href=\"https:\/\/webpack.js.org\/\">Webpack<\/a><\/noindex>. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u043d\u0430\u0448\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e Webpack:<\/p>\n<h5>webpack.common.js:<\/h5>\n<p><\/p>\n<pre><code class=\"cpp\">const path = require('path');\nconst MiniCssExtractPlugin = require('mini-css-extract-plugin');\n\nmodule.exports = {\n  entry: {\n    game: '.\/src\/client\/index.js',\n  },\n  output: {\n    filename: '[name].[contenthash].js',\n    path: path.resolve(__dirname, 'dist'),\n  },\n  module: {\n    rules: [\n      {\n        test: \/.js$\/,\n        exclude: \/node_modules\/,\n        use: {\n          loader: \"babel-loader\",\n          options: {\n            presets: ['@babel\/preset-env'],\n          },\n        },\n      },\n      {\n        test: \/.css$\/,\n        use: [\n          {\n            loader: MiniCssExtractPlugin.loader,\n          },\n          'css-loader',\n        ],\n      },\n    ],\n  },\n  plugins: [\n    new MiniCssExtractPlugin({\n      filename: '[name].[contenthash].css',\n    }),\n    new HtmlWebpackPlugin({\n      filename: 'index.html',\n      template: 'src\/client\/html\/index.html',\n    }),\n  ],\n};<\/code><\/pre>\n<p>\n\u0421\u0430\u043c\u044b\u043c\u0438 \u0432\u0430\u0436\u043d\u044b\u043c\u0438 \u0437\u0434\u0435\u0441\u044c \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438:<\/p>\n<ul>\n<li><code>src\/client\/index.js<\/code> \u2014 \u044d\u0442\u043e \u0432\u0445\u043e\u0434\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 Javascript (JS). Webpack \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c \u043e\u0442\u0441\u044e\u0434\u0430 \u0438 \u0441\u0442\u0430\u043d\u0435\u0442 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e \u0438\u0441\u043a\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b.<\/li>\n<li>\u0412\u044b\u0445\u043e\u0434\u043d\u043e\u0439 JS \u043d\u0430\u0448\u0435\u0439 \u0441\u0431\u043e\u0440\u043a\u0438 Webpack \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 <code>dist\/<\/code>. \u042f \u0431\u0443\u0434\u0443 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u043d\u0430\u0448\u0438\u043c <strong>\u043f\u0430\u043a\u0435\u0442\u043e\u043c JS<\/strong>.<\/li>\n<li>\u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <noindex><a rel=\"nofollow\" href=\"https:\/\/babeljs.io\/\" rel=\"noopener noreferrer\">Babel<\/a><\/noindex>, \u0438 \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e <noindex><a rel=\"nofollow\" href=\"https:\/\/babeljs.io\/docs\/en\/babel-preset-env\" rel=\"noopener noreferrer\">@babel\/preset-env<\/a><\/noindex> \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043f\u0438\u043b\u044f\u0446\u0438\u0438 (transpiling) \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430 JS \u0434\u043b\u044f \u0441\u0442\u0430\u0440\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432.<\/li>\n<li>\u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 CSS, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0441\u044b\u043b\u0430\u044e\u0442\u0441\u044f \u0444\u0430\u0439\u043b\u044b JS, \u0438 \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0438\u0445 \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435. \u042f \u0431\u0443\u0434\u0443 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043d\u0430\u0448\u0438\u043c <strong>\u043f\u0430\u043a\u0435\u0442\u043e\u043c CSS<\/strong>.<\/li>\n<\/ul>\n<p>\n\u0412\u044b \u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u043d\u044b\u0435 \u0438\u043c\u0435\u043d\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 <code>'[name].[contenthash].ext'<\/code>. \u0412 \u043d\u0438\u0445 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f <noindex><a rel=\"nofollow\" href=\"https:\/\/webpack.js.org\/configuration\/output\/#output-filename\" rel=\"noopener noreferrer\">\u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438\u043c\u0451\u043d \u0444\u0430\u0439\u043b\u043e\u0432<\/a><\/noindex> Webpack: <code>[name]<\/code> \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043c\u0435\u043d\u0451\u043d \u043d\u0430 \u0438\u043c\u044f \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e <code>game<\/code>), \u0430 <code>[contenthash]<\/code> \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043c\u0435\u043d\u0451\u043d \u043d\u0430 \u0445\u0435\u0448 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430. \u041c\u044b \u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e, \u0447\u0442\u043e\u0431\u044b <noindex><a rel=\"nofollow\" href=\"https:\/\/webpack.js.org\/guides\/caching\/#output-filenames\" rel=\"noopener noreferrer\">\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043b\u044f \u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/a><\/noindex> \u2014 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043a\u0430\u0437\u0430\u0442\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u043c \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u043f\u0430\u043a\u0435\u0442\u044b JS, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e <strong>\u0435\u0441\u043b\u0438 \u043f\u0430\u043a\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u0442\u043e \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0438 \u0435\u0433\u043e \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430<\/strong> (\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f <code>contenthash<\/code>). \u0413\u043e\u0442\u043e\u0432\u044b\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0432\u0438\u0434\u0430 <code>game.dbeee76e91a97d0c7207.js<\/code>.<\/p>\n<p>\u0424\u0430\u0439\u043b <code>webpack.common.js<\/code> \u2014 \u044d\u0442\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0412\u043e\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438:<\/p>\n<h5>webpack.dev.js<\/h5>\n<p><\/p>\n<pre><code class=\"cpp\">const merge = require('webpack-merge');\nconst common = require('.\/webpack.common.js');\n\nmodule.exports = merge(common, {\n  mode: 'development',\n});<\/code><\/pre>\n<p>\n\u0414\u043b\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 <code>webpack.dev.js<\/code>, \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043d\u0430 <code>webpack.prod.js<\/code>, \u0447\u0442\u043e\u0431\u044b \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440\u044b \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u043f\u0440\u0438 \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0438 \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d.<\/p>\n<h3>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430<\/h3>\n<p>\n\u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435, \u0447\u0442\u043e\u0431\u044b \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0437\u0430 \u044d\u0442\u0430\u043f\u0430\u043c\u0438, \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0432 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u0430: \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b <noindex><a rel=\"nofollow\" href=\"https:\/\/nodejs.org\/en\/download\/\">Node<\/a><\/noindex> \u0438 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.npmjs.com\/get-npm\">NPM<\/a><\/noindex>. \u0414\u0430\u043b\u0435\u0435 \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c<\/p>\n<pre><code class=\"cpp\">$ git clone https:\/\/github.com\/vzhou842\/example-.io-game.git\n$ cd example-.io-game\n$ npm install<\/code><\/pre>\n<p>\n\u0438 \u0432\u044b \u0433\u043e\u0442\u043e\u0432\u044b \u043a \u0440\u0430\u0431\u043e\u0442\u0435! \u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c<\/p>\n<pre><code class=\"cpp\">$ npm run develop<\/code><\/pre>\n<p>\n\u0438 \u0437\u0430\u0439\u0442\u0438 \u0432 \u0432\u0435\u0431-\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043d\u0430 <noindex>localhost:3000<\/noindex>. \u0421\u0435\u0440\u0432\u0435\u0440 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0437\u0430\u043d\u043e\u0432\u043e \u043f\u0430\u043a\u0435\u0442\u044b JS \u0438 CSS \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u2014 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u0447\u0442\u043e\u0431\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f!<\/p>\n<h2>3. \u0412\u0445\u043e\u0434\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/h2>\n<p>\n\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u043a\u043e\u0434\u0443 \u0438\u0433\u0440\u044b. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 <code>index.html<\/code>, \u043f\u0440\u0438 \u043f\u043e\u0441\u0435\u0449\u0435\u043d\u0438\u0438 \u0441\u0430\u0439\u0442\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0435\u0451 \u043f\u0435\u0440\u0432\u043e\u0439. \u041d\u0430\u0448\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439:<\/p>\n<h5>index.html<\/h5>\n<p><\/p>\n<pre>&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;An example .io game&lt;\/title&gt;\n  &lt;link type=\"text\/css\" rel=\"stylesheet\" href=\"\/game.bundle.css\"&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;canvas id=\"game-canvas\"&gt;&lt;\/canvas&gt;\n  &lt;script async src=\"\/game.bundle.js\"&gt;&lt;\/script&gt;\n  &lt;div id=\"play-menu\" class=\"hidden\"&gt;\n    &lt;input type=\"text\" id=\"username-input\" placeholder=\"Username\" \/&gt;\n    &lt;button id=\"play-button\"&gt;PLAY&lt;\/button&gt;\n  &lt;\/div&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n<p>\n<i>\u042d\u0442\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430 \u0441\u043b\u0435\u0433\u043a\u0430 \u0443\u043f\u0440\u043e\u0449\u0451\u043d \u0434\u043b\u044f \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0441\u0442\u0438, \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u044f \u0441\u0434\u0435\u043b\u0430\u044e \u0438 \u0441\u043e \u043c\u043d\u043e\u0433\u0438\u043c\u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u043f\u043e\u0441\u0442\u0430. \u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/vzhou842\/example-.io-game\">Github<\/a><\/noindex>.<\/i><\/p>\n<p>\u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.w3schools.com\/html\/html5_canvas.asp\">\u042d\u043b\u0435\u043c\u0435\u043d\u0442 HTML5 Canvas<\/a><\/noindex> (<code>&lt;canvas&gt;<\/code>), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0438\u0433\u0440\u044b.<\/li>\n<li><code>&lt;link&gt;<\/code> \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0430\u043a\u0435\u0442\u0430 CSS.<\/li>\n<li><code>&lt;script&gt;<\/code> \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0430\u043a\u0435\u0442\u0430 Javascript.<\/li>\n<li>\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e \u0441 \u0438\u043c\u0435\u043d\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f <code>&lt;input&gt;<\/code> \u0438 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u00abPLAY\u00bb (<code>&lt;button&gt;<\/code>).<\/li>\n<\/ul>\n<p>\n\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043d\u0430\u0447\u043d\u0451\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f Javascript-\u043a\u043e\u0434, \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u0444\u0430\u0439\u043b\u0430 JS \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438: <code>src\/client\/index.js<\/code>.<\/p>\n<h5>index.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">import { connect, play } from '.\/networking';\nimport { startRendering, stopRendering } from '.\/render';\nimport { startCapturingInput, stopCapturingInput } from '.\/input';\nimport { downloadAssets } from '.\/assets';\nimport { initState } from '.\/state';\nimport { setLeaderboardHidden } from '.\/leaderboard';\n\nimport '.\/css\/main.css';\n\nconst playMenu = document.getElementById('play-menu');\nconst playButton = document.getElementById('play-button');\nconst usernameInput = document.getElementById('username-input');\n\nPromise.all([\n  connect(),\n  downloadAssets(),\n]).then(() =&gt; {\n  playMenu.classList.remove('hidden');\n  usernameInput.focus();\n  playButton.onclick = () =&gt; {\n    \/\/ Play!\n    play(usernameInput.value);\n    playMenu.classList.add('hidden');\n    initState();\n    startCapturingInput();\n    startRendering();\n    setLeaderboardHidden(false);\n  };\n});<\/code><\/pre>\n<p>\n\u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u043c, \u043d\u043e \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0435 \u0442\u0430\u043a \u043c\u043d\u043e\u0433\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439:<\/p>\n<ol>\n<li>\u0418\u043c\u043f\u043e\u0440\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 JS-\u0444\u0430\u0439\u043b\u043e\u0432.<\/li>\n<li>\u0418\u043c\u043f\u043e\u0440\u0442 CSS (\u0447\u0442\u043e\u0431\u044b Webpack \u0437\u043d\u0430\u043b, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u0445 \u0432 \u043d\u0430\u0448 \u043f\u0430\u043a\u0435\u0442 CSS).<\/li>\n<li>\u0417\u0430\u043f\u0443\u0441\u043a <code>connect()<\/code> \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0438 \u0437\u0430\u043f\u0443\u0441\u043a <code>downloadAssets()<\/code> \u0434\u043b\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0438\u0433\u0440\u044b.<\/li>\n<li><em>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u044d\u0442\u0430\u043f\u0430 3 <\/em> \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e (<code>playMenu<\/code>).<\/li>\n<li>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u00abPLAY\u00bb. \u041f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043a\u043d\u043e\u043f\u043a\u0438 \u043a\u043e\u0434 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0438\u0433\u0440\u0443 \u0438 \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0443, \u0447\u0442\u043e \u043c\u044b \u0433\u043e\u0442\u043e\u0432\u044b \u0438\u0433\u0440\u0430\u0442\u044c.<\/li>\n<\/ol>\n<p>\n\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u00ab\u043c\u044f\u0441\u043e\u00bb \u043d\u0430\u0448\u0435\u0439 \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0442\u0435\u0445 \u0444\u0430\u0439\u043b\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0444\u0430\u0439\u043b\u043e\u043c <code>index.js<\/code>. \u0421\u0435\u0439\u0447\u0430\u0441 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0438\u0445 \u0432\u0441\u0435 \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443.<\/p>\n<h2>4. \u041e\u0431\u043c\u0435\u043d \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/h2>\n<p>\n\u0412 \u044d\u0442\u043e\u0439 \u0438\u0433\u0440\u0435 \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0445\u043e\u0440\u043e\u0448\u043e \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <noindex><a rel=\"nofollow\" href=\"https:\/\/socket.io\/\">socket.io<\/a><\/noindex>. \u0412 Socket.io \u0435\u0441\u0442\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/WebSockets_API\">WebSockets<\/a><\/noindex>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0442 \u0434\u043b\u044f \u0434\u0432\u0443\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0439 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438: \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0443 <em>\u0438<\/em> \u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430\u043c \u043f\u043e \u0442\u043e\u043c\u0443 \u0436\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044e.<\/p>\n<p>\u0423 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b <code>src\/client\/networking.js<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0439\u043c\u0451\u0442\u0441\u044f <strong>\u0432\u0441\u0435\u043c\u0438<\/strong> \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u044f\u043c\u0438 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c:<\/p>\n<h5>networking.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">import io from 'socket.io-client';\nimport { processGameUpdate } from '.\/state';\n\nconst Constants = require('..\/shared\/constants');\n\nconst socket = io(`ws:\/\/${window.location.host}`);\nconst connectedPromise = new Promise(resolve =&gt; {\n  socket.on('connect', () =&gt; {\n    console.log('Connected to server!');\n    resolve();\n  });\n});\n\nexport const connect = onGameOver =&gt; (\n  connectedPromise.then(() =&gt; {\n    \/\/ Register callbacks\n    socket.on(Constants.MSG_TYPES.GAME_UPDATE, processGameUpdate);\n    socket.on(Constants.MSG_TYPES.GAME_OVER, onGameOver);\n  })\n);\n\nexport const play = username =&gt; {\n  socket.emit(Constants.MSG_TYPES.JOIN_GAME, username);\n};\n\nexport const updateDirection = dir =&gt; {\n  socket.emit(Constants.MSG_TYPES.INPUT, dir);\n};<\/code><\/pre>\n<p>\n<i>\u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0441\u0442\u0438 \u0442\u043e\u0436\u0435 \u0441\u043b\u0435\u0433\u043a\u0430 \u0441\u043e\u043a\u0440\u0430\u0449\u0451\u043d.<\/i><\/p>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u0442\u0440\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f:<\/p>\n<ul>\n<li>\u041c\u044b \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443. <code>connectedPromise<\/code> \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435.<\/li>\n<li>\u0415\u0441\u043b\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e, \u043c\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c callback-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 (<code>processGameUpdate()<\/code> \u0438 <code>onGameOver()<\/code>) \u0434\u043b\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/li>\n<li>\u042d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c <code>play()<\/code> \u0438 <code>updateDirection()<\/code>, \u0447\u0442\u043e\u0431\u044b \u0438\u0445 \u043c\u043e\u0433\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0444\u0430\u0439\u043b\u044b.<\/li>\n<\/ul>\n<p><\/p>\n<h2>5. \u0420\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/h2>\n<p>\n\u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443!<\/p>\n<p>\u2026\u043d\u043e \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u043d\u0443\u0436\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0432\u0441\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f (\u0440\u0435\u0441\u0443\u0440\u0441\u044b), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432:<\/p>\n<h5>assets.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const ASSET_NAMES = ['ship.svg', 'bullet.svg'];\n\nconst assets = {};\nconst downloadPromise = Promise.all(ASSET_NAMES.map(downloadAsset));\n\nfunction downloadAsset(assetName) {\n  return new Promise(resolve =&gt; {\n    const asset = new Image();\n    asset.onload = () =&gt; {\n      console.log(`Downloaded ${assetName}`);\n      assets[assetName] = asset;\n      resolve();\n    };\n    asset.src = `\/assets\/${assetName}`;\n  });\n}\n\nexport const downloadAssets = () =&gt; downloadPromise;\nexport const getAsset = assetName =&gt; assets[assetName];<\/code><\/pre>\n<p>\n\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435 \u0442\u0430\u043a \u0441\u043b\u043e\u0436\u043d\u043e! \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u043c\u044b\u0441\u043b \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 <code>assets<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c \u043a\u043b\u044e\u0447 \u0438\u043c\u0435\u043d\u0438 \u0444\u0430\u0439\u043b\u0430 \u043a \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 <code>Image<\/code>. \u041a\u043e\u0433\u0434\u0430 \u0440\u0435\u0441\u0443\u0440\u0441 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0441\u044f, \u043c\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0435\u0433\u043e \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 <code>assets<\/code> \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c. \u041a\u043e\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043e \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 (\u0442\u043e \u0435\u0441\u0442\u044c \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b <strong>\u0432\u0441\u0435<\/strong> \u0440\u0435\u0441\u0443\u0440\u0441\u044b), \u043c\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c <code>downloadPromise<\/code>.<\/p>\n<p>\u0421\u043a\u0430\u0447\u0430\u0432 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043a \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0443. \u041a\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u043d\u043e \u0440\u0430\u043d\u0435\u0435, \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <noindex><a rel=\"nofollow\" href=\"https:\/\/www.w3schools.com\/html\/html5_canvas.asp\">HTML5 Canvas<\/a><\/noindex> (<code>&lt;canvas&gt;<\/code>). \u041d\u0430\u0448\u0430 \u0438\u0433\u0440\u0430 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ol>\n<li>\u0424\u043e\u043d<\/li>\n<li>\u041a\u043e\u0440\u0430\u0431\u043b\u044c \u0438\u0433\u0440\u043e\u043a\u0430<\/li>\n<li>\u0414\u0440\u0443\u0433\u0438\u0445 \u0438\u0433\u0440\u043e\u043a\u043e\u0432, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u0432 \u0438\u0433\u0440\u0435<\/li>\n<li>\u0421\u043d\u0430\u0440\u044f\u0434\u044b<\/li>\n<\/ol>\n<p>\n\u0412\u043e\u0442 \u0432\u0430\u0436\u043d\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b <code>src\/client\/render.js<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u044e\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0435 \u0432\u044b\u0448\u0435 \u0447\u0435\u0442\u044b\u0440\u0435 \u043f\u0443\u043d\u043a\u0442\u0430:<\/p>\n<h5>render.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">import { getAsset } from '.\/assets';\nimport { getCurrentState } from '.\/state';\n\nconst Constants = require('..\/shared\/constants');\nconst { PLAYER_RADIUS, PLAYER_MAX_HP, BULLET_RADIUS, MAP_SIZE } = Constants;\n\n\/\/ Get the canvas graphics context\nconst canvas = document.getElementById('game-canvas');\nconst context = canvas.getContext('2d');\n\n\/\/ Make the canvas fullscreen\ncanvas.width = window.innerWidth;\ncanvas.height = window.innerHeight;\n\nfunction render() {\n  const { me, others, bullets } = getCurrentState();\n  if (!me) {\n    return;\n  }\n\n  \/\/ Draw background\n  renderBackground(me.x, me.y);\n\n  \/\/ Draw all bullets\n  bullets.forEach(renderBullet.bind(null, me));\n\n  \/\/ Draw all players\n  renderPlayer(me, me);\n  others.forEach(renderPlayer.bind(null, me));\n}\n\n\/\/ ... Helper functions here excluded\n\nlet renderInterval = null;\nexport function startRendering() {\n  renderInterval = setInterval(render, 1000 \/ 60);\n}\nexport function stopRendering() {\n  clearInterval(renderInterval);\n}<\/code><\/pre>\n<p>\n<i>\u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0442\u043e\u0436\u0435 \u0441\u043e\u043a\u0440\u0430\u0449\u0451\u043d \u0434\u043b\u044f \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0441\u0442\u0438.<\/i><\/p>\n<p><code>render()<\/code> \u2014 \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430. <code>startRendering()<\/code> \u0438 <code>stopRendering()<\/code> \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0435\u0439 \u0446\u0438\u043a\u043b\u043e\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 60 FPS.<\/p>\n<p>\u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>renderBullet()<\/code>) \u043d\u0435 \u0442\u0430\u043a \u0432\u0430\u0436\u043d\u044b, \u043d\u043e \u0432\u043e\u0442 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<h5>render.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">function renderBullet(me, bullet) {\n  const { x, y } = bullet;\n  context.drawImage(\n    getAsset('bullet.svg'),\n    canvas.width \/ 2 + x - me.x - BULLET_RADIUS,\n    canvas.height \/ 2 + y - me.y - BULLET_RADIUS,\n    BULLET_RADIUS * 2,\n    BULLET_RADIUS * 2,\n  );\n}<\/code><\/pre>\n<p>\n\u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u0447\u0442\u043e \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>getAsset()<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u043d\u0435\u0435 \u0432\u0438\u0434\u0435\u043b\u0438 \u0432 <code>asset.js<\/code>!<\/p>\n<blockquote><p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430, \u0442\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u043e\u0441\u0442\u0430\u0432\u0448\u0443\u044e\u0441\u044f \u0447\u0430\u0441\u0442\u044c <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/vzhou842\/example-.io-game\/blob\/master\/src\/client\/render.js\">src\/client\/render.js<\/a><\/noindex>.<\/p><\/blockquote>\n<p><\/p>\n<h2>6. \u041a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0439 \u0432\u0432\u043e\u0434<\/h2>\n<p>\n\u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u0433\u0440\u0443 <em>\u0438\u0433\u0440\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0439<\/em>! \u0421\u0445\u0435\u043c\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439: \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u044b\u0448\u044c (\u043d\u0430 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435) \u0438\u043b\u0438 \u043a\u0430\u0441\u0430\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 (\u043d\u0430 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435). \u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e, \u043c\u044b \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/EventListener\">Event Listeners<\/a><\/noindex> \u0434\u043b\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439 Mouse \u0438 Touch.<br \/>\n\u0412\u0441\u0435\u043c \u044d\u0442\u0438\u043c \u0437\u0430\u0439\u043c\u0451\u0442\u0441\u044f <code>src\/client\/input.js<\/code>:<\/p>\n<h5>input.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">import { updateDirection } from '.\/networking';\n\nfunction onMouseInput(e) {\n  handleInput(e.clientX, e.clientY);\n}\n\nfunction onTouchInput(e) {\n  const touch = e.touches[0];\n  handleInput(touch.clientX, touch.clientY);\n}\n\nfunction handleInput(x, y) {\n  const dir = Math.atan2(x - window.innerWidth \/ 2, window.innerHeight \/ 2 - y);\n  updateDirection(dir);\n}\n\nexport function startCapturingInput() {\n  window.addEventListener('mousemove', onMouseInput);\n  window.addEventListener('touchmove', onTouchInput);\n}\n\nexport function stopCapturingInput() {\n  window.removeEventListener('mousemove', onMouseInput);\n  window.removeEventListener('touchmove', onTouchInput);\n}<\/code><\/pre>\n<p>\n<code>onMouseInput()<\/code> \u0438 <code>onTouchInput()<\/code> \u2014 \u044d\u0442\u043e Event Listeners, \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0435 <code>updateDirection()<\/code> (\u0438\u0437 <code>networking.js<\/code>) \u043f\u0440\u0438 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432\u0432\u043e\u0434\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0438 \u043c\u044b\u0448\u0438). <code>updateDirection()<\/code> \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u043c\u0435\u043d\u043e\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432\u0432\u043e\u0434\u0430 \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0433\u0440\u044b.<\/p>\n<h2>7. \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/h2>\n<p><\/p>\n<blockquote><p>\u042d\u0442\u043e\u0442 \u0440\u0430\u0437\u0434\u0435\u043b \u2014 \u0441\u0430\u043c\u044b\u0439 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u043e\u0441\u0442\u0430. \u041d\u0435 \u0440\u0430\u0441\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0439\u0442\u0435\u0441\u044c, \u0435\u0441\u043b\u0438 \u043d\u0435 \u043f\u043e\u0439\u043c\u0451\u0442\u0435 \u0435\u0433\u043e \u0441 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044f! \u041c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430\u0436\u0435 \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0438 \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u043d\u0435\u043c\u0443 \u043f\u043e\u0437\u0436\u0435.<\/p><\/blockquote>\n<p>\n\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043a\u0443\u0441\u043e\u043a \u043f\u0430\u0437\u043b\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u2014 \u044d\u0442\u043e <strong>state<\/strong>. \u041f\u043e\u043c\u043d\u0438\u0442\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u043a\u043e\u0434\u0430 \u0438\u0437 \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u00ab\u0420\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u00bb?<\/p>\n<h5>render.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">import { getCurrentState } from '.\/state';\n\nfunction render() {\n  const { me, others, bullets } = getCurrentState();\n\n  \/\/ Do the rendering\n  \/\/ ...\n}<\/code><\/pre>\n<p>\n<code>getCurrentState()<\/code> \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u043c \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0433\u0440\u044b \u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0435 <strong>\u0432 \u043b\u044e\u0431\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438<\/strong> \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0445 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0412\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440:<\/p>\n<pre><code class=\"cpp\">{\n  \"t\": 1555960373725,\n  \"me\": {\n    \"x\": 2213.8050880413657,\n    \"y\": 1469.370893425012,\n    \"direction\": 1.3082443894581433,\n    \"id\": \"AhzgAtklgo2FJvwWAADO\",\n    \"hp\": 100\n  },\n  \"others\": [],\n  \"bullets\": [\n    {\n      \"id\": \"RUJfJ8Y18n\",\n      \"x\": 2354.029197099604,\n      \"y\": 1431.6848318262666\n    },\n    {\n      \"id\": \"ctg5rht5s\",\n      \"x\": 2260.546457727445,\n      \"y\": 1456.8088728920968\n    }\n  ],\n  \"leaderboard\": [\n    {\n      \"username\": \"Player\",\n      \"score\": 3\n    }\n  ]\n}<\/code><\/pre>\n<p>\n\u041a\u0430\u0436\u0434\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u044f\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u043f\u043e\u043b\u0435\u0439:<\/p>\n<ul>\n<li><strong>t<\/strong>: \u043c\u0435\u0442\u043a\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0449\u0430\u044f \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f.<\/li>\n<li><strong>me<\/strong>: \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0431 \u0438\u0433\u0440\u043e\u043a\u0435, \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0449\u0435\u0433\u043e \u044d\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435.<\/li>\n<li><strong>others<\/strong>: \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0434\u0440\u0443\u0433\u0438\u0445 \u0438\u0433\u0440\u043e\u043a\u0430\u0445, \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0432 \u0442\u043e\u0439 \u0436\u0435 \u0438\u0433\u0440\u0435.<\/li>\n<li><strong>bullets<\/strong>: \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0441\u043d\u0430\u0440\u044f\u0434\u0430\u0445 \u0432 \u0438\u0433\u0440\u0435.<\/li>\n<li><strong>leaderboard<\/strong>: \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043b\u0438\u0434\u0435\u0440\u043e\u0432. \u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435 \u043c\u044b \u0438\u0445 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u043c.<\/li>\n<\/ul>\n<p><\/p>\n<h3>7.1 \u041d\u0430\u0438\u0432\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/h3>\n<p>\n\u041d\u0430\u0438\u0432\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>getCurrentState()<\/code> \u043c\u043e\u0436\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b.<\/p>\n<h5>naive-state.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">let lastGameUpdate = null;\n\n\/\/ Handle a newly received game update.\nexport function processGameUpdate(update) {\n  lastGameUpdate = update;\n}\n\nexport function getCurrentState() {\n  return lastGameUpdate;\n}<\/code><\/pre>\n<p>\n\u041a\u0440\u0430\u0441\u0438\u0432\u043e \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u043e! \u041d\u043e \u0435\u0441\u043b\u0438 \u0431\u044b \u0432\u0441\u0451 \u0431\u044b\u043b\u043e \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e. \u041e\u0434\u043d\u0430 \u0438\u0437 \u043f\u0440\u0438\u0447\u0438\u043d, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0442\u0430\u043a\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u0442\u0438\u0447\u043d\u0430: <strong>\u043e\u043d\u0430 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u0447\u0430\u0441\u0442\u043e\u0442\u0443 \u043a\u0430\u0434\u0440\u043e\u0432 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 \u0442\u0430\u043a\u0442\u043e\u0432 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/strong>.<\/p>\n<blockquote><p><strong>\u0427\u0430\u0441\u0442\u043e\u0442\u0430 \u043a\u0430\u0434\u0440\u043e\u0432 (Frame Rate)<\/strong>: \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u0430\u0434\u0440\u043e\u0432 (\u0442.\u0435. \u0432\u044b\u0437\u043e\u0432\u043e\u0432 <code>render()<\/code>) \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443, \u0438\u043b\u0438 FPS. \u0412 \u0438\u0433\u0440\u0430\u0445 \u043e\u0431\u044b\u0447\u043d\u043e \u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0438\u0447\u044c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435 60 FPS.<\/p><\/blockquote>\n<p><\/p>\n<blockquote><p><strong>\u0427\u0430\u0441\u0442\u043e\u0442\u0430 \u0442\u0430\u043a\u0442\u043e\u0432 (Tick Rate)<\/strong>: \u0447\u0430\u0441\u0442\u043e\u0442\u0430, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c. <strong>\u0427\u0430\u0441\u0442\u043e \u043e\u043d\u0430 \u043d\u0438\u0436\u0435, \u0447\u0435\u043c \u0447\u0430\u0441\u0442\u043e\u0442\u0430 \u043a\u0430\u0434\u0440\u043e\u0432<\/strong>. \u0412 \u043d\u0430\u0448\u0435\u0439 \u0438\u0433\u0440\u0435 \u0441\u0435\u0440\u0432\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 30 \u0442\u0430\u043a\u0442\u043e\u0432 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443.<\/p><\/blockquote>\n<p>\n\u0415\u0441\u043b\u0438 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b, \u0442\u043e FPS \u043f\u043e \u0441\u0443\u0442\u0438 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0432\u044b\u0441\u0438\u0442\u044c 30, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e <em>\u043c\u044b \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 30 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443<\/em>. \u0414\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c <code>render()<\/code> 60 \u0440\u0430\u0437 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443, \u0442\u043e \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u044d\u0442\u0438\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u043f\u043e \u0441\u0443\u0442\u0438 \u043d\u0435 \u0434\u0435\u043b\u0430\u044f \u043d\u0438\u0447\u0435\u0433\u043e. \u0415\u0449\u0451 \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043d\u0430\u0438\u0432\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043e\u043d\u0430 <strong>\u043f\u043e\u0434\u0432\u0435\u0440\u0436\u0435\u043d\u0430 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430\u043c<\/strong>. \u041f\u0440\u0438 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b \u0440\u043e\u0432\u043d\u043e \u0447\u0435\u0440\u0435\u0437 \u043a\u0430\u0436\u0434\u044b\u0435 33 \u043c\u0441 (30 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443):<\/p>\n<p><img decoding=\"async\" alt=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io\" src=\"\/wp-content\/uploads\/2019\/05\/7d390b63f5afcecd1f2235260dc0c8cd.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043d\u0438\u0447\u0442\u043e \u043d\u0435 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e. \u0411\u043e\u043b\u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0430\u044f \u043a\u0430\u0440\u0442\u0438\u043d\u0430:<br \/>\n<img decoding=\"async\" alt=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io\" src=\"\/wp-content\/uploads\/2019\/05\/e2d2f68c35474df42a85c69ef3c7395d.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u041d\u0430\u0438\u0432\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u2014 \u044d\u0442\u043e \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430\u0438\u0445\u0443\u0434\u0448\u0438\u0439 \u0441\u043b\u0443\u0447\u0430\u0439, \u043a\u043e\u0433\u0434\u0430 \u0434\u0435\u043b\u043e \u0434\u043e\u0445\u043e\u0434\u0438\u0442 \u0434\u043e \u0437\u0430\u0434\u0435\u0440\u0436\u0435\u043a. \u0415\u0441\u043b\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0441 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439 50 \u043c\u0441, \u0442\u043e <strong>\u043a\u043b\u0438\u0435\u043d\u0442 \u0437\u0430\u0442\u043e\u0440\u043c\u0430\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f<\/strong> \u043d\u0430 \u043b\u0438\u0448\u043d\u0438\u0435 50 \u043c\u0441, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0433\u0440\u044b \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f. \u041c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u043e \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e \u0434\u043b\u044f \u0438\u0433\u0440\u043e\u043a\u0430: \u0438\u0437-\u0437\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0445 \u0442\u043e\u0440\u043c\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u0433\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0434\u0451\u0440\u0433\u0430\u043d\u043d\u043e\u0439 \u0438 \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0439.<\/p>\n<h3>7.2 \u0423\u043b\u0443\u0447\u0448\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/h3>\n<p>\n\u041c\u044b \u0432\u043d\u0435\u0441\u0451\u043c \u0432 \u043d\u0430\u0438\u0432\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <strong>\u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0443 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430<\/strong> \u043d\u0430 100 \u043c\u0441. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u00ab\u0442\u0435\u043a\u0443\u0449\u0435\u0435\u00bb \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u043e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u0433\u0440\u044b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043d\u0430 100 \u043c\u0441. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0432\u043d\u043e <strong>150<\/strong>, \u0442\u043e \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c\u0441\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u044b\u043b \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u043e \u0432\u0440\u0435\u043c\u044f <strong>50<\/strong>:<\/p>\n<p><img decoding=\"async\" alt=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io\" src=\"\/wp-content\/uploads\/2019\/05\/e669708413c37c753b8f36286657b6cf.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u042d\u0442\u043e \u0434\u0430\u0451\u0442 \u043d\u0430\u043c \u0431\u0443\u0444\u0435\u0440 \u0432 100 \u043c\u0441, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u0435\u0440\u0435\u0436\u0438\u0442\u044c \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0438\u0433\u0440\u044b:<\/p>\n<p><img decoding=\"async\" alt=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io\" src=\"\/wp-content\/uploads\/2019\/05\/57037994c04d5ad9f730ee8d879daf84.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u0420\u0430\u0441\u043f\u043b\u0430\u0442\u043e\u0439 \u0437\u0430 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u0430\u044f <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Input_lag\" rel=\"noopener noreferrer\">\u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u0432\u0432\u043e\u0434\u0430 (input lag)<\/a><\/noindex> \u043d\u0430 100 \u043c\u0441. \u042d\u0442\u043e \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0436\u0435\u0440\u0442\u0432\u0430 \u0437\u0430 \u043f\u043b\u0430\u0432\u043d\u044b\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u2014 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0438\u0433\u0440\u043e\u043a\u043e\u0432 (\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043a\u0430\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0445) \u0434\u0430\u0436\u0435 \u043d\u0435 \u0437\u0430\u043c\u0435\u0442\u0438\u0442 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438. \u041b\u044e\u0434\u044f\u043c \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043f\u0440\u043e\u0449\u0435 \u043f\u0440\u0438\u0441\u043f\u043e\u0441\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u043a \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0435 \u0432 100 \u043c\u0441, \u0447\u0435\u043c \u0438\u0433\u0440\u0430\u0442\u044c \u0441 \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u043e\u0439.<\/p>\n<blockquote><p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0443\u044e \u0442\u0435\u0445\u043d\u0438\u043a\u0443 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Client-side_prediction\" rel=\"noopener noreferrer\">\u00ab\u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u00bb<\/a><\/noindex>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u043e\u0440\u043e\u0448\u043e \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e \u0441\u043d\u0438\u0436\u0435\u043d\u0438\u0435\u043c \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c\u044b\u0445 \u0437\u0430\u0434\u0435\u0440\u0436\u0435\u043a, \u043d\u043e \u0432 \u044d\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0435 \u043e\u043d\u0430 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442.<\/p><\/blockquote>\n<p>\n\u0415\u0449\u0451 \u043e\u0434\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u2014 \u044d\u0442\u043e <strong>\u043b\u0438\u043d\u0435\u0439\u043d\u0430\u044f \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u044f<\/strong>. \u0418\u0437-\u0437\u0430 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u043c\u044b \u043e\u0431\u044b\u0447\u043d\u043e \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043d\u0430 \u043e\u0434\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u0433\u043e\u043d\u044f\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0435. \u041a\u043e\u0433\u0434\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>getCurrentState()<\/code>, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Linear_interpolation\" rel=\"noopener noreferrer\">\u043b\u0438\u043d\u0435\u0439\u043d\u0443\u044e \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u044e<\/a><\/noindex> \u043c\u0435\u0436\u0434\u0443 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u0438\u0433\u0440\u044b \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u0434 \u0438 \u043f\u043e\u0441\u043b\u0435 \u0442\u0435\u043a\u0443\u0449\u0438\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0435:<\/p>\n<p><img decoding=\"async\" alt=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io\" src=\"\/wp-content\/uploads\/2019\/05\/9213a0a72e830e0a76e814374d17b536.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u042d\u0442\u043e \u0440\u0435\u0448\u0430\u0435\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 \u043a\u0430\u0434\u0440\u043e\u0432: \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u0430\u0434\u0440\u044b \u0441 \u043b\u044e\u0431\u043e\u0439 \u043d\u0443\u0436\u043d\u043e\u0439 \u043d\u0430\u043c \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439!<\/p>\n<h3>7.3 \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/h3>\n<p>\n\u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 <code>src\/client\/state.js<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0438 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0443 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430, \u0438 \u043b\u0438\u043d\u0435\u0439\u043d\u0443\u044e \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u044e, \u043d\u043e \u044d\u0442\u043e \u043d\u0435\u043d\u0430\u0434\u043e\u043b\u0433\u043e. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u043e\u0431\u044c\u0451\u043c \u043a\u043e\u0434 \u043d\u0430 \u0434\u0432\u0435 \u0447\u0430\u0441\u0442\u0438. \u0412\u043e\u0442 \u043f\u0435\u0440\u0432\u0430\u044f:<\/p>\n<h5>state.js, \u0447\u0430\u0441\u0442\u044c 1<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const RENDER_DELAY = 100;\n\nconst gameUpdates = [];\nlet gameStart = 0;\nlet firstServerTimestamp = 0;\n\nexport function initState() {\n  gameStart = 0;\n  firstServerTimestamp = 0;\n}\n\nexport function processGameUpdate(update) {\n  if (!firstServerTimestamp) {\n    firstServerTimestamp = update.t;\n    gameStart = Date.now();\n  }\n  gameUpdates.push(update);\n\n  \/\/ Keep only one game update before the current server time\n  const base = getBaseUpdate();\n  if (base &gt; 0) {\n    gameUpdates.splice(0, base);\n  }\n}\n\nfunction currentServerTime() {\n  return firstServerTimestamp + (Date.now() - gameStart) - RENDER_DELAY;\n}\n\n\/\/ Returns the index of the base update, the first game update before\n\/\/ current server time, or -1 if N\/A.\nfunction getBaseUpdate() {\n  const serverTime = currentServerTime();\n  for (let i = gameUpdates.length - 1; i &gt;= 0; i--) {\n    if (gameUpdates[i].t &lt;= serverTime) {\n      return i;\n    }\n  }\n  return -1;\n}<\/code><\/pre>\n<p>\n\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 <code>currentServerTime()<\/code>. \u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0435\u043b\u0438 \u0440\u0430\u043d\u0435\u0435, \u0432 \u043a\u0430\u0436\u0434\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u043c\u0435\u0442\u043a\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u041c\u044b \u0445\u043e\u0442\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0443 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443, \u043e\u0442\u0441\u0442\u0430\u0432\u0430\u044f \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 100 \u043c\u0441, \u043d\u043e <strong>\u043c\u044b \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0443\u0437\u043d\u0430\u0435\u043c, \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435<\/strong>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0437\u043d\u0430\u0442\u044c, \u043a\u0430\u043a \u0434\u043e\u043b\u0433\u043e \u0434\u043e\u0431\u0438\u0440\u0430\u043b\u043e\u0441\u044c \u0434\u043e \u043d\u0430\u0441 \u043b\u044e\u0431\u043e\u0435 \u0438\u0437 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439. \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u043d\u0435\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c \u0438 \u0435\u0433\u043e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043c\u043e\u0436\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u0432\u0430\u0440\u044c\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f!<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043e\u0431\u043e\u0439\u0442\u0438 \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443, \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u0443\u043c\u043d\u0443\u044e \u0430\u043f\u043f\u0440\u043e\u043a\u0441\u0438\u043c\u0430\u0446\u0438\u044e: \u043c\u044b <strong>\u043f\u0440\u0438\u0442\u0432\u043e\u0440\u0438\u043c\u0441\u044f, \u0447\u0442\u043e \u043f\u0435\u0440\u0432\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0431\u044b\u043b\u043e \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e<\/strong>. \u0415\u0441\u043b\u0438 \u0431\u044b \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0432\u0435\u0440\u043d\u043e, \u0442\u043e \u043c\u044b \u0431\u044b \u0437\u043d\u0430\u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 \u044d\u0442\u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442! \u041c\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043c\u0435\u0442\u043a\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 <code>firstServerTimestamp<\/code> \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043d\u0430\u0448\u0443 <strong>\u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e<\/strong> (\u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0443\u044e) \u043c\u0435\u0442\u043a\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u0442\u043e\u0442 \u0436\u0435 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432 <code>gameStart<\/code>.<\/p>\n<p>\u041e\u0439, \u043f\u043e\u0441\u0442\u043e\u0439\u0442\u0435-\u043a\u0430. <b>\u0420\u0430\u0437\u0432\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 = \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0435?<\/b> \u041f\u043e\u0447\u0435\u043c\u0443 \u043c\u044b \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0435\u043c \u00ab\u043c\u0435\u0442\u043a\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u00bb \u0438 \u00ab\u043c\u0435\u0442\u043a\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u00bb? \u042d\u0442\u043e \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 \u0432\u043e\u043f\u0440\u043e\u0441! \u041e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u044d\u0442\u043e \u043d\u0435 \u043e\u0434\u043d\u043e \u0438 \u0442\u043e \u0436\u0435. <code>Date.now()<\/code> \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u043c\u0435\u0442\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0435 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u044d\u0442\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u043c\u0430\u0448\u0438\u043d \u0444\u0430\u043a\u0442\u043e\u0440\u043e\u0432. <strong>\u041d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0439\u0442\u0435, \u0447\u0442\u043e \u043c\u0435\u0442\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438 \u043d\u0430 \u0432\u0441\u0435\u0445 \u043c\u0430\u0448\u0438\u043d\u0430\u0445.<\/strong><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 <code>currentServerTime()<\/code>: \u043e\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <strong>\u043c\u0435\u0442\u043a\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430<\/strong>. \u0414\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u044d\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 (<code>firstServerTimestamp &lt;+ (Date.now() - gameStart)<\/code>) \u043c\u0438\u043d\u0443\u0441 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 (<code>RENDER_DELAY<\/code>).<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c\u0441\u044f, \u043a\u0430\u043a \u043c\u044b \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b. \u041f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>processGameUpdate()<\/code>, \u0438 \u043c\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 <code>gameUpdates<\/code>. \u0417\u0430\u0442\u0435\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u043c\u044f\u0442\u0438 \u043c\u044b \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0432\u0441\u0435 \u0441\u0442\u0430\u0440\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e <strong>\u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f<\/strong>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d\u0438 \u043d\u0430\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u044b.<\/p>\n<p>\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 \u00ab\u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\u00bb? \u042d\u0442\u043e <strong>\u043f\u0435\u0440\u0432\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u043d\u0430\u0445\u043e\u0434\u0438\u043c, \u0434\u0432\u0438\u0433\u0430\u044f\u0441\u044c \u043d\u0430\u0437\u0430\u0434 \u043e\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/strong>. \u041f\u043e\u043c\u043d\u0438\u0442\u0435 \u044d\u0442\u0443 \u0441\u0445\u0435\u043c\u0443?<\/p>\n<p><img decoding=\"async\" alt=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io\" src=\"\/wp-content\/uploads\/2019\/05\/1ff7ecd395c2a4e9a4c17c1ec1872fc5.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u043b\u0435\u0432\u0430 \u043e\u0442 \u00abClient Render Time\u00bb \u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0431\u0430\u0437\u043e\u0432\u044b\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435\u043c.<\/p>\n<p>\u0414\u043b\u044f \u0447\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435? \u041f\u043e\u0447\u0435\u043c\u0443 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e? \u0427\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u044d\u0442\u043e\u043c, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 <em>\u043d\u0430\u043a\u043e\u043d\u0435\u0446-\u0442\u043e<\/em> \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <code>getCurrentState()<\/code>:<\/p>\n<h5>state.js, \u0447\u0430\u0441\u0442\u044c 2<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">export function getCurrentState() {\n  if (!firstServerTimestamp) {\n    return {};\n  }\n\n  const base = getBaseUpdate();\n  const serverTime = currentServerTime();\n\n  \/\/ If base is the most recent update we have, use its state.\n  \/\/ Else, interpolate between its state and the state of (base + 1).\n  if (base &lt; 0) {\n    return gameUpdates[gameUpdates.length - 1];\n  } else if (base === gameUpdates.length - 1) {\n    return gameUpdates[base];\n  } else {\n    const baseUpdate = gameUpdates[base];\n    const next = gameUpdates[base + 1];\n    const r = (serverTime - baseUpdate.t) \/ (next.t - baseUpdate.t);\n    return {\n      me: interpolateObject(baseUpdate.me, next.me, r),\n      others: interpolateObjectArray(baseUpdate.others, next.others, r),\n      bullets: interpolateObjectArray(baseUpdate.bullets, next.bullets, r),\n    };\n  }\n}<\/code><\/pre>\n<p>\n\u041c\u044b \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0442\u0440\u0438 \u0441\u043b\u0443\u0447\u0430\u044f:<\/p>\n<ol>\n<li><code>base &lt; 0<\/code> \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u043d\u0435\u0442 (\u0441\u043c. \u0432\u044b\u0448\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <code>getBaseUpdate()<\/code>). \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0441\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0441\u0440\u0430\u0437\u0443 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0438\u0433\u0440\u044b \u0438\u0437-\u0437\u0430 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430. \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u0430\u043c\u043e\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u043e\u0431\u043d\u043e\u043b\u0432\u0435\u043d\u0438\u0435.<\/li>\n<li><code>base<\/code> \u2014 \u044d\u0442\u043e \u0441\u0430\u043c\u043e\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u0438\u0437-\u0437\u0430 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u0438\u043b\u0438 \u043f\u043b\u043e\u0445\u043e\u0439 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u043e\u043c. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0442\u043e\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u0430\u043c\u043e\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c.<\/li>\n<li>\u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438 \u0434\u043e, \u0438 \u043f\u043e\u0441\u043b\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e <strong>\u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c<\/strong>!<\/li>\n<\/ol>\n<p>\n\u0412\u0441\u0451, \u0447\u0442\u043e \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0432 <code>state.js<\/code> \u2014 \u044d\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043b\u0438\u043d\u0435\u0439\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f \u0441\u043e\u0431\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u0443\u044e (\u043d\u043e \u0441\u043a\u0443\u0447\u043d\u0443\u044e) \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0443. \u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0435\u0451 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0442\u043e \u043e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 <code>state.js<\/code> \u043d\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/vzhou842\/example-.io-game\/blob\/master\/src\/client\/state.js\" rel=\"noopener noreferrer\">Github<\/a><\/noindex>.<\/p>\n<h2>\u0427\u0430\u0441\u0442\u044c 2. \u0411\u044d\u043a\u0435\u043d\u0434-\u0441\u0435\u0440\u0432\u0435\u0440<\/h2>\n<p>\n\u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0431\u044d\u043a\u0435\u043d\u0434 Node.js, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043d\u0430\u0448\u0438\u043c <noindex><a rel=\"nofollow\" href=\"https:\/\/example-io-game.victorzhou.com\/\">\u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0438\u0433\u0440\u044b .io<\/a><\/noindex>.<\/p>\n<h2>1. \u0412\u0445\u043e\u0434\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/h2>\n<p>\n\u0414\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f Node.js \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <noindex><a rel=\"nofollow\" href=\"https:\/\/expressjs.com\/\">Express<\/a><\/noindex>. \u0415\u0433\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u043e\u0439 \u0437\u0430\u0439\u043c\u0451\u0442\u0441\u044f \u043d\u0430\u0448 \u0444\u0430\u0439\u043b \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 <code>src\/server\/server.js<\/code>:<\/p>\n<h5>server.js, \u0447\u0430\u0441\u0442\u044c 1<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const express = require('express');\nconst webpack = require('webpack');\nconst webpackDevMiddleware = require('webpack-dev-middleware');\nconst webpackConfig = require('..\/..\/webpack.dev.js');\n\n\/\/ Setup an Express server\nconst app = express();\napp.use(express.static('public'));\n\nif (process.env.NODE_ENV === 'development') {\n  \/\/ Setup Webpack for development\n  const compiler = webpack(webpackConfig);\n  app.use(webpackDevMiddleware(compiler));\n} else {\n  \/\/ Static serve the dist\/ folder in production\n  app.use(express.static('dist'));\n}\n\n\/\/ Listen on port\nconst port = process.env.PORT || 3000;\nconst server = app.listen(port);\nconsole.log(`Server listening on port ${port}`);<\/code><\/pre>\n<p>\n\u041f\u043e\u043c\u043d\u0438\u0442\u0435, \u0447\u0442\u043e \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u043b\u0438 Webpack? \u0418\u043c\u0435\u043d\u043d\u043e \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Webpack. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0438\u0445 \u0434\u0432\u0443\u043c\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438:<\/p>\n<ul>\n<li>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/webpack\/webpack-dev-middleware\">webpack-dev-middleware<\/a><\/noindex> \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u0435\u0440\u0435\u0441\u0431\u043e\u0440\u043a\u0438 \u043d\u0430\u0448\u0438\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0438\u043b\u0438<\/li>\n<li>\u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0430\u043f\u043a\u0443 <code>dist\/<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e Webpack \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u0444\u0430\u0439\u043b\u044b \u043f\u043e\u0441\u043b\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430.<\/li>\n<\/ul>\n<p>\n\u0415\u0449\u0451 \u043e\u0434\u043d\u0430 \u0432\u0430\u0436\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 <code>server.js<\/code> \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/socket.io\/\">socket.io<\/a><\/noindex>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 Express:<\/p>\n<h5>server.js, \u0447\u0430\u0441\u0442\u044c 2<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const socketio = require('socket.io');\nconst Constants = require('..\/shared\/constants');\n\n\/\/ Setup Express\n\/\/ ...\nconst server = app.listen(port);\nconsole.log(`Server listening on port ${port}`);\n\n\/\/ Setup socket.io\nconst io = socketio(server);\n\n\/\/ Listen for socket.io connections\nio.on('connection', socket =&gt; {\n  console.log('Player connected!', socket.id);\n\n  socket.on(Constants.MSG_TYPES.JOIN_GAME, joinGame);\n  socket.on(Constants.MSG_TYPES.INPUT, handleInput);\n  socket.on('disconnect', onDisconnect);\n});<\/code><\/pre>\n<p>\n\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f socket.io \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043a\u0435\u0442\u0430. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0443-\u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u0443 <code>game<\/code>:<\/p>\n<h5>server.js, \u0447\u0430\u0441\u0442\u044c 3<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const Game = require('.\/game');\n\n\/\/ ...\n\n\/\/ Setup the Game\nconst game = new Game();\n\nfunction joinGame(username) {\n  game.addPlayer(this, username);\n}\n\nfunction handleInput(dir) {\n  game.handleInput(this, dir);\n}\n\nfunction onDisconnect() {\n  game.removePlayer(this);\n}<\/code><\/pre>\n<p>\n\u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0438\u0433\u0440\u0443 \u0436\u0430\u043d\u0440\u0430 .io, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 <code>Game<\/code> (\u00abGame\u00bb) \u2013 \u0432\u0441\u0435 \u0438\u0433\u0440\u043e\u043a\u0438 \u0438\u0433\u0440\u0430\u044e\u0442 \u043d\u0430 \u043e\u0434\u043d\u043e\u0439 \u0430\u0440\u0435\u043d\u0435! \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 <code>Game<\/code>.<\/p>\n<h2>2. Game \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/h2>\n<p>\n\u041a\u043b\u0430\u0441\u0441 <code>Game<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u0430\u043c\u0443\u044e \u0432\u0430\u0436\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u041e\u043d \u0438\u043c\u0435\u0435\u0442 \u0434\u0432\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438: <strong>\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u043e\u043a\u0430\u043c\u0438<\/strong> \u0438 <strong>\u0441\u0438\u043c\u0443\u043b\u044f\u0446\u0438\u044f \u0438\u0433\u0440\u044b<\/strong>.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u043f\u0435\u0440\u0432\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u2013 \u0441 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u043e\u043a\u0430\u043c\u0438.<\/p>\n<h5>game.js, \u0447\u0430\u0441\u0442\u044c 1<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const Constants = require('..\/shared\/constants');\nconst Player = require('.\/player');\n\nclass Game {\n  constructor() {\n    this.sockets = {};\n    this.players = {};\n    this.bullets = [];\n    this.lastUpdateTime = Date.now();\n    this.shouldSendUpdate = false;\n    setInterval(this.update.bind(this), 1000 \/ 60);\n  }\n\n  addPlayer(socket, username) {\n    this.sockets[socket.id] = socket;\n\n    \/\/ Generate a position to start this player at.\n    const x = Constants.MAP_SIZE * (0.25 + Math.random() * 0.5);\n    const y = Constants.MAP_SIZE * (0.25 + Math.random() * 0.5);\n    this.players[socket.id] = new Player(socket.id, username, x, y);\n  }\n\n  removePlayer(socket) {\n    delete this.sockets[socket.id];\n    delete this.players[socket.id];\n  }\n\n  handleInput(socket, dir) {\n    if (this.players[socket.id]) {\n      this.players[socket.id].setDirection(dir);\n    }\n  }\n\n  \/\/ ...\n}<\/code><\/pre>\n<p>\n\u0412 \u044d\u0442\u043e\u0439 \u0438\u0433\u0440\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u043f\u043e \u043f\u043e\u043b\u044e <code>id<\/code> \u0438\u0445 \u0441\u043e\u043a\u0435\u0442\u0430 socket.io (\u0435\u0441\u043b\u0438 \u0432\u044b \u0437\u0430\u043f\u0443\u0442\u0430\u043b\u0438\u0441\u044c, \u0442\u043e \u0441\u043d\u043e\u0432\u0430 \u0432\u0435\u0440\u043d\u0438\u0442\u0435\u0441\u044c \u043a <code>server.js<\/code>). Socket.io \u0441\u0430\u043c \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0441\u043e\u043a\u0435\u0442\u0443 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 <code>id<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043e\u0431 \u044d\u0442\u043e\u043c \u0431\u0435\u0441\u043f\u043e\u043a\u043e\u0438\u0442\u044c\u0441\u044f \u043d\u0435 \u043d\u0443\u0436\u043d\u043e. \u042f \u0431\u0443\u0434\u0443 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e <strong>ID \u0438\u0433\u0440\u043e\u043a\u0430<\/strong>.<\/p>\n<p>\u0417\u0430\u043f\u043e\u043c\u043d\u0438\u0432 \u044d\u0442\u043e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0438\u0437\u0443\u0447\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>Game<\/code>:<\/p>\n<ul>\n<li><code>sockets<\/code> \u2014 \u044d\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 ID \u0438\u0433\u0440\u043e\u043a\u0430 \u043a \u0441\u043e\u043a\u0435\u0442\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0432\u044f\u0437\u0430\u043d \u0441 \u0438\u0433\u0440\u043e\u043a\u043e\u043c. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0437\u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u043e\u043a\u0435\u0442\u0430\u043c \u043f\u043e \u0438\u0445 ID \u0438\u0433\u0440\u043e\u043a\u043e\u0432.<\/li>\n<li><code>players<\/code> \u2014 \u044d\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442, \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 ID \u0438\u0433\u0440\u043e\u043a\u0430 \u043a \u043e\u0431\u044a\u0435\u043a\u0442\u0443 code&gt;Player<\/li>\n<\/ul>\n<p>\n<code>bullets<\/code> \u2014 \u044d\u0442\u043e \u043c\u0430\u0441\u0441\u0438\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 <code>Bullet<\/code>, \u043d\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430.<br \/>\n<code>lastUpdateTime<\/code> \u2014 \u044d\u0442\u043e \u043c\u0435\u0442\u043a\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b. \u0412\u0441\u043a\u043e\u0440\u0435 \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c, \u043a\u0430\u043a \u043e\u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f.<br \/>\n<code>shouldSendUpdate<\/code> \u2014 \u044d\u0442\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f. \u0415\u0451 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u044b \u0442\u043e\u0436\u0435 \u0443\u0432\u0438\u0434\u0438\u043c \u0432\u0441\u043a\u043e\u0440\u0435.<br \/>\n\u041c\u0435\u0442\u043e\u0434\u044b <code>addPlayer()<\/code>, <code>removePlayer()<\/code> \u0438 <code>handleInput()<\/code> \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442\u044c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e, \u043e\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 <code>server.js<\/code>. \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0441\u0432\u0435\u0436\u0438\u0442\u044c \u043f\u0430\u043c\u044f\u0442\u044c, \u0432\u0435\u0440\u043d\u0438\u0442\u0435\u0441\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0432\u044b\u0448\u0435.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0441\u0442\u0440\u043e\u043a\u0430 <code>constructor()<\/code> \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 <strong>\u0446\u0438\u043a\u043b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f<\/strong> \u0438\u0433\u0440\u044b (\u0441 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439 60 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439\/\u0441):<\/p>\n<h5>game.js, \u0447\u0430\u0441\u0442\u044c 2<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const Constants = require('..\/shared\/constants');\nconst applyCollisions = require('.\/collisions');\n\nclass Game {\n  \/\/ ...\n\n  update() {\n    \/\/ Calculate time elapsed\n    const now = Date.now();\n    const dt = (now - this.lastUpdateTime) \/ 1000;\n    this.lastUpdateTime = now;\n\n    \/\/ Update each bullet\n    const bulletsToRemove = [];\n    this.bullets.forEach(bullet =&gt; {\n      if (bullet.update(dt)) {\n        \/\/ Destroy this bullet\n        bulletsToRemove.push(bullet);\n      }\n    });\n    this.bullets = this.bullets.filter(\n      bullet =&gt; !bulletsToRemove.includes(bullet),\n    );\n\n    \/\/ Update each player\n    Object.keys(this.sockets).forEach(playerID =&gt; {\n      const player = this.players[playerID];\n      const newBullet = player.update(dt);\n      if (newBullet) {\n        this.bullets.push(newBullet);\n      }\n    });\n\n    \/\/ Apply collisions, give players score for hitting bullets\n    const destroyedBullets = applyCollisions(\n      Object.values(this.players),\n      this.bullets,\n    );\n    destroyedBullets.forEach(b =&gt; {\n      if (this.players[b.parentID]) {\n        this.players[b.parentID].onDealtDamage();\n      }\n    });\n    this.bullets = this.bullets.filter(\n      bullet =&gt; !destroyedBullets.includes(bullet),\n    );\n\n    \/\/ Check if any players are dead\n    Object.keys(this.sockets).forEach(playerID =&gt; {\n      const socket = this.sockets[playerID];\n      const player = this.players[playerID];\n      if (player.hp &lt;= 0) {\n        socket.emit(Constants.MSG_TYPES.GAME_OVER);\n        this.removePlayer(socket);\n      }\n    });\n\n    \/\/ Send a game update to each player every other time\n    if (this.shouldSendUpdate) {\n      const leaderboard = this.getLeaderboard();\n      Object.keys(this.sockets).forEach(playerID =&gt; {\n        const socket = this.sockets[playerID];\n        const player = this.players[playerID];\n        socket.emit(\n          Constants.MSG_TYPES.GAME_UPDATE,\n          this.createUpdate(player, leaderboard),\n        );\n      });\n      this.shouldSendUpdate = false;\n    } else {\n      this.shouldSendUpdate = true;\n    }\n  }\n\n  \/\/ ...\n}<\/code><\/pre>\n<p>\n\u041c\u0435\u0442\u043e\u0434 <code>update()<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442, \u043d\u0430\u0432\u0435\u0440\u043d\u043e, \u0441\u0430\u043c\u0443\u044e \u0432\u0430\u0436\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0438 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u041f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0438\u043c \u0432\u0441\u0451, \u0447\u0442\u043e \u043e\u043d \u0434\u0435\u043b\u0430\u0435\u0442:<\/p>\n<ol>\n<li>\u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 <code>dt<\/code> \u043f\u0440\u043e\u0448\u043b\u043e \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e <code>update()<\/code>.<\/li>\n<li>\u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043d\u0430\u0440\u044f\u0434 \u0438 \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0430\u0435\u0442 \u0438\u0445. \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u044d\u0442\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u043f\u043e\u0437\u0436\u0435. \u041f\u043e\u043a\u0430 \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0437\u043d\u0430\u0442\u044c, \u0447\u0442\u043e <code>bullet.update()<\/code> <strong>\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>true<\/code>, \u0435\u0441\u043b\u0438 \u0441\u043d\u0430\u0440\u044f\u0434 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d<\/strong> (\u043e\u043d \u0432\u044b\u0448\u0435\u043b \u0437\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u0430\u0440\u0435\u043d\u044b).<\/li>\n<li>\u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430 \u0438 \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0441\u043d\u0430\u0440\u044f\u0434. \u042d\u0442\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043c\u044b \u0442\u043e\u0436\u0435 \u0443\u0432\u0438\u0434\u0438\u043c \u043f\u043e\u0437\u0436\u0435 \u2014 <code>player.update()<\/code> <strong>\u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 <code>Bullet<\/code><\/strong>.<\/li>\n<li>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u0441\u043d\u0430\u0440\u044f\u0434\u0430\u043c\u0438 \u0438 \u0438\u0433\u0440\u043e\u043a\u0430\u043c\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>applyCollisions()<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0441\u043d\u0430\u0440\u044f\u0434\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043f\u0430\u043b\u0438 \u0432 \u0438\u0433\u0440\u043e\u043a\u043e\u0432. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0451\u043d\u043d\u043e\u0433\u043e \u0441\u043d\u0430\u0440\u044f\u0434\u0430 \u043c\u044b \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u043e\u0447\u043a\u0438 \u0438\u0433\u0440\u043e\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0435\u0433\u043e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u043b (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>player.onDealtDamage()<\/code>), \u0430 \u0437\u0430\u0442\u0435\u043c \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0441\u043d\u0430\u0440\u044f\u0434 \u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 <code>bullets<\/code>.<\/li>\n<li>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0435\u0442 \u0438 \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0430\u0435\u0442 \u0432\u0441\u0435\u0445 \u0443\u0431\u0438\u0442\u044b\u0445 \u0438\u0433\u0440\u043e\u043a\u043e\u0432.<\/li>\n<li>\u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435\u043c \u0438\u0433\u0440\u043e\u043a\u0430\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b <strong>\u043a\u0430\u0436\u0434\u044b\u0439 \u0432\u0442\u043e\u0440\u043e\u0439<\/strong> \u0440\u0430\u0437 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 <code>update()<\/code>. \u042d\u0442\u043e \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u0430\u044f \u0432\u044b\u0448\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <code>shouldSendUpdate<\/code>. \u0422\u0430\u043a \u043a\u0430\u043a <code>update()<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f 60 \u0440\u0430\u0437\/\u0441, \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 30 \u0440\u0430\u0437\/\u0441. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, <strong>\u0447\u0430\u0441\u0442\u043e\u0442\u0430 \u0442\u0430\u043a\u0442\u043e\u0432<\/strong> \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0440\u0430\u0432\u043d\u0430 30 \u0442\u0430\u043a\u0442\u0430\u043c\/\u0441 (\u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438 \u043e \u0447\u0430\u0441\u0442\u043e\u0442\u0435 \u0442\u0430\u043a\u0442\u043e\u0432 \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438).<\/li>\n<\/ol>\n<p><\/p>\n<blockquote><p><strong>\u0417\u0430\u0447\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b \u0442\u043e\u043b\u044c\u043a\u043e <em>\u0447\u0435\u0440\u0435\u0437 \u0440\u0430\u0437<\/em> ?<\/strong> \u0414\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u043a\u0430\u043d\u0430\u043b\u0430. 30 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0438\u0433\u0440\u044b \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443 \u2013 \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e!<\/p><\/blockquote>\n<p><\/p>\n<blockquote><p><strong>\u041f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u0442\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c <code>update()<\/code> 30 \u0440\u0430\u0437 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443?<\/strong> \u0414\u043b\u044f \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u0441\u0438\u043c\u0443\u043b\u044f\u0446\u0438\u0438 \u0438\u0433\u0440\u044b. \u0427\u0435\u043c \u0447\u0430\u0449\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>update()<\/code>, \u0442\u0435\u043c \u0442\u043e\u0447\u043d\u0435\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u0438\u043c\u0443\u043b\u044f\u0446\u0438\u044f \u0438\u0433\u0440\u044b. \u041d\u043e \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0443\u0432\u043b\u0435\u043a\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0432\u044b\u0437\u043e\u0432\u043e\u0432 <code>update()<\/code>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0442\u0440\u0430\u0442\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u2014 60 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443 \u0432\u043f\u043e\u043b\u043d\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e.<\/p><\/blockquote>\n<p>\n\u041e\u0441\u0442\u0430\u0432\u0448\u0430\u044f\u0441\u044f \u0447\u0430\u0441\u0442\u044c \u043a\u043b\u0430\u0441\u0441\u0430 <code>Game<\/code> \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0432 <code>update()<\/code>:<\/p>\n<h5>game.js, \u0447\u0430\u0441\u0442\u044c 3<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">class Game {\n  \/\/ ...\n\n  getLeaderboard() {\n    return Object.values(this.players)\n      .sort((p1, p2) =&gt; p2.score - p1.score)\n      .slice(0, 5)\n      .map(p =&gt; ({ username: p.username, score: Math.round(p.score) }));\n  }\n\n  createUpdate(player, leaderboard) {\n    const nearbyPlayers = Object.values(this.players).filter(\n      p =&gt; p !== player &amp;&amp; p.distanceTo(player) &lt;= Constants.MAP_SIZE \/ 2,\n    );\n    const nearbyBullets = this.bullets.filter(\n      b =&gt; b.distanceTo(player) &lt;= Constants.MAP_SIZE \/ 2,\n    );\n\n    return {\n      t: Date.now(),\n      me: player.serializeForUpdate(),\n      others: nearbyPlayers.map(p =&gt; p.serializeForUpdate()),\n      bullets: nearbyBullets.map(b =&gt; b.serializeForUpdate()),\n      leaderboard,\n    };\n  }\n}<\/code><\/pre>\n<p>\n<code>getLeaderboard()<\/code> \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442 \u2013 \u043e\u043d \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u043f\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443 \u043e\u0447\u043a\u043e\u0432, \u0431\u0435\u0440\u0451\u0442 \u043f\u044f\u0442\u044c \u043b\u0443\u0447\u0448\u0438\u0445 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0441\u0447\u0451\u0442.<\/p>\n<p><code>createUpdate()<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 <code>update()<\/code> \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0438\u0433\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0438\u0433\u0440\u043e\u043a\u0430\u043c. \u0415\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0432\u044b\u0437\u043e\u0432\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 <code>serializeForUpdate()<\/code>, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u043e\u0432 <code>Player<\/code> \u0438 <code>Bullet<\/code>. \u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u0447\u0442\u043e \u043e\u043d \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0438\u0433\u0440\u043e\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e <strong>\u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0445<\/strong> \u0438\u0433\u0440\u043e\u043a\u0430\u0445 \u0438 \u0441\u043d\u0430\u0440\u044f\u0434\u0430\u0445 \u2013 \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u0438\u0433\u0440\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u0445, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u0434\u0430\u043b\u0435\u043a\u043e \u043e\u0442 \u0438\u0433\u0440\u043e\u043a\u0430!<\/p>\n<h2>3. \u0418\u0433\u0440\u043e\u0432\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435<\/h2>\n<p>\n\u0412 \u043d\u0430\u0448\u0435\u0439 \u0438\u0433\u0440\u0435 \u0441\u043d\u0430\u0440\u044f\u0434\u044b \u0438 \u0438\u0433\u0440\u043e\u043a\u0438 \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0438: \u044d\u0442\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0435 \u043a\u0440\u0443\u0433\u043b\u044b\u0435 \u043f\u043e\u0434\u0432\u0438\u0436\u043d\u044b\u0435 \u0438\u0433\u0440\u043e\u0432\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b. \u0427\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u044d\u0442\u043e\u0439 \u0441\u0445\u043e\u0436\u0435\u0441\u0442\u044c\u044e \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u0438 \u0441\u043d\u0430\u0440\u044f\u0434\u043e\u0432, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 <code>Object<\/code>:<\/p>\n<h5>object.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">class Object {\n  constructor(id, x, y, dir, speed) {\n    this.id = id;\n    this.x = x;\n    this.y = y;\n    this.direction = dir;\n    this.speed = speed;\n  }\n\n  update(dt) {\n    this.x += dt * this.speed * Math.sin(this.direction);\n    this.y -= dt * this.speed * Math.cos(this.direction);\n  }\n\n  distanceTo(object) {\n    const dx = this.x - object.x;\n    const dy = this.y - object.y;\n    return Math.sqrt(dx * dx + dy * dy);\n  }\n\n  setDirection(dir) {\n    this.direction = dir;\n  }\n\n  serializeForUpdate() {\n    return {\n      id: this.id,\n      x: this.x,\n      y: this.y,\n    };\n  }\n}<\/code><\/pre>\n<p>\n\u0417\u0434\u0435\u0441\u044c \u043d\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e. \u042d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0441\u0442\u0430\u043d\u0435\u0442 \u0445\u043e\u0440\u043e\u0448\u0435\u0439 \u043e\u043f\u043e\u0440\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u043e\u0439 \u0434\u043b\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043a\u043b\u0430\u0441\u0441 <code>Bullet<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <code>Object<\/code>:<\/p>\n<h5>bullet.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const shortid = require('shortid');\nconst ObjectClass = require('.\/object');\nconst Constants = require('..\/shared\/constants');\n\nclass Bullet extends ObjectClass {\n  constructor(parentID, x, y, dir) {\n    super(shortid(), x, y, dir, Constants.BULLET_SPEED);\n    this.parentID = parentID;\n  }\n\n  \/\/ Returns true if the bullet should be destroyed\n  update(dt) {\n    super.update(dt);\n    return this.x &lt; 0 || this.x &gt; Constants.MAP_SIZE || this.y &lt; 0 || this.y &gt; Constants.MAP_SIZE;\n  }\n}<\/code><\/pre>\n<p>\n\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <code>Bullet<\/code> \u043e\u0447\u0435\u043d\u044c \u043a\u043e\u0440\u043e\u0442\u043a\u0430! \u041c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043a <code>Object<\/code> \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f:<\/p>\n<ul>\n<li>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u043a\u0435\u0442\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/www.npmjs.com\/package\/shortid\">shortid<\/a><\/noindex> \u0434\u043b\u044f \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 <code>id<\/code> \u0441\u043d\u0430\u0440\u044f\u0434\u0430.<\/li>\n<li>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044f <code>parentID<\/code>, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0438\u0433\u0440\u043e\u043a\u0430, \u0441\u043e\u0437\u0434\u0430\u0432\u0448\u0435\u0433\u043e \u044d\u0442\u043e\u0442 \u0441\u043d\u0430\u0440\u044f\u0434.<\/li>\n<li>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 <code>update()<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0440\u0430\u0432\u043d\u043e <code>true<\/code>, \u0435\u0441\u043b\u0438 \u0441\u043d\u0430\u0440\u044f\u0434 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u0430\u0440\u0435\u043d\u044b (\u043f\u043e\u043c\u043d\u0438\u0442\u0435, \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438 \u043e\u0431 \u044d\u0442\u043e\u043c \u0432 \u043f\u0440\u043e\u0448\u043b\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435?).<\/li>\n<\/ul>\n<p>\n\u041f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a <code>Player<\/code>:<\/p>\n<h5>player.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const ObjectClass = require('.\/object');\nconst Bullet = require('.\/bullet');\nconst Constants = require('..\/shared\/constants');\n\nclass Player extends ObjectClass {\n  constructor(id, username, x, y) {\n    super(id, x, y, Math.random() * 2 * Math.PI, Constants.PLAYER_SPEED);\n    this.username = username;\n    this.hp = Constants.PLAYER_MAX_HP;\n    this.fireCooldown = 0;\n    this.score = 0;\n  }\n\n  \/\/ Returns a newly created bullet, or null.\n  update(dt) {\n    super.update(dt);\n\n    \/\/ Update score\n    this.score += dt * Constants.SCORE_PER_SECOND;\n\n    \/\/ Make sure the player stays in bounds\n    this.x = Math.max(0, Math.min(Constants.MAP_SIZE, this.x));\n    this.y = Math.max(0, Math.min(Constants.MAP_SIZE, this.y));\n\n    \/\/ Fire a bullet, if needed\n    this.fireCooldown -= dt;\n    if (this.fireCooldown &lt;= 0) {\n      this.fireCooldown += Constants.PLAYER_FIRE_COOLDOWN;\n      return new Bullet(this.id, this.x, this.y, this.direction);\n    }\n    return null;\n  }\n\n  takeBulletDamage() {\n    this.hp -= Constants.BULLET_DAMAGE;\n  }\n\n  onDealtDamage() {\n    this.score += Constants.SCORE_BULLET_HIT;\n  }\n\n  serializeForUpdate() {\n    return {\n      ...(super.serializeForUpdate()),\n      direction: this.direction,\n      hp: this.hp,\n    };\n  }\n}<\/code><\/pre>\n<p>\n\u0418\u0433\u0440\u043e\u043a\u0438 \u0441\u043b\u043e\u0436\u043d\u0435\u0435, \u0447\u0435\u043c \u0441\u043d\u0430\u0440\u044f\u0434\u044b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u044d\u0442\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0435\u0449\u0451 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0439. \u0415\u0433\u043e \u043c\u0435\u0442\u043e\u0434 <code>update()<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0431\u041e\u043b\u044c\u0448\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443, \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u043d\u0430\u0440\u044f\u0434, \u0435\u0441\u043b\u0438 \u043d\u0435 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c <code>fireCooldown<\/code> (\u043f\u043e\u043c\u043d\u0438\u0442\u0435, \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438 \u043e\u0431 \u044d\u0442\u043e\u043c \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435?). \u0422\u0430\u043a\u0436\u0435 \u043e\u043d \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <code>serializeForUpdate()<\/code>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u0438\u0433\u0440\u043e\u043a\u0430.<\/p>\n<p><strong>\u041d\u0430\u043b\u0438\u0447\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 <code>Object<\/code> \u2014 \u0432\u0430\u0436\u043d\u044b\u0439 \u0448\u0430\u0433, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u0434\u0430<\/strong>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0431\u0435\u0437 \u043a\u043b\u0430\u0441\u0441\u0430 <code>Object<\/code> \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <code>distanceTo()<\/code>, \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u044b \u0432\u0441\u0435\u0445 \u044d\u0442\u0438\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u0430\u0445 \u0431\u044b\u043b\u0430 \u0431\u044b \u043a\u043e\u0448\u043c\u0430\u0440\u043e\u043c. <strong>\u042d\u0442\u043e \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043e\u0441\u043e\u0431\u043e \u0432\u0430\u0436\u043d\u043e \u0434\u043b\u044f \u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432<\/strong>, \u043a\u043e\u0433\u0434\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u044e\u0449\u0438\u0445 <code>Object<\/code> \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0440\u0430\u0441\u0442\u0451\u0442.<\/p>\n<h2>4. \u0420\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u0439<\/h2>\n<p>\n\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u0447\u0442\u043e \u043d\u0430\u043c \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u2013 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0441\u043d\u0430\u0440\u044f\u0434\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432 \u0438\u0433\u0440\u043e\u043a\u043e\u0432! \u0412\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u0435 \u044d\u0442\u043e\u0442 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u043a\u043e\u0434\u0430 \u0438\u0437 \u043c\u0435\u0442\u043e\u0434\u0430 <code>update()<\/code> \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>Game<\/code>:<\/p>\n<h5>game.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const applyCollisions = require('.\/collisions');\n\nclass Game {\n  \/\/ ...\n\n  update() {\n    \/\/ ...\n\n    \/\/ Apply collisions, give players score for hitting bullets\n    const destroyedBullets = applyCollisions(\n      Object.values(this.players),\n      this.bullets,\n    );\n    destroyedBullets.forEach(b =&gt; {\n      if (this.players[b.parentID]) {\n        this.players[b.parentID].onDealtDamage();\n      }\n    });\n    this.bullets = this.bullets.filter(\n      bullet =&gt; !destroyedBullets.includes(bullet),\n    );\n\n    \/\/ ...\n  }\n}<\/code><\/pre>\n<p>\n\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>applyCollisions()<\/code>, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439 \u0432\u0441\u0435 \u0441\u043d\u0430\u0440\u044f\u0434\u044b, \u043f\u043e\u043f\u0430\u0432\u0448\u0438\u0435 \u0432 \u0438\u0433\u0440\u043e\u043a\u043e\u0432. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u0441\u043b\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e<\/p>\n<ul>\n<li>\u0412\u0441\u0435 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u0440\u0443\u0433\u0430\u043c\u0438, \u0430 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0430\u044f \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u0439 \u0444\u0438\u0433\u0443\u0440\u0430.<\/li>\n<li>\u0423 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>distanceTo()<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>Object<\/code>.<\/li>\n<\/ul>\n<p>\n\u0412\u043e\u0442 \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0430\u0448\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u0439:<\/p>\n<h5>collisions.js<\/h5>\n<p><\/p>\n<pre><code class=\"javascript\">const Constants = require('..\/shared\/constants');\n\n\/\/ Returns an array of bullets to be destroyed.\nfunction applyCollisions(players, bullets) {\n  const destroyedBullets = [];\n  for (let i = 0; i &lt; bullets.length; i++) {\n    \/\/ Look for a player (who didn't create the bullet) to collide each bullet with.\n    \/\/ As soon as we find one, break out of the loop to prevent double counting a bullet.\n    for (let j = 0; j &lt; players.length; j++) {\n      const bullet = bullets[i];\n      const player = players[j];\n      if (\n        bullet.parentID !== player.id &amp;&amp;\n        player.distanceTo(bullet) &lt;= Constants.PLAYER_RADIUS + Constants.BULLET_RADIUS\n      ) {\n        destroyedBullets.push(bullet);\n        player.takeBulletDamage();\n        break;\n      }\n    }\n  }\n  return destroyedBullets;\n}<\/code><\/pre>\n<p>\n\u042d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u0439 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043e \u043d\u0430 \u0442\u043e\u043c \u0444\u0430\u043a\u0442\u0435, \u0447\u0442\u043e <strong>\u0434\u0432\u0430 \u043a\u0440\u0443\u0433\u0430 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044e\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0438\u0445 \u0446\u0435\u043d\u0442\u0440\u0430\u043c\u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u0441\u0443\u043c\u043c\u044b \u0438\u0445 \u0440\u0430\u0434\u0438\u0443\u0441\u043e\u0432<\/strong>. \u0412\u043e\u0442 \u0441\u043b\u0443\u0447\u0430\u0439, \u043a\u043e\u0433\u0434\u0430 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0446\u0435\u043d\u0442\u0440\u0430\u043c\u0438 \u0434\u0432\u0443\u0445 \u043a\u0440\u0443\u0433\u043e\u0432 \u0442\u043e\u0447\u043d\u043e \u0440\u0430\u0432\u043d\u043e \u0441\u0443\u043c\u043c\u0435 \u0438\u0445 \u0440\u0430\u0434\u0438\u0443\u0441\u043e\u0432:<\/p>\n<p><img decoding=\"async\" alt=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io\" src=\"\/wp-content\/uploads\/2019\/05\/fc3245d0907ba91cb36f3910e18a5250.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u0417\u0434\u0435\u0441\u044c \u043d\u0443\u0436\u043d\u043e \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043d\u0435\u0441\u0442\u0438\u0441\u044c \u0435\u0449\u0451 \u043a \u043f\u0430\u0440\u0435 \u0430\u0441\u043f\u0435\u043a\u0442\u043e\u0432:<\/p>\n<ul>\n<li>\u0421\u043d\u0430\u0440\u044f\u0434 \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043f\u0430\u0434\u0430\u0442\u044c \u0432 \u0441\u043e\u0437\u0434\u0430\u0432\u0448\u0435\u0433\u043e \u0435\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430. \u042d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0441\u0442\u0438\u0447\u044c, \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u044f <code>bullet.parentID<\/code> \u0441 <code>player.id<\/code>.<\/li>\n<li>\u0421\u043d\u0430\u0440\u044f\u0434 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043f\u0430\u0434\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0438\u0433\u0440\u043e\u043a\u0430\u043c\u0438. \u042d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u043c\u044b \u0440\u0435\u0448\u0438\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <code>break<\/code>: \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0439\u0434\u0435\u043d \u0438\u0433\u0440\u043e\u043a, \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0432\u0448\u0438\u0439\u0441\u044f \u0441\u043e \u0441\u043d\u0430\u0440\u044f\u0434\u043e\u043c, \u043c\u044b \u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u043e\u0438\u0441\u043a \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u0441\u043d\u0430\u0440\u044f\u0434\u0443.<\/li>\n<\/ul>\n<p><\/p>\n<h2>\u041a\u043e\u043d\u0435\u0446<\/h2>\n<p>\n\u0412\u043e\u0442 \u0438 \u0432\u0441\u0451! \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0432\u0441\u0451, \u0447\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u043d\u0430\u0442\u044c \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0436\u0430\u043d\u0440\u0430 .io. \u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435? <strong>\u0421\u043e\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0438\u0433\u0440\u0443 .io!<\/strong><\/p>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0438\u043c\u0435\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0438 \u0432\u044b\u043b\u043e\u0436\u0435\u043d \u043d\u0430 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/vzhou842\/example-.io-game\">Github<\/a><\/noindex>.<br \/>\n<br \/>\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/450574\/\">habr.com<\/a><\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u044b\u0448\u0435\u0434\u0448\u0430\u044f \u0432 2015 \u0433\u043e\u0434\u0443 Agar.io \u0441\u0442\u0430\u043b\u0430 \u043f\u0440\u0430\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u0436\u0430\u043d\u0440\u0430 \u0438\u0433\u0440 .io, \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441 \u0442\u0435\u0445 \u043f\u043e\u0440 \u0441\u0438\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u0440\u043e\u0441\u043b\u0430. \u0420\u043e\u0441\u0442 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u0438 \u0438\u0433\u0440 .io \u044f \u0438\u0441\u043f\u044b\u0442\u0430\u043b \u043d\u0430 \u0441\u0435\u0431\u0435: \u0437\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0442\u0440\u0438 \u0433\u043e\u0434\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u0438 \u043f\u0440\u043e\u0434\u0430\u043b \u0434\u0432\u0435 \u0438\u0433\u0440\u044b \u044d\u0442\u043e\u0433\u043e \u0436\u0430\u043d\u0440\u0430.. \u041d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439, \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u0440\u0430\u043d\u044c\u0448\u0435 \u043d\u0435 \u0441\u043b\u044b\u0448\u0430\u043b\u0438 \u043e \u0442\u0430\u043a\u0438\u0445 \u0438\u0433\u0440\u0430\u0445: \u044d\u0442\u043e \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":24979,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-33243","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u044b\u0448\u0435\u0434\u0448\u0430\u044f \u0432 2015 \u0433\u043e\u0434\u0443 Agar.io \u0441\u0442\u0430\u043b\u0430 \u043f\u0440\u0430\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u0436\u0430\u043d\u0440\u0430 \u0438\u0433\u0440 .io, \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441 \u0442\u0435\u0445 \u043f\u043e\u0440 \u0441\u0438\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u0440\u043e\u0441\u043b\u0430. \u0420\u043e\u0441\u0442 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u0438 \u0438\u0433\u0440 .io \u044f \u0438\u0441\u043f\u044b\u0442\u0430\u043b \u043d\u0430 \u0441\u0435\u0431\u0435: \u0437\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0442\u0440\u0438 \u0433\u043e\u0434\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u0438 \u043f\u0440\u043e\u0434\u0430\u043b \u0434\u0432\u0435 \u0438\u0433\u0440\u044b \u044d\u0442\u043e\u0433\u043e \u0436\u0430\u043d\u0440\u0430.. \u041d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439, \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u0440\u0430\u043d\u044c\u0448\u0435 \u043d\u0435 \u0441\u043b\u044b\u0448\u0430\u043b\u0438 \u043e \u0442\u0430\u043a\u0438\u0445 \u0438\u0433\u0440\u0430\u0445: \u044d\u0442\u043e \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/sozdanie-mnogopolzovatelskoj-veb-igry-v-zhanre-io\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u044b\u0448\u0435\u0434\u0448\u0430\u044f \u0432 2015 \u0433\u043e\u0434\u0443 Agar.io \u0441\u0442\u0430\u043b\u0430 \u043f\u0440\u0430\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u0436\u0430\u043d\u0440\u0430 \u0438\u0433\u0440 .io, \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441 \u0442\u0435\u0445 \u043f\u043e\u0440 \u0441\u0438\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u0440\u043e\u0441\u043b\u0430. \u0420\u043e\u0441\u0442 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u0438 \u0438\u0433\u0440 .io \u044f \u0438\u0441\u043f\u044b\u0442\u0430\u043b \u043d\u0430 \u0441\u0435\u0431\u0435: \u0437\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0442\u0440\u0438 \u0433\u043e\u0434\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u0438 \u043f\u0440\u043e\u0434\u0430\u043b \u0434\u0432\u0435 \u0438\u0433\u0440\u044b \u044d\u0442\u043e\u0433\u043e \u0436\u0430\u043d\u0440\u0430.. \u041d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439, \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u0440\u0430\u043d\u044c\u0448\u0435 \u043d\u0435 \u0441\u043b\u044b\u0448\u0430\u043b\u0438 \u043e \u0442\u0430\u043a\u0438\u0445 \u0438\u0433\u0440\u0430\u0445: \u044d\u0442\u043e \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/sozdanie-mnogopolzovatelskoj-veb-igry-v-zhanre-io\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:51:31+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:51:31+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Erstellung von Multiplayer-Webspielen im .io-Genre | ProHoster","description":"Agar.io, das 2015 ver\u00f6ffentlicht wurde, gilt als Wegbereiter eines neuen Genres von .io-Spielen, dessen Popularit\u00e4t seitdem stark gestiegen ist. Diese Beliebtheit habe ich selbst erlebt: In den letzten drei Jahren habe ich zwei Spiele dieses Genres entwickelt und verkauft. Falls Sie noch nie von solchen Spielen geh\u00f6rt haben: Es handelt sich um kostenlose Multiplayer-Webspiele, in denen","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/sozdanie-mnogopolzovatelskoj-veb-igry-v-zhanre-io","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b \u0432 \u0436\u0430\u043d\u0440\u0435 .io | ProHoster","og:description":"\u0412\u044b\u0448\u0435\u0434\u0448\u0430\u044f \u0432 2015 \u0433\u043e\u0434\u0443 Agar.io \u0441\u0442\u0430\u043b\u0430 \u043f\u0440\u0430\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u0436\u0430\u043d\u0440\u0430 \u0438\u0433\u0440 .io, \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441 \u0442\u0435\u0445 \u043f\u043e\u0440 \u0441\u0438\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u0440\u043e\u0441\u043b\u0430. \u0420\u043e\u0441\u0442 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u0438 \u0438\u0433\u0440 .io \u044f \u0438\u0441\u043f\u044b\u0442\u0430\u043b \u043d\u0430 \u0441\u0435\u0431\u0435: \u0437\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0442\u0440\u0438 \u0433\u043e\u0434\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u0438 \u043f\u0440\u043e\u0434\u0430\u043b \u0434\u0432\u0435 \u0438\u0433\u0440\u044b \u044d\u0442\u043e\u0433\u043e \u0436\u0430\u043d\u0440\u0430.. \u041d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439, \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u0440\u0430\u043d\u044c\u0448\u0435 \u043d\u0435 \u0441\u043b\u044b\u0448\u0430\u043b\u0438 \u043e \u0442\u0430\u043a\u0438\u0445 \u0438\u0433\u0440\u0430\u0445: \u044d\u0442\u043e \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0432\u0435\u0431-\u0438\u0433\u0440\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/sozdanie-mnogopolzovatelskoj-veb-igry-v-zhanre-io","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:51:31+00:00","article:modified_time":"2019-10-31T18:51:31+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"33243","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 14:31:20","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:44:41","updated":"2026-01-21 14:31:20"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/33243","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=33243"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/33243\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/24979"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=33243"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=33243"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=33243"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}