.io เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเต

.io เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเต
2015-เตฝ เดชเตเดฑเดคเตเดคเดฟเดฑเด™เตเด™เดฟ เด…เด—เตผ.เด“เดฏเต‹ เด’เดฐเต เดชเตเดคเดฟเดฏ เดตเดฟเดญเดพเด—เดคเตเดคเดฟเดจเตเดฑเต† เด‰เดชเดœเตเดžเดพเดคเดพเดตเดพเดฏเดฟ games.io, เด…เดคเดฟเดจเตเดฑเต† เดœเดจเดชเตเดฐเต€เดคเดฟ เด…เดจเตเดจเตเดฎเตเดคเตฝ เดตเดณเดฐเต†เดฏเดงเดฟเด•เด‚ เดตเดณเตผเดจเตเดจเต. .io เด—เต†เดฏเดฟเดฎเตเด•เดณเตเดŸเต† เดœเดจเดชเตเดฐเต€เดคเดฟเดฏเตเดŸเต† เดตเตผเดฆเตเดงเดจเดตเต เดžเดพเตป เด…เดจเตเดญเดตเดฟเดšเตเดšเดฟเดŸเตเดŸเตเดฃเตเดŸเต: เด•เดดเดฟเดžเตเดž เดฎเต‚เดจเตเดจเต เดตเตผเดทเดฎเดพเดฏเดฟ, เด เดˆ เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เดฐเดฃเตเดŸเต เด—เต†เดฏเดฟเดฎเตเด•เตพ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดตเดฟเตฝเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดคเต..

เดˆ เด—เต†เดฏเดฟเดฎเตเด•เดณเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเต เดจเดฟเด™เตเด™เตพ เดฎเตเดฎเตเดชเต เด•เต‡เดŸเตเดŸเดฟเดŸเตเดŸเดฟเดฒเตเดฒเต†เด™เตเด•เดฟเตฝ, เด…เดต เดธเต—เดœเดจเตเดฏ เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเดฎเตเด•เดณเดพเดฃเต, เด…เดคเต เด•เดณเดฟเด•เตเด•เดพเตป เดŽเดณเตเดชเตเดชเดฎเดพเดฃเต (เด…เด•เตเด•เต—เดฃเตเดŸเต เด†เดตเดถเตเดฏเดฎเดฟเดฒเตเดฒ). เด…เดตเตผ เดธเดพเดงเดพเดฐเดฃเดฏเดพเดฏเดฟ เดจเดฟเดฐเดตเดงเดฟ เดŽเดคเดฟเตผ เด•เดณเดฟเด•เตเด•เดพเดฐเต† เด’เดฐเต เดตเต‡เดฆเดฟเดฏเดฟเตฝ เดฎเดคเตเดธเดฐเดฟเดชเตเดชเดฟเด•เตเด•เตเดจเตเดจเต. เดฎเดฑเตเดฑเต เดชเตเดฐเดถเดธเตเดคเดฎเดพเดฏ .io เด—เต†เดฏเดฟเดฎเตเด•เตพ: Slither.io ะธ Diep.io.

เดŽเด™เตเด™เดจเต†เดฏเต†เดจเตเดจเต เดˆ เดชเต‹เดธเตเดฑเตเดฑเดฟเตฝ เดจเดฎเตเดฎเตพ เด•เดฃเตเดŸเต†เดคเตเดคเตเด‚ เด†เดฆเตเดฏเด‚ เดฎเตเดคเตฝ เด’เดฐเต .io เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเด•. เด‡เดคเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดจเต, เดœเดพเดตเดพเดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเดฟเดจเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเตเดณเตเดณ เด…เดฑเดฟเดตเต เดฎเดพเดคเตเดฐเด‚ เดฎเดคเดฟเดฏเดพเด•เตเด‚: เดตเดพเด•เตเดฏเด˜เดŸเดจ เดชเต‹เดฒเตเดณเตเดณ เด•เดพเดฐเตเดฏเด™เตเด™เตพ เดจเดฟเด™เตเด™เตพ เดฎเดจเดธเตเดธเดฟเดฒเดพเด•เตเด•เต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต ES6, เด•เต€เดตเต‡เดกเต this ะธ เดตเดพเด—เตเดฆเดพเดจเด™เตเด™เตพ. เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดœเดพเดตเดพเดธเตเด•เตเดฐเดฟเดชเตเดฑเตเดฑเต เด•เตƒเดคเตเดฏเดฎเดพเดฏเดฟ เด…เดฑเดฟเดฏเดฟเดฒเตเดฒเต†เด™เตเด•เดฟเดฒเตเด‚, เดชเต‹เดธเตเดฑเตเดฑเดฟเดจเตเดฑเต† เดญเต‚เดฐเดฟเดญเดพเด—เดตเตเด‚ เดจเดฟเด™เตเด™เตพเด•เตเด•เต เด‡เดชเตเดชเต‹เดดเตเด‚ เดฎเดจเดธเตเดธเดฟเดฒเดพเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเด‚.

เด’เดฐเต .io เด—เต†เดฏเดฟเดฎเดฟเดจเตเดฑเต† เด‰เดฆเดพเดนเดฐเดฃเด‚

เดชเดฐเดฟเดถเต€เดฒเดจ เดธเดนเดพเดฏเดคเตเดคเดฟเดจเดพเดฏเดฟ เดžเด™เตเด™เตพ เดฑเดซเตผ เดšเต†เดฏเตเดฏเตเด‚ เด‰เดฆเดพเดนเดฐเดฃเด‚ เด—เต†เดฏเดฟเด‚ .io. เด‡เดคเต เด•เดณเดฟเด•เตเด•เดพเตป เดถเตเดฐเดฎเดฟเด•เตเด•เตเด•!

.io เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเต
เด—เต†เดฏเดฟเด‚ เดตเดณเดฐเต† เดฒเดณเดฟเดคเดฎเดพเดฃเต: เดฎเดฑเตเดฑเต เด•เดณเดฟเด•เตเด•เดพเตผเด•เตเด•เตŠเดชเตเดชเด‚ เด’เดฐเต เด…เดฑเต€เดจเดฏเดฟเตฝ เดจเดฟเด™เตเด™เตพ เด’เดฐเต เด•เดชเตเดชเตฝ เดจเดฟเดฏเดจเตเดคเตเดฐเดฟเด•เตเด•เตเดจเตเดจเต. เดจเดฟเด™เตเด™เดณเตเดŸเต† เด•เดชเตเดชเตฝ เดธเตเดตเดชเตเดฐเต‡เดฐเดฟเดคเดฎเดพเดฏเดฟ เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเด•เตพ เดตเต†เดŸเดฟเดตเดฏเตเด•เตเด•เตเด•เดฏเตเด‚ เดฎเดฑเตเดฑเต เด•เดณเดฟเด•เตเด•เดพเดฐเต† เด…เดตเดฐเตเดŸเต† เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเด•เตพ เด’เดดเดฟเดตเดพเด•เตเด•เดฟเด•เตเด•เตŠเดฃเตเดŸเต เดจเดฟเด™เตเด™เตพ เด…เดŸเดฟเด•เตเด•เดพเตป เดถเตเดฐเดฎเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต.

1. เดธเด‚เด•เตเดทเดฟเดชเตเดค เด…เดตเดฒเต‹เด•เดจเด‚/เดชเดฆเตเดงเดคเดฟ เด˜เดŸเดจ

เดžเดพเตป เดถเตเดชเดพเตผเดถเดšเต†เดฏเตเดฏเตเดจเตเดจเต เดธเต‹เดดเตเดธเต เด•เต‹เดกเต เดกเต—เตบเดฒเต‹เดกเต เดšเต†เดฏเตเดฏเตเด• เด‰เดฆเดพเดนเดฐเดฃ เด—เต†เดฏเดฟเด‚ เด…เดคเดฟเดจเดพเตฝ เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดŽเดจเตเดจเต† เดชเดฟเดจเตเดคเตเดŸเดฐเดพเดจเดพเด•เตเด‚.

เด‰เดฆเดพเดนเดฐเดฃเด‚ เด‡เดจเดฟเดชเตเดชเดฑเดฏเตเดจเตเดจเดต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต:

  • เดชเตเดฐเด•เดŸเดฟเดชเตเดชเดฟเด•เตเด•เตเด• เด—เต†เดฏเดฟเดฎเดฟเดจเตเดฑเต† เดตเต†เดฌเต เดธเต†เตผเดตเตผ เดจเดฟเดฏเดจเตเดคเตเดฐเดฟเด•เตเด•เตเดจเตเดจ Node.js-เดจเตเดณเตเดณ เดเดฑเตเดฑเดตเตเด‚ เดœเดจเดชเตเดฐเดฟเดฏ เดตเต†เดฌเต เดšเดŸเตเดŸเด•เตเด•เต‚เดŸเดพเดฃเต.
  • socket.io โ€” เดฌเตเดฐเต—เดธเดฑเดฟเดจเตเด‚ เดธเต†เตผเดตเดฑเดฟเดจเตเดฎเดฟเดŸเดฏเดฟเตฝ เดกเดพเดฑเตเดฑ เด•เตˆเดฎเดพเดฑเตเดฑเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดจเตเดณเตเดณ เดตเต†เดฌเตโ€Œเดธเต‹เด•เตเด•เดฑเตเดฑเต เดฒเตˆเดฌเตเดฐเดฑเดฟ.
  • เดตเต†เดฌเตโ€Œเดชเดพเดฏเตเด•เตเด•เต - เดฎเตŠเดกเตเดฏเต‚เตพ เดฎเดพเดจเต‡เดœเตผ. เดŽเดจเตเดคเตเด•เตŠเดฃเตเดŸเต เดตเต†เดฌเตโ€Œเดชเดพเด•เตเด•เต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เดฃเด‚ เดŽเดจเตเดจเดคเดฟเดจเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเต เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดตเดพเดฏเดฟเด•เตเด•เดพเด‚ เด‡เดตเดฟเดŸเต†.

เดชเตเดฐเต‹เดœเด•เตเดฑเตเดฑเต เดกเดฏเดฑเด•เตเดŸเดฑเดฟ เด˜เดŸเดจ เด‡เด™เตเด™เดจเต†เดฏเดพเดฃเต:

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

เดชเตŠเดคเต/

เดŽเดฒเตเดฒเดพเด‚ เดซเต‹เตพเดกเดฑเดฟเตฝ เด‰เดฃเตเดŸเต public/ เดธเต†เตผเดตเตผ เดธเตเดฅเดฟเดฐเดฎเดพเดฏเดฟ เด•เตˆเดฎเดพเดฑเตเด‚. IN public/assets/ เดžเด™เตเด™เดณเตเดŸเต† เดชเตเดฐเต‹เดœเด•เตเดฑเตเดฑเต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจ เดšเดฟเดคเตเดฐเด™เตเด™เตพ เด…เดŸเด™เตเด™เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต.

src /

เดŽเดฒเตเดฒเดพ เดธเต‹เดดเตโ€Œเดธเต เด•เต‹เดกเตเด‚ เดซเต‹เตพเดกเดฑเดฟเดฒเดพเดฃเต src/. เดถเต€เตผเดทเด•เด™เตเด™เตพ client/ ะธ server/ เดธเตเดตเดฏเด‚ เดธเด‚เดธเดพเดฐเดฟเด•เตเด•เตเด•เดฏเตเด‚ shared/ เด•เตเดฒเดฏเดจเตเดฑเตเด‚ เดธเต†เตผเดตเดฑเตเด‚ เด‡เดฑเด•เตเด•เตเดฎเดคเดฟ เดšเต†เดฏเตเดค เด’เดฐเต เด•เต‹เตบเดธเตเดฑเตเดฑเดจเตเดฑเตเดธเต เดซเดฏเตฝ เด…เดŸเด™เตเด™เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต.

2. เด…เดธเด‚เดฌเตเดฒเดฟเด•เตพ/เดชเดฆเตเดงเดคเดฟ เดชเดพเดฐเดพเดฎเต€เดฑเตเดฑเดฑเตเด•เตพ

เดฎเตเด•เดณเดฟเตฝ เดชเดฑเดžเตเดžเดคเตเดชเต‹เดฒเต†, เดชเตเดฐเต‹เดœเด•เตเดฑเตเดฑเต เดจเดฟเตผเดฎเตเดฎเดฟเด•เตเด•เดพเตป เดžเด™เตเด™เตพ เด’เดฐเต เดฎเตŠเดกเตเดฏเต‚เตพ เดฎเดพเดจเต‡เดœเตผ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต เดตเต†เดฌเตโ€Œเดชเดพเดฏเตเด•เตเด•เต. เดจเดฎเตเด•เตเด•เต เดจเดฎเตเดฎเตเดŸเต† เดตเต†เดฌเตโ€Œเดชเดพเด•เตเด•เต เด•เต‹เตบเดซเดฟเด—เดฑเต‡เดทเตป เดจเต‹เด•เตเด•เดพเด‚:

webpack.common.js:

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

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

เด‡เดตเดฟเดŸเต† เดเดฑเตเดฑเดตเตเด‚ เดชเตเดฐเดงเดพเดจเดชเตเดชเต†เดŸเตเดŸ เดตเดฐเดฟเด•เตพ เด‡เดจเดฟเดชเตเดชเดฑเดฏเตเดจเตเดจเดตเดฏเดพเดฃเต:

  • src/client/index.js Javascript (JS) เด•เตเดฒเดฏเดจเตเดฑเดฟเตปเดฑเต† เดŽเตปเดŸเตเดฐเดฟ เดชเต‹เดฏเดฟเดจเตเดฑเต เด†เดฃเต. Webpack เด‡เดตเดฟเดŸเต† เดจเดฟเดจเตเดจเต เด†เดฐเด‚เดญเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดฎเดฑเตเดฑเต เด‡เดฑเด•เตเด•เตเดฎเดคเดฟ เดšเต†เดฏเตเดค เดซเดฏเดฒเตเด•เตพเด•เตเด•เดพเดฏเดฟ เด†เดตเตผเดคเตเดคเดฟเดšเตเดšเต เดจเต‹เด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเด‚.
  • เดžเด™เตเด™เดณเตเดŸเต† เดตเต†เดฌเตโ€Œเดชเดพเด•เตเด•เต เดฌเดฟเตฝเดกเดฟเดจเตเดฑเต† เด”เดŸเตเดŸเตโ€ŒเดชเตเดŸเตเดŸเต JS เดกเดฏเดฑเด•เตเดŸเดฑเดฟเดฏเดฟเตฝ เดธเตเดฅเดฟเดคเดฟเดšเต†เดฏเตเดฏเตเด‚ dist/. เดžเดพเตป เดˆ เดซเดฏเดฒเดฟเดจเต† เดžเด™เตเด™เดณเตเดŸเต† เดŽเดจเตเดจเต เดตเดฟเดณเดฟเด•เตเด•เตเด‚ JS เดชเดพเด•เตเด•เต‡เดœเต.
  • เดžเด™เตเด™เตพ เด‰เดชเดฏเต‡เดพเด—เดฟเด•เตเด•เตเดจเตเดจเต เดฌเดพเดฌเต‡เตฝ, เดชเตเดฐเดคเตเดฏเต‡เด•เดฟเดšเตเดšเต เด•เต‹เตบเดซเดฟเด—เดฑเต‡เดทเตป @babel/preset-env เดชเดดเดฏ เดฌเตเดฐเต—เดธเดฑเตเด•เตพเด•เตเด•เดพเดฏเดฟ เดžเด™เตเด™เดณเตเดŸเต† JS เด•เต‹เดกเต เดŸเตเดฐเดพเตปเดธเตเดชเตˆเตฝ เดšเต†เดฏเตเดฏเดพเตป.
  • JS เดซเดฏเดฒเตเด•เตพ เดฑเดซเดฑเตปเดธเต เดšเต†เดฏเตเดค เดŽเดฒเตเดฒเดพ CSS-เด‰เด‚ เดŽเด•เตโ€Œเดธเตโ€ŒเดŸเตเดฐเดพเด•เตโ€Œเดฑเตเดฑเตเดšเต†เดฏเตเดฏเดพเดจเตเด‚ เด…เดตเดฏเต† เด’เดฐเดฟเดŸเดคเตเดคเต เดธเด‚เดฏเต‹เดœเดฟเดชเตเดชเดฟเด•เตเด•เดพเดจเตเด‚ เดžเด™เตเด™เตพ เด’เดฐเต เดชเตเดฒเด—เดฟเตป เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต. เดžเดพเตป เด…เดคเดฟเดจเต† เดจเดฎเตเดฎเตเดŸเต‡เดคเต เดŽเดจเตเดจเต เดตเดฟเดณเดฟเด•เตเด•เตเด‚ CSS เดชเดพเด•เตเด•เต‡เดœเต.

เดตเดฟเดšเดฟเดคเตเดฐเดฎเดพเดฏ เดชเดพเด•เตเด•เต‡เดœเต เดซเดฏเตฝ เดจเดพเดฎเด™เตเด™เตพ เดจเดฟเด™เตเด™เตพ เดถเตเดฐเดฆเตเดงเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เดพเด‚ '[name].[contenthash].ext'. เด…เดต เด…เดŸเด™เตเด™เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต เดซเดฏเดฒเดฟเดจเตเดฑเต† เดชเต‡เดฐเต เดฎเดพเดฑเตเดฑเดฟเดธเตเดฅเดพเดชเดฟเด•เตเด•เตฝ เดตเต†เดฌเตโ€Œเดชเดพเด•เตเด•เต: [name] เด‡เตปเดชเตเดŸเตเดŸเต เดชเต‹เดฏเดฟเดจเตเดฑเดฟเดจเตเดฑเต† เดชเต‡เดฐเต เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดฎเดพเดฑเตเดฑเดฟเดธเตเดฅเดพเดชเดฟเด•เตเด•เตเด‚ (เดžเด™เตเด™เดณเตเดŸเต† เด•เดพเดฐเตเดฏเดคเตเดคเดฟเตฝ เด…เดคเต game), เด’เดชเตเดชเด‚ [contenthash] เดซเดฏเตฝ เด‰เดณเตเดณเดŸเด•เตเด•เด™เตเด™เดณเตเดŸเต† เด’เดฐเต เดนเดพเดทเต เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดฎเดพเดฑเตเดฑเดฟเดธเตเดฅเดพเดชเดฟเด•เตเด•เตเด‚. เดžเด™เตเด™เตพ เด‡เดคเต เดšเต†เดฏเตเดฏเตเดจเตเดจเต เดนเดพเดทเดฟเด‚เด—เดฟเดจเดพเดฏเดฟ เดชเตเดฐเต‹เดœเด•เตเดฑเตเดฑเต เด’เดชเตเดฑเตเดฑเดฟเดฎเตˆเดธเต เดšเต†เดฏเตเดฏเตเด• - เด•เดพเดฐเดฃเด‚ เดžเด™เตเด™เดณเตเดŸเต† JS เดชเดพเด•เตเด•เต‡เดœเตเด•เตพ เด…เดจเดฟเดถเตเดšเดฟเดคเดฎเดพเดฏเดฟ เด•เดพเดทเต† เดšเต†เดฏเตเดฏเดพเตป เดฌเตเดฐเต—เดธเดฑเตเด•เดณเต‹เดŸเต เดชเดฑเดฏเดพเด‚ เด’เดฐเต เดชเดพเด•เตเด•เต‡เดœเต เดฎเดพเดฑเตเด•เดฏเดพเดฃเต†เด™เตเด•เดฟเตฝ, เด…เดคเดฟเดจเตเดฑเต† เดซเดฏเดฒเดฟเดจเตเดฑเต† เดชเต‡เดฐเตเด‚ เดฎเดพเดฑเตเดจเตเดจเต (เดฎเดพเดฑเตเดฑเด™เตเด™เตพ contenthash). เดชเต‚เตผเดคเตเดคเดฟเดฏเดพเดฏ เดซเดฒเด‚ เด•เดพเดดเตเดšเดฏเตเดŸเต† เดซเดฏเตฝ เดจเดพเดฎเดฎเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚ game.dbeee76e91a97d0c7207.js.

เดซเดฏเดฒเต webpack.common.js - เดกเต†เดตเดฒเดชเตโ€Œเดฎเต†เดจเตเดฑเต, เดชเต‚เตผเดคเตเดคเดฟเดฏเดพเดฏ เดชเตเดฐเต‹เดœเด•เตเดฑเตเดฑเต เด•เต‹เตบเดซเดฟเด—เดฑเต‡เดทเดจเตเด•เดณเดฟเดฒเต‡เด•เตเด•เต เดžเด™เตเด™เตพ เด‡เดฑเด•เตเด•เตเดฎเดคเดฟ เดšเต†เดฏเตเดฏเตเดจเตเดจ เด…เดŸเดฟเดธเตเดฅเดพเดจ เด•เต‹เตบเดซเดฟเด—เดฑเต‡เดทเตป เดซเดฏเดฒเดพเดฃเดฟเดคเต. เด‰เดฆเดพเดนเดฐเดฃเดคเตเดคเดฟเดจเต, เดตเดฟเด•เดธเดจ เด•เต‹เตบเดซเดฟเด—เดฑเต‡เดทเตป เด‡เดคเดพ:

webpack.dev.js

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

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

เด•เดพเดฐเตเดฏเด•เตเดทเดฎเดคเดฏเตเด•เตเด•เดพเดฏเดฟ, เดžเด™เตเด™เตพ เดตเดฟเด•เดธเดจ เดชเตเดฐเด•เตเดฐเดฟเดฏเดฏเดฟเตฝ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต webpack.dev.js, เดŽเดจเตเดจเดฟเดตเดฏเดฟเดฒเต‡เด•เตเด•เต เดฎเดพเดฑเตเดจเตเดจเต webpack.prod.js, เด‰เตฝเดชเตเดชเดพเดฆเดจเดคเตเดคเดฟเดฒเต‡เด•เตเด•เต เดตเดฟเดจเตเดฏเดธเดฟเด•เตเด•เตเดฎเตเดชเต‹เตพ เดชเดพเด•เตเด•เต‡เดœเต เดตเดฒเตเดชเตเดชเด™เตเด™เตพ เด’เดชเตเดฑเตเดฑเดฟเดฎเตˆเดธเต เดšเต†เดฏเตเดฏเดพเตป.

เดชเตเดฐเดพเดฆเต‡เดถเดฟเด• เดธเดœเตเดœเต€เด•เดฐเดฃเด‚

เดจเดฟเด™เตเด™เดณเตเดŸเต† เดฒเต‹เด•เตเด•เตฝ เดฎเต†เดทเต€เดจเดฟเตฝ เดชเตเดฐเต‹เดœเด•เตเดฑเตเดฑเต เด‡เตปเดธเตเดฑเตเดฑเดพเตพ เดšเต†เดฏเตเดฏเดพเตป เดžเดพเตป เดถเตเดชเดพเตผเดถ เดšเต†เดฏเตเดฏเตเดจเตเดจเต, เด…เดคเตเดตเดดเดฟ เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดˆ เดชเต‹เดธเตเดฑเตเดฑเดฟเตฝ เดฒเดฟเดธเตเดฑเตเดฑเตเดšเต†เดฏเตเดคเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจ เด˜เดŸเตเดŸเด™เตเด™เตพ เดชเดฟเดจเตเดคเตเดŸเดฐเดพเดจเดพเด•เตเด‚. เดธเดœเตเดœเต€เด•เดฐเดฃเด‚ เดฒเดณเดฟเดคเดฎเดพเดฃเต: เด†เดฆเตเดฏเด‚, เดธเดฟเดธเตเดฑเตเดฑเด‚ เด‰เดฃเตเดŸเดพเดฏเดฟเดฐเดฟเด•เตเด•เดฃเด‚ เดจเต‡เดพเดกเต ะธ NPM. เด…เดŸเตเดคเตเดคเดคเดพเดฏเดฟ เดจเดฟเด™เตเด™เตพ เดšเต†เดฏเตเดฏเต‡เดฃเตเดŸเดคเต

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

เดจเดฟเด™เตเด™เตพ เดชเต‹เด•เดพเตป เดคเดฏเตเดฏเดพเดฑเดพเดฃเต! เดตเดฟเด•เดธเดจ เดธเต†เตผเดตเตผ เด†เดฐเด‚เดญเดฟเด•เตเด•เดพเตป, เดชเตเดฐเดตเตผเดคเตเดคเดฟเดชเตเดชเดฟเด•เตเด•เตเด•

$ npm run develop

เดจเดฟเด™เตเด™เดณเตเดŸเต† เดตเต†เดฌเต เดฌเตเดฐเต—เดธเดฑเดฟเดฒเต‡เด•เตเด•เต เดชเต‹เด•เตเด• localhost: 3000. เด•เต‹เดกเต เดฎเดพเดฑเตเดฑเด™เตเด™เตพ เดธเด‚เดญเดตเดฟเด•เตเด•เตเดฎเตเดชเต‹เตพ เดกเต†เดตเดฒเดชเตโ€Œเดฎเต†เดจเตเดฑเต เดธเต†เตผเดตเตผ JS, CSS เดชเดพเด•เตเด•เต‡เดœเตเด•เตพ เดธเตเดตเดฏเดฎเต‡เดต เดชเตเดจเตผเดจเดฟเตผเดฎเตเดฎเดฟเด•เตเด•เตเด‚ - เดŽเดฒเตเดฒเดพ เดฎเดพเดฑเตเดฑเด™เตเด™เดณเตเด‚ เด•เดพเดฃเดพเตป เดชเต‡เดœเต เดชเตเดคเตเด•เตเด•เดฟเดฏเดพเตฝ เดฎเดคเดฟ!

3. เด•เตเดฒเดฏเดจเตเดฑเต เดŽเตปเดŸเตเดฐเดฟ เดชเต‹เดฏเดฟเดจเตเดฑเตเด•เตพ

เด—เต†เดฏเดฟเด‚ เด•เต‹เดกเดฟเดฒเต‡เด•เตเด•เต เดคเดจเตเดจเต† เด‡เดฑเด™เตเด™เดพเด‚. เด†เดฆเตเดฏเด‚ เดจเดฎเตเด•เตเด•เต เด’เดฐเต เดชเต‡เดœเต เดตเต‡เดฃเด‚ index.html, เดจเดฟเด™เตเด™เตพ เดธเตˆเดฑเตเดฑเต เดธเดจเตเดฆเตผเดถเดฟเด•เตเด•เตเดฎเตเดชเต‹เตพ, เดฌเตเดฐเต—เดธเตผ เด†เดฆเตเดฏเด‚ เด…เดคเต เดฒเต‹เดกเต เดšเต†เดฏเตเดฏเตเด‚. เดžเด™เตเด™เดณเตเดŸเต† เดชเต‡เดœเต เดตเดณเดฐเต† เดฒเดณเดฟเดคเดฎเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚:

Index.html

เด’เดฐเต เด‰เดฆเดพเดนเดฐเดฃเด‚ .io เด—เต†เดฏเดฟเด‚  เด•เดณเดฟเด•เตเด•เตเด•

เดˆ เด•เต‹เดกเต เด‰เดฆเดพเดนเดฐเดฃเด‚ เดตเตเดฏเด•เตเดคเดคเดฏเตเด•เตเด•เดพเดฏเดฟ เดšเต†เดฑเตเดคเดพเดฏเดฟ เดฒเดณเดฟเดคเดฎเดพเด•เตเด•เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต, เด•เต‚เดŸเดพเดคเต† เดชเต‹เดธเตเดฑเตเดฑเดฟเดฒเต† เดฎเดฑเตเดฑเต เดชเดฒ เด‰เดฆเดพเดนเดฐเดฃเด™เตเด™เดณเดฟเดฒเตเด‚ เดžเดพเตป เด‡เดคเต เดšเต†เดฏเตเดฏเตเด‚. เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดŽเดฒเตเดฒเดพเดฏเตเดชเตเดชเต‹เดดเตเด‚ เดฎเตเดดเตเดตเตป เด•เต‹เดกเตเด‚ เดจเต‹เด•เตเด•เดพเด‚ เดธเดพเดฎเต‚เดนเดฟเด•เด‚.

เดจเดฎเตเด•เตเด•เต เด‰เดฃเตเดŸเต:

  • HTML5 เด•เตเดฏเดพเตปเดตเดพเดธเต เด˜เดŸเด•เด‚ (<canvas>), เด—เต†เดฏเดฟเด‚ เดฑเต†เตปเดกเตผ เดšเต†เดฏเตเดฏเดพเตป เดžเด™เตเด™เตพ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเด‚.
  • <link> เดžเด™เตเด™เดณเตเดŸเต† CSS เดชเดพเด•เตเด•เต‡เดœเต เดšเต‡เตผเด•เตเด•เดพเตป.
  • <script> เดžเด™เตเด™เดณเตเดŸเต† Javascript เดชเดพเด•เตเด•เต‡เดœเต เดšเต‡เตผเด•เตเด•เดพเตป.
  • เด‰เดชเดฏเต‹เด•เตเดคเตƒเดจเดพเดฎเดฎเตเดณเตเดณ เดชเตเดฐเดงเดพเดจ เดฎเต†เดจเต <input> เด’เดชเตเดชเด‚ "เดชเตเดฒเต‡" เดฌเดŸเตเดŸเดฃเตเด‚ (<button>).

เดนเต‹เด‚ เดชเต‡เดœเต เดฒเต‹เดกเต เดšเต†เดฏเตโ€Œเดคเตเด•เดดเดฟเดžเตเดžเดพเตฝ, เดŽเตปเดŸเตเดฐเดฟ เดชเต‹เดฏเดฟเดจเตเดฑเต JS เดซเดฏเดฒเดฟเตฝ เดคเตเดŸเด™เตเด™เดฟ เดฌเตเดฐเต—เดธเตผ Javascript เด•เต‹เดกเต เดŽเด•เตโ€Œเดธเดฟเด•เตเดฏเต‚เดŸเตเดŸเต เดšเต†เดฏเตเดฏเดพเตป เดคเตเดŸเด™เตเด™เตเด‚: src/client/index.js.

index.js

import { connect, play } from './networking';
import { startRendering, stopRendering } from './render';
import { startCapturingInput, stopCapturingInput } from './input';
import { downloadAssets } from './assets';
import { initState } from './state';
import { setLeaderboardHidden } from './leaderboard';

import './css/main.css';

const playMenu = document.getElementById('play-menu');
const playButton = document.getElementById('play-button');
const usernameInput = document.getElementById('username-input');

Promise.all([
  connect(),
  downloadAssets(),
]).then(() => {
  playMenu.classList.remove('hidden');
  usernameInput.focus();
  playButton.onclick = () => {
    // Play!
    play(usernameInput.value);
    playMenu.classList.add('hidden');
    initState();
    startCapturingInput();
    startRendering();
    setLeaderboardHidden(false);
  };
});

เด‡เดคเต เดธเด™เตเด•เต€เตผเดฃเตเดฃเดฎเดพเดฃเต†เดจเตเดจเต เดคเต‹เดจเตเดจเตเดฎเต†เด™เตเด•เดฟเดฒเตเด‚ เดฏเดฅเดพเตผเดคเตเดฅเดคเตเดคเดฟเตฝ เด‡เดตเดฟเดŸเต† เด•เดพเดฐเตเดฏเดฎเดพเดฏเตŠเดจเตเดจเตเด‚ เดจเดŸเด•เตเด•เตเดจเตเดจเดฟเดฒเตเดฒ:

  1. เดฎเดฑเตเดฑเต เดจเดฟเดฐเดตเดงเดฟ JS เดซเดฏเดฒเตเด•เตพ เด‡เดฑเด•เตเด•เตเดฎเดคเดฟ เดšเต†เดฏเตเดฏเตเด•.
  2. CSS เด‡เดฑเด•เตเด•เตเดฎเดคเดฟ เดšเต†เดฏเตเดฏเตเด• (เด…เดคเดฟเดจเดพเตฝ เดตเต†เดฌเตโ€Œเดชเดพเด•เตเด•เดฟเดจเต เด…เดต เดžเด™เตเด™เดณเตเดŸเต† CSS เดชเดพเด•เตเด•เต‡เดœเดฟเตฝ เด‰เตพเดชเตเดชเต†เดŸเตเดคเตเดคเดพเตป เด…เดฑเดฟเดฏเดพเด‚).
  3. เดธเดฎเดพเดฐเด‚เดญเดฟเด•เตเด•เตเด• connect() เดธเต†เตผเดตเดฑเดฟเดฒเต‡เด•เตเด•เต เด’เดฐเต เด•เดฃเด•เตเดทเตป เดธเตเดฅเดพเดชเดฟเด•เตเด•เดพเดจเตเด‚ เด†เดฐเด‚เดญเดฟเด•เตเด•เดพเดจเตเด‚ downloadAssets() เด—เต†เดฏเดฟเด‚ เดฑเต†เตปเดกเตผ เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดจเต เด†เดตเดถเตเดฏเดฎเดพเดฏ เดšเดฟเดคเตเดฐเด™เตเด™เตพ เดกเต—เตบเดฒเต‹เดกเต เดšเต†เดฏเตเดฏเดพเตป.
  4. เด˜เดŸเตเดŸเด‚ 3 เดชเต‚เตผเดคเตเดคเดฟเดฏเดพเด•เตเด•เดฟเดฏ เดถเต‡เดทเด‚ เดชเตเดฐเดงเดพเดจ เดฎเต†เดจเต เดชเตเดฐเดฆเตผเดถเดฟเดชเตเดชเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต (playMenu).
  5. "เดชเตเดฒเต‡" เดฌเดŸเตเดŸเตบ เด•เตเดฒเดฟเด•เตเด•เต เดนเดพเตปเดกเตเดฒเตผ เดธเดœเตเดœเต€เด•เดฐเดฟเด•เตเด•เตเดจเตเดจเต. เดฌเดŸเตเดŸเตบ เด…เดฎเตผเดคเตเดคเตเดฎเตเดชเต‹เตพ, เด•เต‹เดกเต เด—เต†เดฏเดฟเด‚ เด†เดฐเด‚เดญเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดžเด™เตเด™เตพ เด•เดณเดฟเด•เตเด•เดพเตป เดคเดฏเตเดฏเดพเดฑเดพเดฃเต†เดจเตเดจเต เดธเต†เตผเดตเดฑเดฟเดจเต‹เดŸเต เดชเดฑเดฏเตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต.

เดžเด™เตเด™เดณเตเดŸเต† เด•เตเดฒเดฏเดจเตเดฑเต-เดธเต†เตผเดตเตผ เดฒเต‹เดœเดฟเด•เตเด•เดฟเดจเตเดฑเต† เดชเตเดฐเดงเดพเดจ "เดฎเดพเด‚เดธเด‚" เดซเดฏเตฝ เด‡เดฑเด•เตเด•เตเดฎเดคเดฟ เดšเต†เดฏเตเดค เดซเดฏเดฒเตเด•เดณเดฟเดฒเดพเดฃเต. index.js. เด‡เดชเตเดชเต‹เตพ เดžเด™เตเด™เตพ เด…เดตเดฏเต†เดฒเตเดฒเดพเด‚ เด•เตเดฐเดฎเดคเตเดคเดฟเตฝ เดจเต‹เด•เตเด•เตเด‚.

4. เด•เตเดฒเดฏเดจเตเดฑเต เดกเดพเดฑเตเดฑเดฏเตเดŸเต† เด•เตˆเดฎเดพเดฑเตเดฑเด‚

เดˆ เด—เต†เดฏเดฟเดฎเดฟเตฝ เดธเต†เตผเดตเดฑเตเดฎเดพเดฏเดฟ เด†เดถเดฏเดตเดฟเดจเดฟเดฎเดฏเด‚ เดจเดŸเดคเตเดคเดพเตป เดžเด™เตเด™เตพ เด…เดฑเดฟเดฏเดชเตเดชเต†เดŸเตเดจเตเดจ เด’เดฐเต เดฒเตˆเดฌเตเดฐเดฑเดฟ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต socket.io. Socket.io เดฌเดฟเตฝเดฑเตเดฑเต-เด‡เตป เดชเดฟเดจเตเดคเตเดฃเดฏเตเดฃเตเดŸเต เดตเต†เดฌเตโ€Œเดธเต‹เด•เตเด•เดฑเตเดฑเตเด•เตพ, เดฐเดฃเตเดŸเต เดตเดดเดฟเดฏเตเดณเตเดณ เด†เดถเดฏเดตเดฟเดจเดฟเดฎเดฏเดคเตเดคเดฟเดจเต เด…เดจเตเดฏเต‹เดœเตเดฏเดฎเดพเดฏเดต: เดžเด™เตเด™เตพเด•เตเด•เต เดธเต†เตผเดตเดฑเดฟเดฒเต‡เด•เตเด•เต เดธเดจเตเดฆเต‡เดถเด™เตเด™เตพ เด…เดฏเดฏเตเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเด‚ ะธ เดธเต†เตผเดตเดฑเดฟเดจเต เด’เดฐเต‡ เด•เดฃเด•เตเดทเดจเดฟเดฒเต‚เดŸเต† เดžเด™เตเด™เตพเด•เตเด•เต เดธเดจเตเดฆเต‡เดถเด™เตเด™เตพ เด…เดฏเดฏเตเด•เตเด•เดพเตป เด•เดดเดฟเดฏเตเด‚.

เดžเด™เตเด™เตพเด•เตเด•เต เด’เดฐเต เดซเดฏเตฝ เด‰เดฃเตเดŸเดพเด•เตเด‚ src/client/networking.jsเด†เดฐเต เดชเดฐเดฟเดชเดพเดฒเดฟเด•เตเด•เตเด‚ เดŽเดฒเตเดฒเดพเดตเดฐเตเด‚ เดธเต†เตผเดตเดฑเตเดฎเดพเดฏเตเดณเตเดณ เด†เดถเดฏเดตเดฟเดจเดฟเดฎเดฏเด™เตเด™เตพ:

networking.js

import io from 'socket.io-client';
import { processGameUpdate } from './state';

const Constants = require('../shared/constants');

const socket = io(`ws://${window.location.host}`);
const connectedPromise = new Promise(resolve => {
  socket.on('connect', () => {
    console.log('Connected to server!');
    resolve();
  });
});

export const connect = onGameOver => (
  connectedPromise.then(() => {
    // Register callbacks
    socket.on(Constants.MSG_TYPES.GAME_UPDATE, processGameUpdate);
    socket.on(Constants.MSG_TYPES.GAME_OVER, onGameOver);
  })
);

export const play = username => {
  socket.emit(Constants.MSG_TYPES.JOIN_GAME, username);
};

export const updateDirection = dir => {
  socket.emit(Constants.MSG_TYPES.INPUT, dir);
};

เดตเตเดฏเด•เตเดคเดคเดฏเตเด•เตเด•เดพเดฏเดฟ เดˆ เด•เต‹เดกเตเด‚ เดšเต†เดฑเตเดคเดพเดฏเดฟ เดšเตเดฐเตเด•เตเด•เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต.

เดˆ เดซเดฏเดฒเดฟเตฝ เดชเตเดฐเดงเดพเดจเดฎเดพเดฏเตเด‚ เดฎเต‚เดจเตเดจเต เด•เดพเดฐเตเดฏเด™เตเด™เดณเดพเดฃเต เดจเดŸเด•เตเด•เตเดจเตเดจเดคเต:

  • เดžเด™เตเด™เตพ เดธเต†เตผเดตเดฑเดฟเดฒเต‡เด•เตเด•เต เด•เดฃเด•เตเดฑเตเดฑเตเดšเต†เดฏเตเดฏเดพเตป เดถเตเดฐเดฎเดฟเด•เตเด•เตเดจเตเดจเต. connectedPromise เดžเด™เตเด™เตพ เด’เดฐเต เด•เดฃเด•เตเดทเตป เดธเตเดฅเดพเดชเดฟเด•เตเด•เตเดฎเตเดชเต‹เตพ เดฎเดพเดคเตเดฐเดฎเต‡ เด…เดจเตเดตเดฆเดฟเด•เตเด•เต‚.
  • เด•เดฃเด•เตเดทเตป เดตเดฟเดœเดฏเด•เดฐเดฎเดพเดฃเต†เด™เตเด•เดฟเตฝ, เดžเด™เตเด™เตพ เด•เต‹เตพเดฌเดพเด•เตเด•เต เดชเตเดฐเดตเตผเดคเตเดคเดจเด™เตเด™เตพ เดฐเดœเดฟเดธเตเดฑเตเดฑเตผ เดšเต†เดฏเตเดฏเตเดจเตเดจเต (processGameUpdate() ะธ onGameOver()) เดธเต†เตผเดตเดฑเดฟเตฝ เดจเดฟเดจเตเดจเต เดžเด™เตเด™เตพเด•เตเด•เต เดฒเดญเดฟเดšเตเดšเต‡เด•เตเด•เดพเดตเตเดจเตเดจ เดธเดจเตเดฆเต‡เดถเด™เตเด™เตพเด•เตเด•เต.
  • เดžเด™เตเด™เตพ เด•เดฏเดฑเตเดฑเตเดฎเดคเดฟ เดšเต†เดฏเตเดฏเตเดจเตเดจเต play() ะธ updateDirection()เด…เดคเดฟเดจเดพเตฝ เดฎเดฑเตเดฑเต เดซเดฏเดฒเตเด•เตพเด•เตเด•เต เด…เดต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เดพเดจเดพเด•เตเด‚.

5. เด•เตเดฒเดฏเดจเตเดฑเต เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต

เดšเดฟเดคเตเดฐเด‚ เดธเตเด•เตเดฐเต€เดจเดฟเตฝ เดชเตเดฐเดฆเตผเดถเดฟเดชเตเดชเดฟเด•เตเด•เดพเดจเตเดณเตเดณ เดธเดฎเดฏเดฎเดพเดฃเดฟเดคเต!

...เดŽเดจเตเดจเดพเตฝ เด‡เดคเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดจเต เดฎเตเดฎเตเดชเต, เด‡เดคเดฟเดจเต เด†เดตเดถเตเดฏเดฎเดพเดฏ เดŽเดฒเตเดฒเดพ เดšเดฟเดคเตเดฐเด™เตเด™เดณเตเด‚ (เดตเดฟเดญเดตเด™เตเด™เตพ) เดกเต—เตบเดฒเต‹เดกเต เดšเต†เดฏเตเดฏเต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต. เดจเดฎเตเด•เตเด•เต เด’เดฐเต เดฑเดฟเดธเต‹เดดเตเดธเต เดฎเดพเดจเต‡เดœเตผ เดŽเดดเตเดคเดพเด‚:

Assets.js

const ASSET_NAMES = ['ship.svg', 'bullet.svg'];

const assets = {};
const downloadPromise = Promise.all(ASSET_NAMES.map(downloadAsset));

function downloadAsset(assetName) {
  return new Promise(resolve => {
    const asset = new Image();
    asset.onload = () => {
      console.log(`Downloaded ${assetName}`);
      assets[assetName] = asset;
      resolve();
    };
    asset.src = `/assets/${assetName}`;
  });
}

export const downloadAssets = () => downloadPromise;
export const getAsset = assetName => assets[assetName];

เดฑเดฟเดธเต‹เดดเตเดธเต เดฎเดพเดจเต‡เดœเตเดฎเต†เดจเตเดฑเต เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เดพเตป เด…เดคเตเดฐ เดฌเตเดฆเตเดงเดฟเดฎเตเดŸเตเดŸเตเดณเตเดณ เด•เดพเดฐเตเดฏเดฎเดฒเตเดฒ! เด’เดฐเต เดตเดธเตเดคเตเดตเดฟเดจเต† เดธเด‚เดญเดฐเดฟเด•เตเด•เตเด• เดŽเดจเตเดจเดคเดพเดฃเต เดชเตเดฐเดงเดพเดจ เด•เดพเดฐเตเดฏเด‚ assets, เด‡เดคเต เดซเดฏเตฝเดจเดพเดฎ เด•เต€เดฏเต† เด’เดฌเตเดœเด•เตเดฑเตเดฑเต เดฎเต‚เดฒเตเดฏเดตเตเดฎเดพเดฏเดฟ เดฌเดจเตเดงเดฟเดชเตเดชเดฟเด•เตเด•เตเด‚ Image. เด‰เดฑเดตเดฟเดŸเด‚ เดฒเต‹เดกเต เดšเต†เดฏเตเดฏเตเดฎเตเดชเต‹เตพ, เดžเด™เตเด™เตพ เด…เดคเต เด’เดฐเต เด’เดฌเตเดœเด•เตเดฑเตเดฑเดฟเดฒเต‡เด•เตเด•เต เดธเด‚เดฐเด•เตเดทเดฟเด•เตเด•เตเดจเตเดจเต assets เดญเดพเดตเดฟเดฏเดฟเตฝ เดชเต†เดŸเตเดŸเต†เดจเตเดจเตเดณเตเดณ เดฐเดธเต€เดคเดฟเดจเดพเดฏเดฟ. เด“เดฐเต‹ เดตเตเดฏเด•เตเดคเดฟเด—เดค เด‰เดฑเดตเดฟเดŸเดคเตเดคเดฟเดจเตเดฑเต†เดฏเตเด‚ เดกเต—เตบเดฒเต‹เดกเต เดŽเดชเตเดชเต‹เตพ เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเด‚ (เด…เดคเดพเดฏเดคเต, เดกเต—เตบเดฒเต‹เดกเต เดšเต†เดฏเตเดฏเตเด‚ เดŽเดฒเตเดฒเดพเด‚ เดตเดฟเดญเดตเด™เตเด™เตพ), เดžเด™เตเด™เตพ เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเดจเตเดจเต downloadPromise.

เด‰เดฑเดตเดฟเดŸเด™เตเด™เตพ เดกเต—เตบเดฒเต‹เดกเต เดšเต†เดฏเตเดค เดถเต‡เดทเด‚, เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เด†เดฐเด‚เดญเดฟเด•เตเด•เดพเด‚. เดจเต‡เดฐเดคเตเดคเต† เดชเดฑเดžเตเดžเดคเตเดชเต‹เดฒเต†, เดžเด™เตเด™เตพ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจ เด’เดฐเต เดตเต†เดฌเต เดชเต‡เดœเดฟเตฝ เดตเดฐเดฏเตเด•เตเด•เดพเตป HTML5 เด•เตเดฏเดพเตปเดตเดพเดธเต (<canvas>). เดžเด™เตเด™เดณเตเดŸเต† เด—เต†เดฏเดฟเด‚ เดตเดณเดฐเต† เดฒเดณเดฟเดคเดฎเดพเดฃเต, เด…เดคเดฟเดจเดพเตฝ เดžเด™เตเด™เตพ เด‡เดจเดฟเดชเตเดชเดฑเดฏเตเดจเตเดจเดต เดฎเดพเดคเตเดฐเด‚ เดฑเต†เตปเดกเตผ เดšเต†เดฏเตเดฏเต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต:

  1. เดชเดถเตเดšเดพเดคเตเดคเดฒเด‚
  2. เด•เดณเดฟเด•เตเด•เดพเดฐเตป เด•เดชเตเดชเตฝ
  3. เด•เดณเดฟเดฏเดฟเดฒเต† เดฎเดฑเตเดฑเต เด•เดณเดฟเด•เตเด•เดพเตผ
  4. เดทเต†เดฒเตเดฒเตเด•เตพ

เดชเตเดฐเดงเดพเดจเดชเตเดชเต†เดŸเตเดŸ เดธเตโ€Œเดจเดฟเดชเตเดชเต†เดฑเตเดฑเตเด•เตพ เด‡เดคเดพ src/client/render.js, เดฎเตเด•เดณเดฟเตฝ เดฒเดฟเดธเตเดฑเตเดฑเตเดšเต†เดฏเตเดคเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจ เดจเดพเดฒเต เดชเต‹เดฏเดฟเดจเตเดฑเตเด•เตพ เด•เตƒเดคเตเดฏเดฎเดพเดฏเดฟ เดตเดฐเดฏเตเด•เตเด•เตเดจเตเดจเต:

render.js

import { getAsset } from './assets';
import { getCurrentState } from './state';

const Constants = require('../shared/constants');
const { PLAYER_RADIUS, PLAYER_MAX_HP, BULLET_RADIUS, MAP_SIZE } = Constants;

// Get the canvas graphics context
const canvas = document.getElementById('game-canvas');
const context = canvas.getContext('2d');

// Make the canvas fullscreen
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

function render() {
  const { me, others, bullets } = getCurrentState();
  if (!me) {
    return;
  }

  // Draw background
  renderBackground(me.x, me.y);

  // Draw all bullets
  bullets.forEach(renderBullet.bind(null, me));

  // Draw all players
  renderPlayer(me, me);
  others.forEach(renderPlayer.bind(null, me));
}

// ... Helper functions here excluded

let renderInterval = null;
export function startRendering() {
  renderInterval = setInterval(render, 1000 / 60);
}
export function stopRendering() {
  clearInterval(renderInterval);
}

เดตเตเดฏเด•เตเดคเดคเดฏเตเด•เตเด•เดพเดฏเดฟ เดˆ เด•เต‹เดกเตเด‚ เดšเตเดฐเตเด•เตเด•เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต.

render() เดŽเดจเตเดจเดคเดพเดฃเต เดˆ เดซเดฏเดฒเดฟเดจเตเดฑเต† เดชเตเดฐเดงเดพเดจ เดชเตเดฐเดตเตผเดคเตเดคเดจเด‚. startRendering() ะธ stopRendering() 60 FPS-เตฝ เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เดธเตˆเด•เตเด•เดฟเดณเดฟเดจเตเดฑเต† เดธเดœเต€เดตเดฎเดพเด•เตเด•เตฝ เดจเดฟเดฏเดจเตเดคเตเดฐเดฟเด•เตเด•เตเด•.

เดตเตเดฏเด•เตเดคเดฟเด—เดค เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เดธเดนเดพเดฏ เดชเตเดฐเดตเตผเดคเตเดคเดจเด™เตเด™เดณเตเดŸเต† เดชเตเดฐเดคเตเดฏเต‡เด• เดจเดฟเตผเดตเตเดตเดนเดฃเด™เตเด™เตพ (เด‰เดฆเดพเดนเดฐเดฃเดคเตเดคเดฟเดจเต renderBullet()) เด…เดคเตเดฐ เดชเตเดฐเดงเดพเดจเดฎเดฒเตเดฒ, เดŽเดจเตเดจเดพเตฝ เด’เดฐเต เดฒเดณเดฟเดคเดฎเดพเดฏ เด‰เดฆเดพเดนเดฐเดฃเด‚ เด‡เดคเดพ:

render.js

function renderBullet(me, bullet) {
  const { x, y } = bullet;
  context.drawImage(
    getAsset('bullet.svg'),
    canvas.width / 2 + x - me.x - BULLET_RADIUS,
    canvas.height / 2 + y - me.y - BULLET_RADIUS,
    BULLET_RADIUS * 2,
    BULLET_RADIUS * 2,
  );
}

เดžเด™เตเด™เตพ เดฐเต€เดคเดฟเดฏเดพเดฃเต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเดคเต เดŽเดจเตเดจเดคเต เดถเตเดฐเดฆเตเดงเดฟเด•เตเด•เตเด• getAsset(), เด‡เดคเดฟเตฝ เดฎเตเดฎเตเดชเต เด•เดฃเตเดŸเดฟเดฐเตเดจเตเดจเต asset.js!

เดฎเดฑเตเดฑเต เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เดธเดนเดพเดฏ เดชเตเดฐเดตเตผเดคเตเดคเดจเด™เตเด™เตพ เดชเดฐเตเดฏเดตเต‡เด•เตเดทเดฃเด‚ เดšเต†เดฏเตเดฏเดพเตป เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดคเดพเตฝเดชเตเดชเดฐเตเดฏเดฎเตเดฃเตเดŸเต†เด™เตเด•เดฟเตฝ, เดฌเดพเด•เตเด•เดฟเดฏเตเดณเตเดณเดต เดตเดพเดฏเดฟเด•เตเด•เตเด• src/client/render.js.

6. เด•เตเดฒเดฏเดจเตเดฑเต เด‡เตปเดชเตเดŸเตเดŸเต

เด’เดฐเต เด—เต†เดฏเดฟเด‚ เด‰เดฃเตเดŸเดพเด•เตเด•เดพเตป เดธเดฎเดฏเดฎเดพเดฏเดฟ เด•เดณเดฟเด•เตเด•เดพเดตเตเดจเตเดจ! เดจเดฟเดฏเดจเตเดคเตเดฐเดฃ เดธเตเด•เต€เด‚ เดตเดณเดฐเต† เดฒเดณเดฟเดคเดฎเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚: เดšเดฒเดจเดคเตเดคเดฟเดจเตเดฑเต† เดฆเดฟเดถ เดฎเดพเดฑเตเดฑเดพเตป, เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดฎเต—เดธเต (เด’เดฐเต เด•เดฎเตเดชเตเดฏเต‚เดŸเตเดŸเดฑเดฟเตฝ) เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เดพเด‚ เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ เดธเตเด•เตเดฐเต€เดจเดฟเตฝ เดธเตเดชเตผเดถเดฟเด•เตเด•เดพเด‚ (เด’เดฐเต เดฎเตŠเดฌเตˆเตฝ เด‰เดชเด•เดฐเดฃเดคเตเดคเดฟเตฝ). เด‡เดคเต เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เดพเตป เดžเด™เตเด™เตพ เดฐเดœเดฟเดธเตเดฑเตเดฑเตผ เดšเต†เดฏเตเดฏเตเด‚ เด‡เดตเดจเตเดฑเต เดถเตเดฐเต‹เดคเดพเด•เตเด•เตพ เดฎเต—เดธเต, เดŸเดšเตเดšเต เด‡เดตเดจเตเดฑเตเด•เตพเด•เตเด•เดพเดฏเดฟ.
เด‡เดคเตŠเด•เตเด•เต† เดถเตเดฐเดฆเตเดงเดฟเด•เตเด•เตเด‚ src/client/input.js:

input.js

import { updateDirection } from './networking';

function onMouseInput(e) {
  handleInput(e.clientX, e.clientY);
}

function onTouchInput(e) {
  const touch = e.touches[0];
  handleInput(touch.clientX, touch.clientY);
}

function handleInput(x, y) {
  const dir = Math.atan2(x - window.innerWidth / 2, window.innerHeight / 2 - y);
  updateDirection(dir);
}

export function startCapturingInput() {
  window.addEventListener('mousemove', onMouseInput);
  window.addEventListener('touchmove', onTouchInput);
}

export function stopCapturingInput() {
  window.removeEventListener('mousemove', onMouseInput);
  window.removeEventListener('touchmove', onTouchInput);
}

onMouseInput() ะธ onTouchInput() เดตเดฟเดณเดฟเด•เตเด•เตเดจเตเดจ เด‡เดตเดจเตเดฑเต เดถเตเดฐเต‹เดคเดพเด•เตเด•เดณเดพเดฃเต updateDirection() (เดจเดฟเดจเตเดจเต networking.js) เด’เดฐเต เด‡เตปเดชเตเดŸเตเดŸเต เด‡เดตเดจเตเดฑเต เดธเด‚เดญเดตเดฟเด•เตเด•เตเดฎเตเดชเต‹เตพ (เด‰เดฆเดพเดนเดฐเดฃเดคเตเดคเดฟเดจเต, เดฎเต—เดธเต เดจเต€เด•เตเด•เตเดฎเตเดชเต‹เตพ). updateDirection() เด‡เตปเดชเตเดŸเตเดŸเต เด‡เดตเดจเตเดฑเต เดชเตเดฐเต‹เดธเดธเตเดธเต เดšเต†เดฏเตเดฏเตเด•เดฏเตเด‚ เด…เดคเดฟเดจเดจเตเดธเดฐเดฟเดšเตเดšเต เด—เต†เดฏเดฟเด‚ เด…เดตเดธเตเดฅ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เดšเต†เดฏเตเดฏเตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจ เดธเต†เตผเดตเดฑเตเดฎเดพเดฏเตเดณเตเดณ เดธเดจเตเดฆเต‡เดถเด™เตเด™เดณเตเดŸเต† เด•เตˆเดฎเดพเดฑเตเดฑเด‚ เด•เตˆเด•เดพเดฐเตเดฏเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต.

7. เด•เตเดฒเดฏเดจเตเดฑเต เดจเดฟเดฒ

เดˆ เดตเดฟเดญเดพเด—เดฎเดพเดฃเต เดชเต‹เดธเตเดฑเตเดฑเดฟเดจเตเดฑเต† เด†เดฆเตเดฏ เดญเดพเด—เดคเตเดคเดฟเตฝ เดเดฑเตเดฑเดตเตเด‚ เดฌเตเดฆเตเดงเดฟเดฎเตเดŸเตเดŸเตเดณเตเดณเดคเต. เด†เดฆเตเดฏเดฎเดพเดฏเดฟ เดตเดพเดฏเดฟเด•เตเด•เตเดฎเตเดชเต‹เตพ เดคเดจเตเดจเต† เดฎเดจเดธเดฟเดฒเดพเดฏเดฟเดฒเตเดฒเต†เด™เตเด•เดฟเตฝ เดจเดฟเดฐเดพเดถเดชเตเดชเต†เดŸเดฐเตเดคเต! เดจเดฟเด™เตเด™เตพเด•เตเด•เต เด…เดคเต เด’เดดเดฟเดตเดพเด•เตเด•เดพเดจเตเด‚ เดชเดฟเดจเตเดจเต€เดŸเต เด‡เดคเดฟเดฒเต‡เด•เตเด•เต เดฎเดŸเด™เตเด™เดพเดจเตเด‚ เด•เดดเดฟเดฏเตเด‚.

เด•เตเดฒเดฏเดจเตเดฑเต-เดธเต†เตผเดตเตผ เด•เต‹เดกเต เดชเต‚เตผเดคเตเดคเดฟเดฏเดพเด•เตเด•เดพเตป เด†เดตเดถเตเดฏเดฎเดพเดฏ เดชเดธเดฟเดฒเดฟเดจเตเดฑเต† เด…เดตเดธเดพเดจ เดญเดพเด—เดฎเดพเดฃเต เดธเด‚เดธเตเดฅเดพเดจเด‚. เด•เตเดฒเดฏเดจเตเดฑเต เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เดจเดฟเดจเตเดจเตเดณเตเดณ เด•เต‹เดกเต เดธเตเดจเดฟเดชเตเดชเดฑเตเดฑเต เด“เตผเด•เตเด•เตเดจเตเดจเตเดฃเตเดŸเต‹?

render.js

import { getCurrentState } from './state';

function render() {
  const { me, others, bullets } = getCurrentState();

  // Do the rendering
  // ...
}

getCurrentState() เด•เตเดฒเดฏเดจเตเดฑเดฟเดฒเตเดณเตเดณ เดจเดฟเดฒเดตเดฟเดฒเต† เด—เต†เดฏเดฟเด‚ เดจเดฟเดฒ เดžเด™เตเด™เตพเด•เตเด•เต เดจเตฝเด•เดพเตป เด•เดดเดฟเดฏเดฃเด‚ เดเดคเต เดธเดฎเดฏเดคเตเดคเตเด‚ เดธเต†เตผเดตเดฑเดฟเตฝ เดจเดฟเดจเตเดจเต เดฒเดญเดฟเดšเตเดš เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เดณเต† เด…เดŸเดฟเดธเตเดฅเดพเดจเดฎเดพเด•เตเด•เดฟ. เดธเต†เตผเดตเตผ เด…เดฏเดšเตเดšเต‡เด•เตเด•เดพเดตเตเดจเตเดจ เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเดฟเดจเตเดฑเต† เด’เดฐเต เด‰เดฆเดพเดนเดฐเดฃเด‚ เด‡เดคเดพ:

{
  "t": 1555960373725,
  "me": {
    "x": 2213.8050880413657,
    "y": 1469.370893425012,
    "direction": 1.3082443894581433,
    "id": "AhzgAtklgo2FJvwWAADO",
    "hp": 100
  },
  "others": [],
  "bullets": [
    {
      "id": "RUJfJ8Y18n",
      "x": 2354.029197099604,
      "y": 1431.6848318262666
    },
    {
      "id": "ctg5rht5s",
      "x": 2260.546457727445,
      "y": 1456.8088728920968
    }
  ],
  "leaderboard": [
    {
      "username": "Player",
      "score": 3
    }
  ]
}

เด“เดฐเต‹ เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเดฟเดฒเตเด‚ เดธเดฎเดพเดจเดฎเดพเดฏ เด…เดžเตเดšเต เดซเต€เตฝเดกเตเด•เตพ เด…เดŸเด™เตเด™เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต:

  • t: เดˆ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เดŽเดชเตเดชเต‹เดดเดพเดฃเต เดธเตƒเดทเตโ€ŒเดŸเดฟเดšเตเดšเดคเต†เดจเตเดจเต เดธเต‚เดšเดฟเดชเตเดชเดฟเด•เตเด•เตเดจเตเดจ เดธเต†เตผเดตเตผ เดŸเตˆเด‚เดธเตเดฑเตเดฑเดพเดฎเตเดชเต.
  • me: เดˆ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เดฒเดญเดฟเด•เตเด•เตเดจเตเดจ เด•เดณเดฟเด•เตเด•เดพเดฐเดจเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเตเดณเตเดณ เดตเดฟเดตเดฐเด™เตเด™เตพ.
  • เดฎเดฑเตเดฑเตเดณเตเดณเดตเดฐเต†: เด’เดฐเต‡ เด—เต†เดฏเดฟเดฎเดฟเตฝ เดชเด™เตเด•เต†เดŸเตเด•เตเด•เตเดจเตเดจ เดฎเดฑเตเดฑเต เด•เดณเดฟเด•เตเด•เดพเดฐเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเตเดณเตเดณ เดตเดฟเดตเดฐเด™เตเด™เดณเตเดŸเต† เด’เดฐเต เดจเดฟเดฐ.
  • เดฌเตเดณเตเดณเดฑเตเดฑเตเด•เตพ: เด—เต†เดฏเดฟเดฎเดฟเดฒเต† เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเด•เดณเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเตเดณเตเดณ เดตเดฟเดตเดฐเด™เตเด™เดณเตเดŸเต† เด’เดฐเต เดจเดฟเดฐ.
  • เดฒเต€เดกเตผเดฌเต‹เตผเดกเต: เดจเดฟเดฒเดตเดฟเดฒเต† เดฒเต€เดกเตผเดฌเต‹เตผเดกเต เดกเดพเดฑเตเดฑ. เดˆ เดชเต‹เดธเตเดฑเตเดฑเดฟเตฝ เดžเด™เตเด™เตพ เด…เดต เด•เดฃเด•เตเด•เดฟเดฒเต†เดŸเตเด•เตเด•เดฟเดฒเตเดฒ.

7.1 เด‰เดชเดญเต‹เด•เตเดคเดพเดตเดฟเดจเตเดฑเต† เดจเดฟเดทเตเด•เดณเด™เตเด•เดฎเดพเดฏ เด…เดตเดธเตเดฅ

เดจเดฟเดทเตเด•เดณเด™เตเด•เดฎเดพเดฏ เดจเดŸเดชเตเดชเดพเด•เตเด•เตฝ getCurrentState() เด…เดŸเตเดคเตเดคเดฟเดŸเต† เดฒเดญเดฟเดšเตเดš เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเดฟเตฝ เดจเดฟเดจเตเดจเตเดณเตเดณ เดกเดพเดฑเตเดฑ เดฎเดพเดคเตเดฐเดฎเต‡ เดจเต‡เดฐเดฟเดŸเตเดŸเต เดจเตฝเด•เดพเดจเดพเดตเต‚.

naive-state.js

let lastGameUpdate = null;

// Handle a newly received game update.
export function processGameUpdate(update) {
  lastGameUpdate = update;
}

export function getCurrentState() {
  return lastGameUpdate;
}

เดฎเดจเต‹เดนเดฐเดตเตเด‚ เดตเตเดฏเด•เตเดคเดตเตเด‚! เดŽเดจเตเดจเดพเตฝ เด…เดคเต เดตเดณเดฐเต† เดฒเดณเดฟเดคเดฎเดพเดฏเดฟเดฐเตเดจเตเดจเต†เด™เตเด•เดฟเตฝ. เดˆ เดจเดŸเดชเตเดชเดพเด•เตเด•เตฝ เดชเตเดฐเดถเตเดจเดฎเดพเด•เดพเดจเตเดณเตเดณ เด’เดฐเต เด•เดพเดฐเดฃเด‚: เด‡เดคเต เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เดซเตเดฐเต†เดฏเดฟเด‚ เดฑเต‡เดฑเตเดฑเต เดธเต†เตผเดตเตผ เด•เตเดฒเต‹เด•เตเด•เต เดธเตเดชเต€เดกเดฟเดฒเต‡เด•เตเด•เต เดชเดฐเดฟเดฎเดฟเดคเดชเตเดชเต†เดŸเตเดคเตเดคเตเดจเตเดจเต.

เดซเตเดฐเต†เดฏเดฟเด‚ เดฑเต‡เดฑเตเดฑเต: เดซเตเดฐเต†เดฏเดฟเดฎเตเด•เดณเตเดŸเต† เดŽเดฃเตเดฃเด‚ (เด…เดคเดพเดฏเดคเต เด•เต‹เดณเตเด•เตพ render()) เดธเต†เด•เตเด•เตปเดกเดฟเตฝ, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ FPS. เด—เต†เดฏเดฟเดฎเตเด•เตพ เดธเดพเดงเดพเดฐเดฃเดฏเดพเดฏเดฟ เด•เตเดฑเดžเตเดžเดคเต 60 FPS เดŽเด™เตเด•เดฟเดฒเตเด‚ เดจเต‡เดŸเดพเตป เดถเตเดฐเดฎเดฟเด•เตเด•เตเดจเตเดจเต.

เดŸเดฟเด•เตเด•เต เดจเดฟเดฐเด•เตเด•เต: เดธเต†เตผเดตเตผ เด•เตเดฒเดฏเดจเตเดฑเตเด•เตพเด•เตเด•เต เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เตพ เด…เดฏเดฏเตโ€Œเด•เตเด•เตเดจเตเดจ เด†เดตเตƒเดคเตเดคเดฟ. เด‡เดคเต เดชเดฒเดชเตเดชเต‹เดดเตเด‚ เดซเตเดฐเต†เดฏเดฟเด‚ เดฑเต‡เดฑเตเดฑเดฟเดจเต‡เด•เตเด•เดพเตพ เด•เตเดฑเดตเดพเดฃเต. เดžเด™เตเด™เดณเตเดŸเต† เด—เต†เดฏเดฟเดฎเดฟเตฝ, เดธเต†เตผเดตเตผ เดธเต†เด•เตเด•เตปเดกเดฟเตฝ 30 เดŸเดฟเด•เตเด•เตเด•เดณเดฟเตฝ เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจเต.

เดžเด™เตเด™เตพ เดเดฑเตเดฑเดตเตเด‚ เดชเตเดคเดฟเดฏ เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เดฑเต†เตปเดกเตผ เดšเต†เดฏเตเดฏเตเด•เดฏเดพเดฃเต†เด™เตเด•เดฟเตฝ, FPS-เดจเต เด’เดฐเดฟเด•เตเด•เดฒเตเด‚ 30 เด•เดตเดฟเดฏเดพเตป เด•เดดเดฟเดฏเดฟเดฒเตเดฒ เดธเต†เตผเดตเดฑเดฟเตฝ เดจเดฟเดจเตเดจเต เดธเต†เด•เตเด•เตปเดกเดฟเตฝ 30-เตฝ เด•เต‚เดŸเตเดคเตฝ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เตพ เดžเด™เตเด™เตพเด•เตเด•เต เด’เดฐเดฟเด•เตเด•เดฒเตเด‚ เดฒเดญเดฟเด•เตเด•เดฟเดฒเตเดฒ. เดจเดฎเตเดฎเตพ เดตเดฟเดณเดฟเดšเตเดšเดพเดฒเตเด‚ render() เดธเต†เด•เตเด•เตปเดกเดฟเตฝ 60 เดคเดตเดฃ, เดˆ เด•เต‹เดณเตเด•เดณเดฟเตฝ เดชเด•เตเดคเดฟเดฏเตเด‚ เด…เดคเต‡ เด•เดพเดฐเตเดฏเด‚ เดตเต€เดฃเตเดŸเตเด‚ เดตเดฐเดฏเตเด•เตเด•เตเด‚, เด…เดŸเดฟเดธเตเดฅเดพเดจเดชเดฐเดฎเดพเดฏเดฟ เด’เดจเตเดจเตเด‚ เดšเต†เดฏเตเดฏเดฟเดฒเตเดฒ. เดจเดฟเดทเตเด•เดณเด™เตเด•เดฎเดพเดฏ เดจเดŸเดชเตเดชเดพเด•เตเด•เดฒเดฟเดจเตเดฑเต† เดฎเดฑเตเดฑเตŠเดฐเต เดชเตเดฐเดถเตโ€Œเดจเดฎเดพเดฃเต เด…เดคเต เด•เดพเดฒเดคเดพเดฎเดธเดคเตเดคเดฟเดจเต เดตเดฟเดงเต‡เดฏเดฎเดพเดฃเต. เด…เดจเตเดฏเต‹เดœเตเดฏเดฎเดพเดฏ เด‡เดจเตเดฑเตผเดจเต†เดฑเตเดฑเต เดตเต‡เด—เดคเดฏเดฟเตฝ, เด•เตเดฒเดฏเดจเตเดฑเดฟเดจเต เด“เดฐเต‹ 33 เดŽเด‚เดŽเดธเดฟเดฒเตเด‚ (เดธเต†เด•เตเด•เตปเดกเดฟเตฝ 30) เด’เดฐเต เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เดฒเดญเดฟเด•เตเด•เตเด‚:

.io เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเต
เดจเดฟเตผเดญเดพเด—เตเดฏเดตเดถเดพเตฝ, เด’เดจเตเดจเตเด‚ เดคเดฟเด•เดžเตเดžเดคเดฒเตเดฒ. เด•เต‚เดŸเตเดคเตฝ เดฑเดฟเดฏเดฒเดฟเดธเตเดฑเตเดฑเดฟเด•เต เดšเดฟเดคเตเดฐเด‚ เด‡เดคเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚:
.io เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเต
เด•เดพเดฒเดคเดพเดฎเดธเด‚ เดตเดฐเตเดฎเตเดชเต‹เตพ เดจเดฟเดทเตเด•เดณเด™เตเด•เดฎเดพเดฏ เดจเดŸเดชเตเดชเดพเด•เตเด•เตฝ เดเดฑเตเดฑเดตเตเด‚ เดฎเต‹เดถเด‚ เด…เดตเดธเตเดฅเดฏเดพเดฃเต. 50ms เด•เดพเดฒเดคเดพเดฎเดธเดคเตเดคเต‹เดŸเต† เด’เดฐเต เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เดฒเดญเดฟเด•เตเด•เตเด•เดฏเดพเดฃเต†เด™เตเด•เดฟเตฝ, เดคเตเดŸเตผเดจเตเดจเต เด•เตเดฒเดฏเดจเตเดฑเต เดฎเดจเตเดฆเด—เดคเดฟเดฏเดฟเดฒเดพเดฏเดฟ เดฎเตเดฎเตเดชเดคเตเดคเต† เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเดฟเตฝ เดจเดฟเดจเตเดจเต เด—เต†เดฏเดฟเด‚ เดจเดฟเดฒ เด‡เดชเตเดชเต‹เดดเตเด‚ เดฑเต†เตปเดกเตผ เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดจเดพเตฝ เด…เดงเดฟเด• 50ms. เด•เดณเดฟเด•เตเด•เดพเดฐเดจเต เด‡เดคเต เดŽเดคเตเดฐเดคเตเดคเต‹เดณเด‚ เด…เดธเต—เด•เดฐเตเดฏเดฎเดพเดฃเต†เดจเตเดจเต เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดŠเดนเดฟเด•เตเด•เดพเดตเตเดจเตเดจเดคเดพเดฃเต: เดเด•เดชเด•เตเดทเต€เดฏเดฎเดพเดฏ เดฎเดพเดจเตเดฆเตเดฏเด‚ เด•เดพเดฐเดฃเด‚, เด—เต†เดฏเดฟเด‚ เดžเต†เดŸเตเดŸเดฟเด•เตเด•เตเดจเตเดจเดคเตเด‚ เด…เดธเตเดฅเดฟเดฐเดตเตเดฎเดพเดฃเต†เดจเตเดจเต เดคเต‹เดจเตเดจเตเด‚.

7.2 เดฎเต†เดšเตเดšเดชเตเดชเต†เดŸเตเดŸ เด•เตเดฒเดฏเดจเตเดฑเต เดจเดฟเดฒ

เดจเดฟเดทเตเด•เดณเด™เตเด•เดฎเดพเดฏ เดจเดŸเดชเตเดชเดพเด•เตเด•เดฒเดฟเตฝ เดžเด™เตเด™เตพ เดšเดฟเดฒ เดฎเต†เดšเตเดšเดชเตเดชเต†เดŸเตเดคเตเดคเดฒเตเด•เตพ เดจเดŸเดคเตเดคเตเด‚. เด’เดจเตเดจเดพเดฎเดคเดพเดฏเดฟ, เดžเด™เตเด™เตพ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เด•เดพเดฒเดคเดพเดฎเดธเด‚ 100 เดŽเด‚.เดŽเดธเต. เด‡เดคเดฟเดจเตผเดคเตเดฅเด‚ เด•เตเดฒเดฏเดจเตเดฑเดฟเตปเดฑเต† "เดจเดฟเดฒเดตเดฟเดฒเต†" เดจเดฟเดฒ เดŽเดชเตเดชเต‹เดดเตเด‚ เดธเต†เตผเดตเดฑเดฟเดฒเต† เด—เต†เดฏเดฟเด‚ เดจเดฟเดฒเดฏเต‡เด•เตเด•เดพเตพ 100เดฎเดฟ.เดŽเดธเต เดชเดฟเดจเตเดจเดฟเดฒเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚. เด‰เดฆเดพเดนเดฐเดฃเดคเตเดคเดฟเดจเต, เดธเต†เตผเดตเตผ เดธเดฎเดฏเด‚ เด†เดฃเต†เด™เตเด•เดฟเตฝ 150, เด…เดชเตเดชเต‹เตพ เด•เตเดฒเดฏเดจเตเดฑเต เด† เดธเดฎเดฏเดคเตเดคเต เดธเต†เตผเดตเตผ เด‰เดฃเตเดŸเดพเดฏเดฟเดฐเตเดจเตเดจ เด…เดตเดธเตเดฅเดฏเต† เดฑเต†เตปเดกเตผ เดšเต†เดฏเตเดฏเตเด‚ 50:

.io เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเต
เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เดณเตเดŸเต† เดชเตเดฐเดตเดšเดจเดพเดคเต€เดคเดฎเดพเดฏ เดธเดฎเดฏเดคเตเดคเต† เด…เดคเดฟเดœเต€เดตเดฟเด•เตเด•เดพเตป เด‡เดคเต เดžเด™เตเด™เตพเด•เตเด•เต 100ms เดฌเดซเตผ เดจเตฝเด•เตเดจเตเดจเต:

.io เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเต
เด‡เดคเดฟเดจเตเดณเตเดณ เดตเดฟเดฒ เดธเตเดฅเดฟเดฐเดฎเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚ เด‡เตปเดชเตเดŸเตเดŸเต เดฒเดพเด—เต 100 เดŽเด‚.เดŽเดธเต. เดธเตเด—เดฎเดฎเดพเดฏ เด—เต†เดฏเดฟเด‚เดชเตเดฒเต‡เดฏเตโ€Œเด•เตเด•เตเดณเตเดณ เดšเต†เดฑเดฟเดฏ เดคเตเดฏเดพเด—เดฎเดพเดฃเดฟเดคเต - เดฎเดฟเด•เตเด• เด•เดณเดฟเด•เตเด•เดพเดฐเตเด‚ (เดชเตเดฐเดคเตเดฏเต‡เด•เดฟเดšเตเดšเต เดธเดพเดงเดพเดฐเดฃเด•เตเด•เดพเตผ) เดˆ เด•เดพเดฒเดคเดพเดฎเดธเด‚ เดถเตเดฐเดฆเตเดงเดฟเด•เตเด•เตเดจเตเดจเดฟเดฒเตเดฒ. เดชเตเดฐเดตเดšเดจเดพเดคเต€เดคเดฎเดพเดฏ เดฒเต‡เดฑเตเดฑเตปเดธเดฟเดฏเดฟเตฝ เด•เดณเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเต‡เด•เตเด•เดพเตพ เด†เดณเตเด•เตพเด•เตเด•เต เดธเตเดฅเดฟเดฐเดฎเดพเดฏ 100 เดฎเดฟ.เดŽเดธเต เดฒเต‡เดฑเตเดฑเตปเดธเดฟเดฏเดฟเดฒเต‡เด•เตเด•เต เด•เตเดฐเดฎเต€เด•เดฐเดฟเด•เตเด•เตเดจเตเดจเดคเต เดตเดณเดฐเต† เดŽเดณเตเดชเตเดชเดฎเดพเดฃเต.

เดŽเดจเตเดจเต เดตเดฟเดณเดฟเด•เตเด•เดชเตเดชเต†เดŸเตเดจเตเดจ เดฎเดฑเตเดฑเตŠเดฐเต เดธเดพเด™เตเด•เต‡เดคเดฟเด•เดค เดจเดฎเตเด•เตเด•เต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เดพเด‚ "เด•เตเดฒเดฏเดจเตเดฑเต-เดธเตˆเดกเต เดชเตเดฐเดตเดšเดจเด‚", เดฎเดจเดธเตเดธเดฟเดฒเดพเด•เตเด•เดฟเดฏ เด•เดพเดฒเดคเดพเดฎเดธเด‚ เด•เตเดฑเดฏเตเด•เตเด•เตเดจเตเดจเดคเดฟเดจเต เด‡เดคเต เด’เดฐเต เดจเดฒเตเดฒ เดœเต‹เดฒเดฟ เดšเต†เดฏเตเดฏเตเดจเตเดจเต, เดŽเดจเตเดจเดพเตฝ เดˆ เดชเต‹เดธเตเดฑเตเดฑเดฟเตฝ เดšเตผเดšเตเดš เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฒเตเดฒ.

เดžเด™เตเด™เตพ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจ เดฎเดฑเตเดฑเตŠเดฐเต เดฎเต†เดšเตเดšเดชเตเดชเต†เดŸเตเดคเตเดคเตฝ เดฒเต€เดจเดฟเดฏเตผ เด‡เดจเตเดฑเตผเดชเต‹เดณเต‡เดทเตป. เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เด•เดพเดฒเดคเดพเดฎเดธเด‚ เด•เดพเดฐเดฃเด‚, เดžเด™เตเด™เตพ เดธเดพเดงเดพเดฐเดฃเดฏเดพเดฏเดฟ เด•เตเดฒเดฏเดจเตเดฑเดฟเดฒเตเดณเตเดณ เดจเดฟเดฒเดตเดฟเดฒเต† เดธเดฎเดฏเดคเตเดคเต‡เด•เตเด•เดพเตพ เด’เดฐเต เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต†เด™เตเด•เดฟเดฒเตเด‚ เดฎเตเดจเตเดจเดฟเดฒเดพเดฃเต. เดตเดฟเดณเดฟเดšเตเดšเดชเตเดชเต‹เตพ getCurrentState(), เดจเดฎเตเด•เตเด•เต เดจเดฟเดฑเดตเต‡เดฑเตเดฑเดพเด‚ เดฒเต€เดจเดฟเดฏเตผ เด‡เดจเตเดฑเตผเดชเต‹เดณเต‡เดทเตป เด•เตเดฒเดฏเดจเตเดฑเดฟเดฒเตเดณเตเดณ เดจเดฟเดฒเดตเดฟเดฒเต† เดธเดฎเดฏเดคเตเดคเดฟเดจเต เดฎเตเดฎเตเดชเตเด‚ เดถเต‡เดทเดตเตเด‚ เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เตพเด•เตเด•เดฟเดŸเดฏเดฟเตฝ:

.io เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเต
เด‡เดคเต เดซเตเดฐเต†เดฏเดฟเด‚ เดฑเต‡เดฑเตเดฑเต เดชเตเดฐเดถเตเดจเด‚ เดชเดฐเดฟเดนเดฐเดฟเด•เตเด•เตเดจเตเดจเต: เด‡เดชเตเดชเต‹เตพ เดจเดฎเตเด•เตเด•เต เด†เดตเดถเตเดฏเดฎเตเดณเตเดณ เดเดคเต เดซเตเดฐเต†เดฏเดฟเด‚ เดฑเต‡เดฑเตเดฑเดฟเดฒเตเด‚ เดคเดจเดคเดพเดฏ เดซเตเดฐเต†เดฏเดฟเดฎเตเด•เตพ เดฑเต†เตปเดกเตผ เดšเต†เดฏเตเดฏเดพเด‚!

7.3 เดฎเต†เดšเตเดšเดชเตเดชเต†เดŸเตเดŸ เด’เดฐเต เด•เตเดฒเดฏเดจเตเดฑเต เด…เดตเดธเตเดฅ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตเดจเตเดจเต

เด‰เดฆเดพเดนเดฐเดฃเด‚ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตฝ src/client/state.js เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เด•เดพเดฒเดคเดพเดฎเดธเดตเตเด‚ เดฒเต€เดจเดฟเดฏเตผ เด‡เดจเตเดฑเตผเดชเต‹เดณเต‡เดทเดจเตเด‚ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต, เดชเด•เตเดทเต‡ เด‡เดคเต เด…เดงเดฟเด•เด•เดพเดฒเด‚ เดจเดฟเดฒเดจเดฟเตฝเด•เตเด•เดฟเดฒเตเดฒ. เดจเดฎเตเด•เตเด•เต เด•เต‹เดกเต เดฐเดฃเตเดŸเต เดญเดพเด—เด™เตเด™เดณเดพเดฏเดฟ เดตเดฟเดญเดœเดฟเด•เตเด•เดพเด‚. เด†เดฆเตเดฏเดคเตเดคเต‡เดคเต เด‡เดคเดพ:

state.js, เดญเดพเด—เด‚ 1

const RENDER_DELAY = 100;

const gameUpdates = [];
let gameStart = 0;
let firstServerTimestamp = 0;

export function initState() {
  gameStart = 0;
  firstServerTimestamp = 0;
}

export function processGameUpdate(update) {
  if (!firstServerTimestamp) {
    firstServerTimestamp = update.t;
    gameStart = Date.now();
  }
  gameUpdates.push(update);

  // Keep only one game update before the current server time
  const base = getBaseUpdate();
  if (base > 0) {
    gameUpdates.splice(0, base);
  }
}

function currentServerTime() {
  return firstServerTimestamp + (Date.now() - gameStart) - RENDER_DELAY;
}

// Returns the index of the base update, the first game update before
// current server time, or -1 if N/A.
function getBaseUpdate() {
  const serverTime = currentServerTime();
  for (let i = gameUpdates.length - 1; i >= 0; i--) {
    if (gameUpdates[i].t <= serverTime) {
      return i;
    }
  }
  return -1;
}

เดจเดฟเด™เตเด™เตพ เด†เดฆเตเดฏเด‚ เดšเต†เดฏเตเดฏเต‡เดฃเตเดŸเดคเต เด…เดคเต เดŽเดจเตเดคเดพเดฃเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเต†เดจเตเดจเต เด•เดฃเตเดŸเต†เดคเตเดคเตเด• เดŽเดจเตเดจเดคเดพเดฃเต currentServerTime(). เดžเด™เตเด™เตพ เดจเต‡เดฐเดคเตเดคเต† เด•เดฃเตเดŸเดคเตเดชเต‹เดฒเต†, เด“เดฐเต‹ เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเดฟเดฒเตเด‚ เด’เดฐเต เดธเต†เตผเดตเตผ เดŸเตˆเด‚เดธเตเดฑเตเดฑเดพเดฎเตเดชเต เด‰เตพเดชเตเดชเต†เดŸเตเดจเตเดจเต. เดธเต†เตผเดตเดฑเดฟเดจเต เดชเดฟเดจเตเดจเดฟเตฝ 100เดฎเดฟ.เดธเดฟ เด…เด•เดฒเต† เดšเดฟเดคเตเดฐเด‚ เดฑเต†เตปเดกเตผ เดšเต†เดฏเตเดฏเดพเตป เดฑเต†เตปเดกเตผ เดฒเต‡เดฑเตเดฑเตปเดธเดฟ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เดพเตป เดžเด™เตเด™เตพ เด†เด—เตเดฐเดนเดฟเด•เตเด•เตเดจเตเดจเต, เดชเด•เตเดทเต‡ เดธเต†เตผเดตเดฑเดฟเดฒเต† เดจเดฟเดฒเดตเดฟเดฒเต† เดธเดฎเดฏเด‚ เดžเด™เตเด™เตพ เด’เดฐเดฟเด•เตเด•เดฒเตเด‚ เด…เดฑเดฟเดฏเตเด•เดฏเดฟเดฒเตเดฒ, เด•เดพเดฐเดฃเด‚ เดเดคเต†เด™เตเด•เดฟเดฒเตเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เตพ เดžเด™เตเด™เดณเดฟเดฒเต‡เด•เตเด•เต เดŽเดคเตเดคเดพเตป เดŽเดคเตเดฐ เดธเดฎเดฏเดฎเต†เดŸเตเดคเตเดคเตเดตเต†เดจเตเดจเต เดžเด™เตเด™เตพเด•เตเด•เต เด…เดฑเดฟเดฏเดพเตป เด•เดดเดฟเดฏเดฟเดฒเตเดฒ. เด‡เดจเตเดฑเตผเดจเต†เดฑเตเดฑเต เดชเตเดฐเดตเดšเดจเดพเดคเต€เดคเดฎเดพเดฃเต, เด…เดคเดฟเดจเตเดฑเต† เดตเต‡เด—เดค เดตเดณเดฐเต†เดฏเดงเดฟเด•เด‚ เดตเตเดฏเดคเตเดฏเดพเดธเดชเตเดชเต†เดŸเดพเด‚!

เดˆ เดชเตเดฐเดถเตเดจเด‚ เดชเดฐเดฟเดนเดฐเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเต, เดจเดฎเตเด•เตเด•เต เดจเตเดฏเดพเดฏเดฎเดพเดฏ เด’เดฐเต เดเด•เดฆเต‡เดถเด‚ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เดพเด‚: เดžเด™เตเด™เตพ เด†เดฆเตเดฏเดคเตเดคเต† เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เดคเตฝเด•เตเดทเดฃเด‚ เดตเดจเตเดจเดคเดพเดฏเดฟ เดจเดŸเดฟเด•เตเด•เดพเด‚. เด‡เดคเต เดถเดฐเดฟเดฏเดพเดฃเต†เด™เตเด•เดฟเตฝ, เด† เดชเตเดฐเดคเตเดฏเต‡เด• เดจเดฟเดฎเดฟเดทเดคเตเดคเดฟเตฝ เดจเดฎเตเด•เตเด•เต เดธเต†เตผเดตเตผ เดธเดฎเดฏเด‚ เด…เดฑเดฟเดฏเดพเดฎเดพเดฏเดฟเดฐเตเดจเตเดจเต! เดžเด™เตเด™เตพ เดธเต†เตผเดตเตผ เดŸเตˆเด‚เดธเตเดฑเตเดฑเดพเดฎเตเดชเต เดธเด‚เดญเดฐเดฟเด•เตเด•เตเดจเตเดจเต firstServerTimestamp เดจเดฎเตเดฎเตเดŸเต† เดฐเด•เตเดทเดฟเด•เตเด•เตเด• เดชเตเดฐเดพเดฆเต‡เดถเดฟเด•เดฎเดพเดฏ (เด•เตเดฒเดฏเดจเตเดฑเต) เดŸเตˆเด‚เดธเตเดฑเตเดฑเดพเดฎเตเดชเต เด…เดคเต‡ เดจเดฟเดฎเดฟเดทเดคเตเดคเดฟเตฝ gameStart.

เด“, เด’เดฐเต เดจเดฟเดฎเดฟเดทเด‚. เดธเต†เตผเดตเดฑเดฟเตฝ เดธเดฎเดฏเด‚ เด‰เดฃเตเดŸเดพเด•เต‡เดฃเตเดŸเดคเดฒเตเดฒเต‡ = เด•เตเดฒเดฏเดจเตเดฑเดฟเดฒเตเดณเตเดณ เดธเดฎเดฏเด‚? เดŽเดจเตเดคเตเด•เตŠเดฃเตเดŸเดพเดฃเต เดžเด™เตเด™เตพ "เดธเต†เตผเดตเตผ เดŸเตˆเด‚เดธเตเดฑเตเดฑเดพเดฎเตเดชเต", "เด•เตเดฒเดฏเดจเตเดฑเต เดŸเตˆเด‚เดธเตเดฑเตเดฑเดพเดฎเตเดชเต" เดŽเดจเตเดจเดฟเดต เดคเดฎเตเดฎเดฟเตฝ เดตเต‡เตผเดคเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเดคเต? เด‡เดคเตŠเดฐเต เดตเดฒเดฟเดฏ เดšเต‹เดฆเตเดฏเดฎเดพเดฃเต! เด‡เดต เด’เดฐเต‡ เด•เดพเดฐเตเดฏเดฎเดฒเตเดฒเต†เดจเตเดจเต เด‡เดคเต เดฎเดพเดฑเตเดจเตเดจเต. Date.now() เด•เตเดฒเดฏเดจเตเดฑเดฟเดฒเตเด‚ เดธเต†เตผเดตเดฑเดฟเดฒเตเด‚ เดตเตเดฏเดคเตเดฏเดธเตโ€Œเดค เดŸเตˆเด‚เดธเตเดฑเตเดฑเดพเดฎเตเดชเตเด•เตพ เดคเดฟเดฐเดฟเด•เต† เดจเตฝเด•เตเด‚, เด‡เดคเต เดˆ เดฎเต†เดทเต€เดจเตเด•เดณเตเดŸเต† เดชเตเดฐเดพเดฆเต‡เดถเดฟเด• เด˜เดŸเด•เด™เตเด™เดณเต† เด†เดถเตเดฐเดฏเดฟเดšเตเดšเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต. เดŽเดฒเตเดฒเดพ เดฎเต†เดทเต€เดจเตเด•เดณเดฟเดฒเตเด‚ เดŸเตˆเด‚เดธเตเดฑเตเดฑเดพเดฎเตเดชเตเด•เตพ เด’เดฐเตเดชเต‹เดฒเต†เดฏเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเดฎเต†เดจเตเดจเต เด’เดฐเดฟเด•เตเด•เดฒเตเด‚ เด•เดฐเตเดคเดฐเตเดคเต.

เด…เดคเต เดŽเดจเตเดคเดพเดฃเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเต†เดจเตเดจเต เด‡เดชเตเดชเต‹เตพ เดžเด™เตเด™เตพ เดฎเดจเดธเตเดธเดฟเดฒเดพเด•เตเด•เตเดจเตเดจเต currentServerTime(): เด…เดคเต เดคเดฟเดฐเดฟเด•เต† เดตเดฐเตเดจเตเดจเต เดจเดฟเดฒเดตเดฟเดฒเต† เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เดธเดฎเดฏเดคเตเดคเดฟเดจเตเดฑเต† เดธเต†เตผเดตเตผ เดŸเตˆเด‚เดธเตเดฑเตเดฑเดพเดฎเตเดชเต. เดฎเดฑเตเดฑเตŠเดฐเต เดตเดฟเดงเดคเตเดคเดฟเตฝ เดชเดฑเดžเตเดžเดพเตฝ, เด‡เดคเดพเดฃเต เดจเดฟเดฒเดตเดฟเดฒเต† เดธเต†เตผเดตเตผ เดธเดฎเดฏเด‚ (firstServerTimestamp <+ (Date.now() - gameStart)เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เด•เดพเดฒเดคเดพเดฎเดธเด‚ เดฎเตˆเดจเดธเต (RENDER_DELAY).

เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เตพ เดŽเด™เตเด™เดจเต† เด•เตˆเด•เดพเดฐเตเดฏเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต เดŽเดจเตเดจเต เดจเต‹เด•เตเด•เดพเด‚. เดธเต†เตผเดตเดฑเดฟเตฝ เดจเดฟเดจเตเดจเต เด’เดฐเต เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เดฒเดญเดฟเด•เตเด•เตเดฎเตเดชเต‹เตพ, เด…เดคเดฟเดจเต† เดตเดฟเดณเดฟเด•เตเด•เตเดจเตเดจเต processGameUpdate(), เดžเด™เตเด™เตพ เดชเตเดคเดฟเดฏ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เด’เดฐเต เด…เดฑเต‡เดฏเดฟเดฒเต‡เด•เตเด•เต เดธเด‚เดฐเด•เตเดทเดฟเด•เตเด•เตเดจเตเดจเต gameUpdates. เดคเตเดŸเตผเดจเตเดจเต, เดฎเต†เดฎเตเดฎเดฑเดฟ เด‰เดชเดฏเต‹เด—เด‚ เดชเดฐเดฟเดถเต‹เดงเดฟเด•เตเด•เดพเตป, เดžเด™เตเด™เตพ เดชเดดเดฏ เด…เดชเตเดกเต‡เดฑเตเดฑเตเด•เดณเต†เดฒเตเดฒเดพเด‚ เดจเต€เด•เตเด•เด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต เด…เดŸเดฟเดธเตเดฅเดพเดจ เด…เดชเตเดกเต‡เดฑเตเดฑเตเด•เดพเดฐเดฃเด‚ เดจเดฎเตเด•เตเด•เต เด…เดตเดฐเต† เด‡เดจเดฟ เด†เดตเดถเตเดฏเดฎเดฟเดฒเตเดฒ.

เดŽเดจเตเดคเดพเดฃเต "เด•เต‹เตผ เด…เดชเตเดกเต‡เดฑเตเดฑเต"? เดˆ เดจเดฟเดฒเดตเดฟเดฒเต† เดธเต†เตผเดตเตผ เดธเดฎเดฏเดคเตเดคเดฟเตฝ เดจเดฟเดจเตเดจเต เดชเดฟเดจเตเดจเดฟเดฒเต‡เด•เตเด•เต เดจเต€เด™เตเด™เดฟเด•เตเด•เตŠเดฃเตเดŸเต เดžเด™เตเด™เตพ เด•เดฃเตเดŸเต†เดคเตเดคเตเดจเตเดจ เด†เดฆเตเดฏเดคเตเดคเต† เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต. เดˆ เดกเดฏเด—เตเดฐเด‚ เด“เตผเด•เตเด•เตเดจเตเดจเตเดฃเตเดŸเต‹?

.io เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเต
"เด•เตเดฒเดฏเดจเตเดฑเต เดฑเต†เตปเดกเตผ เดŸเตˆเด‚" เดŽเดจเตเดจเดคเดฟเดจเตเดฑเต† เด‡เดŸเดคเตเดตเดถเดคเตเดคเตเดณเตเดณ เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เด…เดŸเดฟเดธเตเดฅเดพเดจ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเดพเดฃเต.

เด…เดŸเดฟเดธเตเดฅเดพเดจ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เดŽเดจเตเดคเดฟเดจเตเดตเต‡เดฃเตเดŸเดฟเดฏเดพเดฃเต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเดคเต? เดŽเดจเตเดคเตเด•เตŠเดฃเตเดŸเดพเดฃเต เดžเด™เตเด™เตพเด•เตเด•เต เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เตพ เด…เดŸเดฟเดธเตเดฅเดพเดจเดคเตเดคเดฟเดฒเต‡เด•เตเด•เต เดกเตเดฐเต‹เดชเตเดชเต เดšเต†เดฏเตเดฏเดพเตป เด•เดดเดฟเดฏเตเด•? เด‡เดคเต เดฎเดจเดธเดฟเดฒเดพเด•เตเด•เดพเตป, เดจเดฎเตเด•เตเด•เต เด’เดŸเตเดตเดฟเตฝ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตเดจเตเดจเดคเต เดจเต‹เด•เตเด•เดพเด‚ getCurrentState():

state.js, เดญเดพเด—เด‚ 2

export function getCurrentState() {
  if (!firstServerTimestamp) {
    return {};
  }

  const base = getBaseUpdate();
  const serverTime = currentServerTime();

  // If base is the most recent update we have, use its state.
  // Else, interpolate between its state and the state of (base + 1).
  if (base < 0) {
    return gameUpdates[gameUpdates.length - 1];
  } else if (base === gameUpdates.length - 1) {
    return gameUpdates[base];
  } else {
    const baseUpdate = gameUpdates[base];
    const next = gameUpdates[base + 1];
    const r = (serverTime - baseUpdate.t) / (next.t - baseUpdate.t);
    return {
      me: interpolateObject(baseUpdate.me, next.me, r),
      others: interpolateObjectArray(baseUpdate.others, next.others, r),
      bullets: interpolateObjectArray(baseUpdate.bullets, next.bullets, r),
    };
  }
}

เดžเด™เตเด™เตพ เดฎเต‚เดจเตเดจเต เด•เต‡เดธเตเด•เตพ เด•เตˆเด•เดพเดฐเตเดฏเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต:

  1. base < 0 เดจเดฟเดฒเดตเดฟเดฒเต† เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เดธเดฎเดฏเด‚ เดตเดฐเต† เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เดณเตŠเดจเตเดจเตเด‚ เด‡เดฒเตเดฒ เดŽเดจเตเดจเดพเดฃเต เด…เตผเดคเตเดฅเดฎเดพเด•เตเด•เตเดจเตเดจเดคเต (เดฎเตเด•เดณเดฟเตฝ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตเดจเตเดจเดคเต เด•เดพเดฃเตเด• getBaseUpdate()). เดฑเต†เตปเดกเดฑเดฟเด‚เด—เต เดฒเดพเด—เต เด•เดพเดฐเดฃเด‚ เด—เต†เดฏเดฟเดฎเดฟเดจเตเดฑเต† เดคเตเดŸเด•เตเด•เดคเตเดคเดฟเตฝ เดคเดจเตเดจเต† เด‡เดคเต เดธเด‚เดญเดตเดฟเด•เตเด•เดพเด‚. เดˆ เดธเดพเดนเดšเดฐเตเดฏเดคเตเดคเดฟเตฝ, เดฒเดญเดฟเดšเตเดš เดเดฑเตเดฑเดตเตเด‚ เดชเตเดคเดฟเดฏ เด…เดชเตเดกเต‡เดฑเตเดฑเต เดžเด™เตเด™เตพ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต.
  2. base เดžเด™เตเด™เตพเด•เตเด•เต เดฒเดญเดฟเดšเตเดš เดเดฑเตเดฑเดตเตเด‚ เดชเตเดคเดฟเดฏ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเดพเดฃเต. เดจเต†เดฑเตเดฑเตโ€Œเดตเตผเด•เตเด•เต เด•เดพเดฒเดคเดพเดฎเดธเด‚ เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ เดฎเต‹เดถเด‚ เด‡เดจเตเดฑเตผเดจเต†เดฑเตเดฑเต เด•เดฃเด•เตเดทเตป เด•เดพเดฐเดฃเด‚ เด‡เดคเต เดธเด‚เดญเดตเดฟเด•เตเด•เดพเด‚. เดˆ เดธเดพเดนเดšเดฐเตเดฏเดคเตเดคเดฟเดฒเตเด‚ เดžเด™เตเด™เตพ เดเดฑเตเดฑเดตเตเด‚ เดชเตเดคเดฟเดฏ เด…เดชเตเดกเต‡เดฑเตเดฑเต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต.
  3. เดจเดฟเดฒเดตเดฟเดฒเต† เดฑเต†เตปเดกเตผ เดธเดฎเดฏเดคเตเดคเดฟเดจเต เดฎเตเดฎเตเดชเตเด‚ เดถเต‡เดทเดตเตเด‚ เดžเด™เตเด™เตพเด•เตเด•เต เด’เดฐเต เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เด‰เดฃเตเดŸเต, เด…เดคเดฟเดจเดพเตฝ เดžเด™เตเด™เตพเด•เตเด•เต เด•เดดเดฟเดฏเตเด‚ เด‡เดจเตเดฑเตผเดชเต‹เดณเต‡เดฑเตเดฑเต!

เด‰เดณเตเดณเดฟเตฝ เด…เดตเดถเต‡เดทเดฟเด•เตเด•เตเดจเตเดจเดคเต†เดฒเตเดฒเดพเด‚ state.js เดฒเดณเดฟเดคเดฎเดพเดฏ (เดŽเดจเตเดจเดพเตฝ เดตเดฟเดฐเดธเดฎเดพเดฏ) เด—เดฃเดฟเดคเดคเตเดคเดฟเดจเตเดฑเต† เดฒเต€เดจเดฟเดฏเตผ เด‡เดจเตเดฑเตผเดชเต‹เดณเต‡เดทเดจเตเดฑเต† เด’เดฐเต เดจเดฟเตผเดตเตเดตเดนเดฃเดฎเดพเดฃเต. เดจเดฟเด™เตเด™เตพเด•เตเด•เดคเต เดธเตเดตเดฏเด‚ เดชเดฐเตเดฏเดตเต‡เด•เตเดทเดฃเด‚ เดšเต†เดฏเตเดฏเดฃเดฎเต†เด™เตเด•เดฟเตฝ, เดคเตเดฑเด•เตเด•เตเด• state.js เด“เตบ เดธเดพเดฎเต‚เดนเดฟเด•เด‚.

เดญเดพเด—เด‚ 2. เดฌเดพเด•เตเด•เต†เตปเดกเต เดธเต†เตผเดตเตผ

เดˆ เดญเดพเด—เดคเตเดคเต เดจเดฎเตเดฎเดณเต† เดจเดฟเดฏเดจเตเดคเตเดฐเดฟเด•เตเด•เตเดจเตเดจ Node.js เดฌเดพเด•เตเด•เต†เตปเดกเต เดจเต‹เด•เตเด•เดพเด‚ เด’เดฐเต .io เด—เต†เดฏเดฟเดฎเดฟเดจเตเดฑเต† เด‰เดฆเดพเดนเดฐเดฃเด‚.

1. เดธเต†เตผเดตเตผ เดŽเตปเดŸเตเดฐเดฟ เดชเต‹เดฏเดฟเดจเตเดฑเต

เดตเต†เดฌเต เดธเต†เตผเดตเตผ เดฎเดพเดจเต‡เดœเตเดšเต†เดฏเตเดฏเดพเตป Node.js เดŽเดจเตเดจ เดชเต‡เดฐเดฟเตฝ เดžเด™เตเด™เตพ เด’เดฐเต เดœเดจเดชเตเดฐเดฟเดฏ เดตเต†เดฌเต เดซเตเดฐเต†เดฏเดฟเด‚เดตเตผเด•เตเด•เต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเด‚ เดชเตเดฐเด•เดŸเดฟเดชเตเดชเดฟเด•เตเด•เตเด•. เด‡เดคเต เดžเด™เตเด™เดณเตเดŸเต† เดธเต†เตผเดตเตผ เดŽเตปเดŸเตเดฐเดฟ เดชเต‹เดฏเดฟเดจเตเดฑเต เดซเดฏเตฝ เดตเดดเดฟ เด•เต‹เตบเดซเดฟเด—เตผ เดšเต†เดฏเตเดฏเดชเตเดชเต†เดŸเตเด‚ src/server/server.js:

server.js, เดญเดพเด—เด‚ 1

const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackConfig = require('../../webpack.dev.js');

// Setup an Express server
const app = express();
app.use(express.static('public'));

if (process.env.NODE_ENV === 'development') {
  // Setup Webpack for development
  const compiler = webpack(webpackConfig);
  app.use(webpackDevMiddleware(compiler));
} else {
  // Static serve the dist/ folder in production
  app.use(express.static('dist'));
}

// Listen on port
const port = process.env.PORT || 3000;
const server = app.listen(port);
console.log(`Server listening on port ${port}`);

เด†เดฆเตเดฏ เดญเดพเด—เดคเตเดคเดฟเตฝ เดจเดฎเตเดฎเตพ Webpack เดšเตผเดšเตเดš เดšเต†เดฏเตเดคเดคเต เด“เตผเด•เตเด•เตเดจเตเดจเตเดฃเตเดŸเต‹? เด‡เดตเดฟเดŸเต†เดฏเดพเดฃเต เดžเด™เตเด™เตพ เดžเด™เตเด™เดณเตเดŸเต† เดตเต†เดฌเตโ€Œเดชเดพเด•เตเด•เต เด•เต‹เตบเดซเดฟเด—เดฑเต‡เดทเดจเตเด•เตพ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเดคเต. เดžเด™เตเด™เตพ เด…เดต เดฐเดฃเตเดŸเต เดคเดฐเดคเตเดคเดฟเตฝ เดชเตเดฐเดฏเต‹เด—เดฟเด•เตเด•เตเด‚:

  • เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเด• webpack-dev-middleware เดžเด™เตเด™เดณเตเดŸเต† เดตเดฟเด•เดธเดจ เดชเดพเด•เตเด•เต‡เดœเตเด•เตพ เดธเตเดตเดฏเดฎเต‡เดต เดชเตเดจเตผเดจเดฟเตผเดฎเตเดฎเดฟเด•เตเด•เดพเตป, เด…เดฒเตเดฒเต†เด™เตเด•เดฟเตฝ
  • เด’เดฐเต เดซเต‹เตพเดกเตผ เดธเตเดฅเดฟเดฐเดฎเดพเดฏเดฟ เด•เตˆเดฎเดพเดฑเตเด• dist/, เดชเตเดฐเตŠเดกเด•เตเดทเตป เดฌเดฟเตฝเดกเดฟเดจเต เดถเต‡เดทเด‚ เดตเต†เดฌเตโ€Œเดชเดพเด•เตเด•เต เดžเด™เตเด™เดณเตเดŸเต† เดซเดฏเดฒเตเด•เตพ เดŽเดดเตเดคเตเด‚.

เดฎเดฑเตเดฑเตŠเดฐเต เดชเตเดฐเดงเดพเดจ เดฆเต—เดคเตเดฏเด‚ server.js เดธเต†เตผเดตเตผ เดธเดœเตเดœเต€เด•เดฐเดฟเด•เตเด•เตเดจเตเดจเดคเต เด‰เตพเด•เตเด•เตŠเดณเตเดณเตเดจเตเดจเต socket.ioเด‡เดคเต เดŽเด•เตเดธเตเดชเตเดฐเดธเต เดธเต†เตผเดตเดฑเดฟเดฒเต‡เด•เตเด•เต เดฒเดณเดฟเดคเดฎเดพเดฏเดฟ เดฌเดจเตเดงเดฟเดชเตเดชเดฟเด•เตเด•เตเดจเตเดจเต:

server.js, เดญเดพเด—เด‚ 2

const socketio = require('socket.io');
const Constants = require('../shared/constants');

// Setup Express
// ...
const server = app.listen(port);
console.log(`Server listening on port ${port}`);

// Setup socket.io
const io = socketio(server);

// Listen for socket.io connections
io.on('connection', socket => {
  console.log('Player connected!', socket.id);

  socket.on(Constants.MSG_TYPES.JOIN_GAME, joinGame);
  socket.on(Constants.MSG_TYPES.INPUT, handleInput);
  socket.on('disconnect', onDisconnect);
});

เดธเต†เตผเดตเดฑเตเดฎเดพเดฏเดฟ เด’เดฐเต socket.io เด•เดฃเด•เตเดทเตป เดตเดฟเดœเดฏเด•เดฐเดฎเดพเดฏเดฟ เดธเตเดฅเดพเดชเดฟเดšเตเดš เดถเต‡เดทเด‚, เดชเตเดคเดฟเดฏ เดธเต‹เด•เตเด•เดฑเตเดฑเดฟเดจเดพเดฏเดฟ เดžเด™เตเด™เตพ เด‡เดตเดจเตเดฑเต เดนเดพเตปเดกเตโ€Œเดฒเดฑเตเด•เตพ เด•เต‹เตบเดซเดฟเด—เตผ เดšเต†เดฏเตเดฏเตเดจเตเดจเต. เด‡เดตเดจเตเดฑเต เดนเดพเตปเดกเตโ€Œเดฒเตผเดฎเดพเตผ เด’เดฐเต เดธเดฟเด‚เด—เดฟเตพเดŸเตบ เด’เดฌเตโ€Œเดœเด•เตโ€Œเดฑเตเดฑเดฟเดฒเต‡เด•เตเด•เต เดกเต†เดฒเดฟเด—เต‡เดฑเตเดฑเต เดšเต†เดฏเตโ€Œเดคเต เด•เตเดฒเดฏเดจเตเดฑเตเด•เดณเดฟเตฝ เดจเดฟเดจเตเดจเต เดฒเดญเดฟเด•เตเด•เตเดจเตเดจ เดธเดจเตเดฆเต‡เดถเด™เตเด™เตพ เดชเตเดฐเต‹เดธเดธเตเดธเต เดšเต†เดฏเตเดฏเตเดจเตเดจเต game:

server.js, เดญเดพเด—เด‚ 3

const Game = require('./game');

// ...

// Setup the Game
const game = new Game();

function joinGame(username) {
  game.addPlayer(this, username);
}

function handleInput(dir) {
  game.handleInput(this, dir);
}

function onDisconnect() {
  game.removePlayer(this);
}

เดžเด™เตเด™เตพ เด’เดฐเต .io เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเด•เดฏเดพเดฃเต, เด…เดคเดฟเดจเดพเตฝ เดžเด™เตเด™เตพเด•เตเด•เต เด’เดฐเต เดชเด•เตผเดชเตเดชเต เดฎเดพเดคเตเดฐเดฎเต‡ เด†เดตเดถเตเดฏเดฎเตเดณเตเดณเต‚ Game ("เด—เต†เดฏเดฟเด‚") - เดŽเดฒเตเดฒเดพ เด•เดณเดฟเด•เตเด•เดพเดฐเตเด‚ เด’เดฐเต‡ เดตเต‡เดฆเดฟเดฏเดฟเตฝ เด•เดณเดฟเด•เตเด•เตเดจเตเดจเต! เดˆ เด•เตเดฒเดพเดธเต เดŽเด™เตเด™เดจเต† เดชเตเดฐเดตเตผเดคเตเดคเดฟเด•เตเด•เตเดจเตเดจเตเดตเต†เดจเตเดจเต เด…เดŸเตเดคเตเดค เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เดจเดฎเตเด•เตเด•เต เดจเต‹เด•เตเด•เดพเด‚ Game.

2. เด—เต†เดฏเดฟเด‚ เดธเต†เตผเดตเดฑเตเด•เตพ

เด•เตเดฒเดพเดธเต Game เดเดฑเตเดฑเดตเตเด‚ เดชเตเดฐเดงเดพเดจเดชเตเดชเต†เดŸเตเดŸ เดธเต†เตผเดตเตผ เดธเตˆเดกเต เดฒเต‹เดœเดฟเด•เต เด…เดŸเด™เตเด™เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต. เด‡เดคเดฟเดจเต เดฐเดฃเตเดŸเต เดชเตเดฐเดงเดพเดจ เดœเต‹เดฒเดฟเด•เดณเตเดฃเตเดŸเต: เดชเตเดฒเต†เดฏเตผ เดฎเดพเดจเต‡เดœเตเดฎเต†เดจเตเดฑเต ะธ เด—เต†เดฏเดฟเด‚ เดธเดฟเดฎเตเดฒเต‡เดทเตป.

เด†เดฆเตเดฏ เดŸเดพเดธเตเด•เตเด•เดฟเตฝ เดจเดฟเดจเตเดจเต เด†เดฐเด‚เดญเดฟเด•เตเด•เดพเด‚ - เด•เดณเดฟเด•เตเด•เดพเดฐเต† เดจเดฟเดฏเดจเตเดคเตเดฐเดฟเด•เตเด•เตเด•.

game.js, เดญเดพเด—เด‚ 1

const Constants = require('../shared/constants');
const Player = require('./player');

class Game {
  constructor() {
    this.sockets = {};
    this.players = {};
    this.bullets = [];
    this.lastUpdateTime = Date.now();
    this.shouldSendUpdate = false;
    setInterval(this.update.bind(this), 1000 / 60);
  }

  addPlayer(socket, username) {
    this.sockets[socket.id] = socket;

    // Generate a position to start this player at.
    const x = Constants.MAP_SIZE * (0.25 + Math.random() * 0.5);
    const y = Constants.MAP_SIZE * (0.25 + Math.random() * 0.5);
    this.players[socket.id] = new Player(socket.id, username, x, y);
  }

  removePlayer(socket) {
    delete this.sockets[socket.id];
    delete this.players[socket.id];
  }

  handleInput(socket, dir) {
    if (this.players[socket.id]) {
      this.players[socket.id].setDirection(dir);
    }
  }

  // ...
}

เดˆ เด—เต†เดฏเดฟเดฎเดฟเตฝ เดžเด™เตเด™เตพ เด•เดณเดฟเด•เตเด•เดพเดฐเต† เดซเต€เตฝเดกเต เด…เดจเตเดธเดฐเดฟเดšเตเดšเต เดคเดฟเดฐเดฟเดšเตเดšเดฑเดฟเดฏเตเด‚ id เด…เดตเดฐเตเดŸเต† เดธเต‹เด•เตเด•เดฑเตเดฑเต socket.io (เดจเดฟเด™เตเด™เตพ เด†เดถเดฏเด•เตเด•เตเดดเดชเตเดชเดคเตเดคเดฟเดฒเดพเดฃเต†เด™เตเด•เดฟเตฝ, เดคเดฟเดฐเดฟเด•เต† เดชเต‹เด•เตเด• server.js). Socket.io เดคเดจเตเดจเต† เด“เดฐเต‹ เดธเต‹เด•เตเด•เดฑเตเดฑเดฟเดจเตเด‚ เด’เดฐเต เดคเดจเดคเต เดจเตฝเด•เตเดจเตเดจเต id, เด…เดคเดฟเดจเดพเตฝ เดจเดฎเตเดฎเตพ เด…เดคเดฟเดจเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเต เดตเดฟเดทเดฎเดฟเด•เตเด•เต‡เดฃเตเดŸเดคเดฟเดฒเตเดฒ. เดžเดพเตป เด…เดตเดจเต† เดตเดฟเดณเดฟเด•เตเด•เดพเด‚ เดชเตเดฒเต†เดฏเตผ เดเดกเดฟ.

เด…เดคเต เดฎเดจเดธเตเดธเดฟเตฝ เดตเต†เดšเตเดšเตเด•เตŠเดฃเตเดŸเต, เด•เตเดฒเดพเดธเตเดธเดฟเดฒเต† เด‡เตปเดธเตเดฑเตเดฑเตปเดธเต เดตเต‡เดฐเดฟเดฏเดฌเดฟเดณเตเด•เตพ เดชเดฐเดฟเดถเต‹เดงเดฟเด•เตเด•เดพเด‚ Game:

  • sockets เดชเตเดฒเต†เดฏเดฑเตเดฎเดพเดฏเดฟ เดฌเดจเตเดงเดชเตเดชเต†เดŸเตเดŸ เดธเต‹เด•เตเด•เดฑเตเดฑเดฟเดฒเต‡เด•เตเด•เต เดชเตเดฒเต†เดฏเตผ เดเดกเดฟเดฏเต† เดฌเดจเตเดงเดฟเดชเตเดชเดฟเด•เตเด•เตเดจเตเดจ เด’เดฐเต เดตเดธเตเดคเตเดตเดพเดฃเต. เด•เดพเดฒเด•เตเดฐเดฎเต‡เดฃ เด…เดตเดฐเตเดŸเต† เดชเตเดฒเต‡เดฏเตผ เดเดกเดฟเด•เตพ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดธเต‹เด•เตเด•เดฑเตเดฑเตเด•เตพ เด†เด•เตโ€Œเดธเดธเต เดšเต†เดฏเตเดฏเดพเตป เด‡เดคเต เดžเด™เตเด™เดณเต† เด…เดจเตเดตเดฆเดฟเด•เตเด•เตเดจเตเดจเต.
  • players เดชเตเดฒเต†เดฏเตผ เดเดกเดฟเดฏเต† เด•เต‹เดกเต> เดชเตเดฒเต†เดฏเตผ เด’เดฌเตโ€Œเดœเด•เตโ€Œเดฑเตเดฑเตเดฎเดพเดฏเดฟ เดฌเดจเตเดงเดฟเดชเตเดชเดฟเด•เตเด•เตเดจเตเดจ เด’เดฐเต เด’เดฌเตโ€Œเดœเด•เตเดฑเตเดฑเต เด†เดฃเต

bullets เดตเดธเตเดคเตเด•เตเด•เดณเตเดŸเต† เด’เดฐเต เดจเดฟเดฐเดฏเดพเดฃเต Bullet, เด’เดฐเต เดชเตเดฐเดคเตเดฏเต‡เด• เด•เตเดฐเดฎเด‚ เด‡เดฒเตเดฒ.
lastUpdateTime - เด‡เดคเดพเดฃเต เด…เดตเดธเดพเดจ เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเดฟเดจเตเดฑเต† เดŸเตˆเด‚เดธเตเดฑเตเดฑเดพเดฎเตเดชเต. เด‡เดคเต เดŽเด™เตเด™เดจเต† เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดฎเต†เดจเตเดจเต เดจเดฎเตเด•เตเด•เต เด‰เดŸเตป เด•เดพเดฃเดพเด‚.
shouldSendUpdate เด’เดฐเต เด“เด•เตเดธเดฟเดฒเดฑเดฟ เดตเต‡เดฐเดฟเดฏเดฌเดฟเตพ เด†เดฃเต. เด…เดคเดฟเดจเตเดฑเต† เด‰เดชเดฏเต‹เด—เดตเตเด‚ เด‰เดŸเตป เด•เดพเดฃเดพเด‚.
เดฐเต€เดคเดฟเด•เตพ addPlayer(), removePlayer() ะธ handleInput() เดตเดฟเดถเดฆเต€เด•เดฐเดฟเด•เตเด•เต‡เดฃเตเดŸ เด†เดตเดถเตเดฏเดฎเดฟเดฒเตเดฒ, เด…เดต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต server.js. เดจเดฟเด™เตเด™เตพเด•เตเด•เต เด’เดฐเต เดฑเดฟเดซเตเดฐเดทเตผ เด†เดตเดถเตเดฏเดฎเตเดฃเตเดŸเต†เด™เตเด•เดฟเตฝ, เด•เตเดฑเดšเตเดšเต เด‰เดฏเดฐเดคเตเดคเดฟเดฒเต‡เด•เตเด•เต เดฎเดŸเด™เตเด™เตเด•.

เด…เดตเดธเดพเดจ เดตเดฐเดฟ constructor() เด†เดฐเด‚เดญเดฟเด•เตเด•เตเดจเตเดจเต เด…เดชเตเดกเต‡เดฑเตเดฑเต เดธเตˆเด•เตเด•เดฟเตพ เด—เต†เดฏเดฟเดฎเตเด•เตพ (60 เด…เดชเตเดกเต‡เดฑเตเดฑเตเด•เตพ/เดธเต†เด•เตเด•เดจเตเดฑเตเด•เดณเตเดŸเต† เด†เดตเตƒเดคเตเดคเดฟเดฏเดฟเตฝ):

game.js, เดญเดพเด—เด‚ 2

const Constants = require('../shared/constants');
const applyCollisions = require('./collisions');

class Game {
  // ...

  update() {
    // Calculate time elapsed
    const now = Date.now();
    const dt = (now - this.lastUpdateTime) / 1000;
    this.lastUpdateTime = now;

    // Update each bullet
    const bulletsToRemove = [];
    this.bullets.forEach(bullet => {
      if (bullet.update(dt)) {
        // Destroy this bullet
        bulletsToRemove.push(bullet);
      }
    });
    this.bullets = this.bullets.filter(
      bullet => !bulletsToRemove.includes(bullet),
    );

    // Update each player
    Object.keys(this.sockets).forEach(playerID => {
      const player = this.players[playerID];
      const newBullet = player.update(dt);
      if (newBullet) {
        this.bullets.push(newBullet);
      }
    });

    // Apply collisions, give players score for hitting bullets
    const destroyedBullets = applyCollisions(
      Object.values(this.players),
      this.bullets,
    );
    destroyedBullets.forEach(b => {
      if (this.players[b.parentID]) {
        this.players[b.parentID].onDealtDamage();
      }
    });
    this.bullets = this.bullets.filter(
      bullet => !destroyedBullets.includes(bullet),
    );

    // Check if any players are dead
    Object.keys(this.sockets).forEach(playerID => {
      const socket = this.sockets[playerID];
      const player = this.players[playerID];
      if (player.hp <= 0) {
        socket.emit(Constants.MSG_TYPES.GAME_OVER);
        this.removePlayer(socket);
      }
    });

    // Send a game update to each player every other time
    if (this.shouldSendUpdate) {
      const leaderboard = this.getLeaderboard();
      Object.keys(this.sockets).forEach(playerID => {
        const socket = this.sockets[playerID];
        const player = this.players[playerID];
        socket.emit(
          Constants.MSG_TYPES.GAME_UPDATE,
          this.createUpdate(player, leaderboard),
        );
      });
      this.shouldSendUpdate = false;
    } else {
      this.shouldSendUpdate = true;
    }
  }

  // ...
}

เดฐเต€เดคเดฟ update() เดธเต†เตผเดตเตผ เดธเตˆเดกเต เดฒเต‹เดœเดฟเด•เตเด•เดฟเดจเตเดฑเต† เดเดฑเตเดฑเดตเตเด‚ เดชเตเดฐเดงเดพเดจเดชเตเดชเต†เดŸเตเดŸ เดญเดพเด—เด‚ เด…เดŸเด™เตเด™เดฟเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจเต. เด…เดคเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเต†เดฒเตเดฒเดพเด‚ เด•เตเดฐเดฎเดคเตเดคเดฟเตฝ เดชเดŸเตเดŸเดฟเด•เดชเตเดชเต†เดŸเตเดคเตเดคเดพเด‚:

  1. เดธเดฎเดฏเด‚ เดŽเดคเตเดฐเดฏเดพเดฃเต†เดจเตเดจเต เด•เดฃเด•เตเด•เดพเด•เตเด•เตเดจเตเดจเต dt เด…เดคเต เด•เดดเดฟเดžเตเดž เด•เดพเดฒเด‚ เดฎเตเดคเตฝ เด‰เดฃเตเดŸเต update().
  2. เด“เดฐเต‹ เดชเตเดฐเตŠเดœเด•เตเดฑเตเดฑเดฟเดฒเตเด‚ เดชเตเดคเตเด•เตเด•เตเด•เดฏเตเด‚ เด†เดตเดถเตเดฏเดฎเต†เด™เตเด•เดฟเตฝ เด…เดตเดฏเต† เดจเดถเดฟเดชเตเดชเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต. เดˆ เดชเตเดฐเดตเตผเดคเตเดคเดจเด‚ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตเดจเตเดจเดคเต เดจเดฎเตเด•เตเด•เต เดชเดฟเดจเตเดจเต€เดŸเต เด•เดพเดฃเดพเด‚. เดคเตฝเด•เตเด•เดพเดฒเด‚ เดจเดฎเตเด•เตเด•เต เด…เดคเดฑเดฟเดžเตเดžเดพเตฝ เดฎเดคเดฟ bullet.update() เดฎเดŸเด™เตเด™เตเดจเตเดจเต true, เดชเตเดฐเตŠเดœเด•เตเดฑเตเดฑเตˆเตฝ เดจเดถเดฟเดชเตเดชเดฟเด•เตเด•เดชเตเดชเต†เดŸเต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต†เด™เตเด•เดฟเตฝ (เด…เดตเตป เด…เดฐเด™เตเด™เดฟเดจเต เดชเตเดฑเดคเตเดคเต‡เด•เตเด•เต เดชเต‹เดฏเดฟ).
  3. เด“เดฐเต‹ เด•เดณเดฟเด•เตเด•เดพเดฐเดจเตเด‚ เด…เดชเตเดกเต‡เดฑเตเดฑเต เดšเต†เดฏเตเดฏเตเด•เดฏเตเด‚ เด†เดตเดถเตเดฏเดฎเต†เด™เตเด•เดฟเตฝ เด’เดฐเต เดชเตเดฐเตŠเดœเด•เตเดฑเตเดฑเตˆเตฝ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต. เดˆ เดจเดŸเดชเตเดชเดพเด•เตเด•เดฒเตเด‚ เดจเดฎเตเด•เตเด•เต เดชเดฟเดจเตเดจเต€เดŸเต เด•เดพเดฃเดพเด‚ - player.update() เด’เดฐเต เดตเดธเตเดคเต เดคเดฟเดฐเดฟเด•เต† เดจเตฝเด•เดพเด‚ Bullet.
  4. เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเด•เดณเตเด‚ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจ เด•เดณเดฟเด•เตเด•เดพเดฐเตเด‚ เดคเดฎเตเดฎเดฟเดฒเตเดณเตเดณ เด•เต‚เดŸเตเดŸเดฟเดฏเดฟเดŸเดฟ เดชเดฐเดฟเดถเต‹เดงเดฟเด•เตเด•เตเดจเตเดจเต applyCollisions(), เด‡เดคเต เด•เดณเดฟเด•เตเด•เดพเดฐเต† เด…เดŸเดฟเด•เตเด•เตเดจเตเดจ เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเด•เดณเตเดŸเต† เด’เดฐเต เดจเดฟเดฐ เดจเตฝเด•เตเดจเตเดจเต. เดฎเดŸเด™เตเด™เดฟเดฏ เด“เดฐเต‹ เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเดฟเดจเตเด‚, เด…เดคเต เดŽเดฑเดฟเดžเตเดž เด•เดณเดฟเด•เตเด•เดพเดฐเดจเตเดฑเต† เดธเตโ€Œเด•เต‹เตผ เดžเด™เตเด™เตพ เดตเตผเดฆเตเดงเดฟเดชเตเดชเดฟเด•เตเด•เตเดจเตเดจเต (เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเดคเต player.onDealtDamage()), เดคเตเดŸเตผเดจเตเดจเต เด…เดฑเต‡เดฏเดฟเตฝ เดจเดฟเดจเตเดจเต เดชเตเดฐเตŠเดœเด•เตเดฑเตเดฑเตˆเตฝ เดจเต€เด•เตเด•เด‚ เดšเต†เดฏเตเดฏเตเด• bullets.
  5. เด•เตŠเดฒเตเดฒเดชเตเดชเต†เดŸเตเดŸ เดŽเดฒเตเดฒเดพ เด•เดณเดฟเด•เตเด•เดพเดฐเต†เดฏเตเด‚ เด…เดฑเดฟเดฏเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดจเดถเดฟเดชเตเดชเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต.
  6. เดŽเดฒเตเดฒเดพ เด•เดณเดฟเด•เตเด•เดพเตผเด•เตเด•เตเด‚ เด’เดฐเต เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเต เด…เดฏเดฏเตโ€Œเด•เตเด•เตเดจเตเดจเต เด“เดฐเต‡เดพ เดจเดฟเดฎเดฟเดทเดตเตเด‚ เดตเดฟเดณเดฟเดšเตเดšเดชเตเดชเต‹เตพ update(). เด‡เดคเต เดŸเตเดฐเดพเด•เตเด•เต เดšเต†เดฏเตเดฏเดพเตป เดฎเตเด•เดณเดฟเตฝ เดธเต‚เดšเดฟเดชเตเดชเดฟเดšเตเดš เด“เด•เตเดธเดฟเดฒเดฑเดฟ เดตเต‡เดฐเดฟเดฏเดฌเดฟเตพ เดžเด™เตเด™เดณเต† เดธเดนเดพเดฏเดฟเด•เตเด•เตเดจเตเดจเต shouldSendUpdate. เด•เดพเดฐเดฃเด‚ update() 60 เดคเดตเดฃ/เดธเต†เด•เตเด•เตปเดกเต เดตเดฟเดณเดฟเด•เตเด•เตเดจเตเดจเต, เดžเด™เตเด™เตพ เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เตพ 30 เดคเดตเดฃ/เดธเต†เด•เตเด•เตปเดกเต เด…เดฏเดฏเตโ€Œเด•เตเด•เตเดจเตเดจเต. เด…เด™เตเด™เดจเต†, เด•เตเดฒเต‹เด•เตเด•เต เด†เดตเตƒเดคเตเดคเดฟ เดธเต†เตผเดตเตผ 30 เด•เตเดฒเต‹เด•เตเด•เต เดธเตˆเด•เตเด•เดฟเดณเตเด•เตพ/เดธเต† เด†เดฃเต (เดžเด™เตเด™เตพ เด†เดฆเตเดฏ เดญเดพเด—เดคเตเดคเดฟเตฝ เด•เตเดฒเต‹เด•เตเด•เต เดซเตเดฐเต€เด•เตเดตเตปเดธเดฟเดฏเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเต เดธเด‚เดธเดพเดฐเดฟเดšเตเดšเต).

เดŽเดจเตเดคเตเด•เตŠเดฃเตเดŸเดพเดฃเต เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เตพ เดฎเดพเดคเตเดฐเด‚ เด…เดฏเดฏเตโ€Œเด•เตเด•เตเดจเตเดจเดคเต เด•เดพเดฒเดคเตเดคเดฟเดฒเต‚เดŸเต† ? เดšเดพเดจเตฝ เดธเด‚เดฐเด•เตเดทเดฟเด•เตเด•เดพเตป. เดธเต†เด•เตเด•เตปเดกเดฟเตฝ 30 เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เตพ เดงเดพเดฐเดพเดณเด‚!

เดชเดฟเดจเตเดจเต† เดตเต†เดฑเตเดคเต† เดตเดฟเดณเดฟเดšเตเดšเดพเดฒเต‹? update() เดธเต†เด•เตเด•เตปเดกเดฟเตฝ 30 เดคเดตเดฃ? เด—เต†เดฏเดฟเด‚ เดธเดฟเดฎเตเดฒเต‡เดทเตป เดฎเต†เดšเตเดšเดชเตเดชเต†เดŸเตเดคเตเดคเดพเตป. เด•เต‚เดŸเตเดคเตฝ เดคเดตเดฃ เด…เดคเต เดตเดฟเดณเดฟเด•เตเด•เดชเตเดชเต†เดŸเตเดจเตเดจเต update(), เด—เต†เดฏเดฟเด‚ เดธเดฟเดฎเตเดฒเต‡เดทเตป เด•เต‚เดŸเตเดคเตฝ เด•เตƒเดคเตเดฏเดคเดฏเตเดณเตเดณเดคเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚. เดŽเดจเตเดจเดพเตฝ เดตเต†เดฒเตเดฒเตเดตเดฟเดณเดฟเด•เดณเตเดŸเต† เดŽเดฃเตเดฃเดคเตเดคเดฟเตฝ เดตเดฒเตเดฒเดพเดคเต† เดญเตเดฐเดฎเดฟเด•เตเด•เดฐเตเดคเต update(), เด•เดพเดฐเดฃเด‚ เด‡เดคเต เด—เดฃเดฟเดคเดชเดฐเดฎเดพเดฏเดฟ เดšเต†เดฒเดตเต‡เดฑเดฟเดฏ เดœเต‹เดฒเดฟเดฏเดพเดฃเต - เดธเต†เด•เตเด•เตปเดกเดฟเตฝ 60 เดฎเดคเดฟ.

เด•เตเดฒเดพเดธเตเดธเดฟเดฒเต† เดฌเดพเด•เตเด•เดฟเดฏเตเดณเตเดณเดตเตผ Game เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจ เดธเดนเดพเดฏ เดฐเต€เดคเดฟเด•เตพ เด‰เตพเด•เตเด•เตŠเดณเตเดณเตเดจเตเดจเต update():

game.js, เดญเดพเด—เด‚ 3

class Game {
  // ...

  getLeaderboard() {
    return Object.values(this.players)
      .sort((p1, p2) => p2.score - p1.score)
      .slice(0, 5)
      .map(p => ({ username: p.username, score: Math.round(p.score) }));
  }

  createUpdate(player, leaderboard) {
    const nearbyPlayers = Object.values(this.players).filter(
      p => p !== player && p.distanceTo(player) <= Constants.MAP_SIZE / 2,
    );
    const nearbyBullets = this.bullets.filter(
      b => b.distanceTo(player) <= Constants.MAP_SIZE / 2,
    );

    return {
      t: Date.now(),
      me: player.serializeForUpdate(),
      others: nearbyPlayers.map(p => p.serializeForUpdate()),
      bullets: nearbyBullets.map(b => b.serializeForUpdate()),
      leaderboard,
    };
  }
}

getLeaderboard() เด‡เดคเต เดตเดณเดฐเต† เดฒเดณเดฟเดคเดฎเดพเดฃเต - เด‡เดคเต เด•เดณเดฟเด•เตเด•เดพเดฐเต† เดธเตโ€Œเด•เต‹เตผ เด…เดจเตเดธเดฐเดฟเดšเตเดšเต เดคเดฐเด‚เดคเดฟเดฐเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดฎเดฟเด•เดšเตเดš เด…เดžเตเดšเต เดชเต‡เดฐเต† เดŽเดŸเตเด•เตเด•เตเด•เดฏเตเด‚ เด“เดฐเต‹เดจเตเดจเดฟเดจเตเด‚ เด‰เดชเดฏเต‹เด•เตเดคเตƒเดจเดพเดฎเดตเตเด‚ เดธเตโ€Œเด•เต‹เดฑเตเด‚ เดจเตฝเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต.

createUpdate() เตฝ เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต update() เด•เดณเดฟเด•เตเด•เดพเตผเด•เตเด•เต เดตเดฟเดคเดฐเดฃเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจ เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเตเด•เตพ เดธเตƒเดทเตโ€ŒเดŸเดฟเด•เตเด•เดพเตป. เด…เดคเดฟเดจเตเดฑเต† เดชเตเดฐเดงเดพเดจ เดฆเตŒเดคเตเดฏเด‚ เดฐเต€เดคเดฟเด•เตพ เดตเดฟเดณเดฟเด•เตเด•เตเด• เดŽเดจเตเดจเดคเดพเดฃเต serializeForUpdate(), เด•เตเดฒเดพเดธเตเด•เตพเด•เตเด•เดพเดฏเดฟ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เดฟ Player ะธ Bullet. เด‡เดคเต เด“เดฐเต‹ เด•เดณเดฟเด•เตเด•เดพเดฐเดจเตเด‚ เดกเดพเดฑเตเดฑ เด•เตˆเดฎเดพเดฑเตเดจเตเดจเต เดŽเดจเตเดจเดคเต เดถเตเดฐเดฆเตเดงเดฟเด•เตเด•เตเด• เดเดฑเตเดฑเดตเตเด‚ เด…เดŸเตเดคเตเดคเตเดณเตเดณ เด•เดณเดฟเด•เตเด•เดพเดฐเตเด‚ เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเด•เดณเตเด‚ - เดชเตเดฒเต†เดฏเดฑเดฟเตฝ เดจเดฟเดจเตเดจเต เด…เด•เดฒเต†เดฏเตเดณเตเดณ เด—เต†เดฏเดฟเด‚ เด’เดฌเตโ€Œเดœเด•เตเดฑเตเดฑเตเด•เดณเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเตเดณเตเดณ เดตเดฟเดตเดฐเด™เตเด™เตพ เด•เตˆเดฎเดพเดฑเต‡เดฃเตเดŸ เด†เดตเดถเตเดฏเดฎเดฟเดฒเตเดฒ!

3. เดธเต†เตผเดตเดฑเดฟเดฒเต† เด—เต†เดฏเดฟเด‚ เดตเดธเตเดคเตเด•เตเด•เตพ

เดžเด™เตเด™เดณเตเดŸเต† เด—เต†เดฏเดฟเดฎเดฟเตฝ, เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเด•เดณเตเด‚ เด•เดณเดฟเด•เตเด•เดพเดฐเตเด‚ เดฏเดฅเดพเตผเดคเตเดฅเดคเตเดคเดฟเตฝ เดตเดณเดฐเต† เดธเดฎเดพเดจเดฎเดพเดฃเต: เด…เดต เด…เดฎเต‚เตผเดคเตเดคเดฎเดพเดฏ เดตเตƒเดคเตเดคเดพเด•เตƒเดคเดฟเดฏเดฟเดฒเตเดณเตเดณ เดšเดฒเดฟเด•เตเด•เตเดจเตเดจ เด—เต†เดฏเดฟเด‚ เด’เดฌเตโ€Œเดœเด•เตเดฑเตเดฑเตเด•เดณเดพเดฃเต. เด•เดณเดฟเด•เตเด•เดพเดฐเตเด‚ เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเด•เดณเตเด‚ เดคเดฎเตเดฎเดฟเดฒเตเดณเตเดณ เดˆ เดธเดพเดฎเตเดฏเด‚ เดชเตเดฐเดฏเต‹เดœเดจเดชเตเดชเต†เดŸเตเดคเตเดคเตเดจเตเดจเดคเดฟเดจเต, เด’เดฐเต เด…เดŸเดฟเดธเตเดฅเดพเดจ เด•เตเดฒเดพเดธเต เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เดฟเด•เตเด•เตŠเดฃเตเดŸเต เดจเดฎเตเด•เตเด•เต เด†เดฐเด‚เดญเดฟเด•เตเด•เดพเด‚ Object:

object.js

class Object {
  constructor(id, x, y, dir, speed) {
    this.id = id;
    this.x = x;
    this.y = y;
    this.direction = dir;
    this.speed = speed;
  }

  update(dt) {
    this.x += dt * this.speed * Math.sin(this.direction);
    this.y -= dt * this.speed * Math.cos(this.direction);
  }

  distanceTo(object) {
    const dx = this.x - object.x;
    const dy = this.y - object.y;
    return Math.sqrt(dx * dx + dy * dy);
  }

  setDirection(dir) {
    this.direction = dir;
  }

  serializeForUpdate() {
    return {
      id: this.id,
      x: this.x,
      y: this.y,
    };
  }
}

เด‡เดตเดฟเดŸเต† เดธเด™เตเด•เต€เตผเดฃเตเดฃเดฎเดพเดฏ เด’เดจเตเดจเตเด‚ เดจเดŸเด•เตเด•เตเดจเตเดจเดฟเดฒเตเดฒ. เดˆ เด•เตเดฒเดพเดธเต เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเดคเตเดคเดฟเดจเต เดจเดฒเตเดฒเตŠเดฐเต เดคเตเดŸเด•เตเด•เดฎเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚. เด•เตเดฒเดพเดธเต เดŽเด™เตเด™เดจเต†เดฏเต†เดจเตเดจเต เดจเต‹เด•เตเด•เดพเด‚ Bullet เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต Object:

bullet.js

const shortid = require('shortid');
const ObjectClass = require('./object');
const Constants = require('../shared/constants');

class Bullet extends ObjectClass {
  constructor(parentID, x, y, dir) {
    super(shortid(), x, y, dir, Constants.BULLET_SPEED);
    this.parentID = parentID;
  }

  // Returns true if the bullet should be destroyed
  update(dt) {
    super.update(dt);
    return this.x < 0 || this.x > Constants.MAP_SIZE || this.y < 0 || this.y > Constants.MAP_SIZE;
  }
}

เดจเดŸเดชเตเดชเดพเด•เตเด•เตฝ Bullet เดตเดณเดฐเต† เดšเต†เดฑเตเดคเต! เดžเด™เตเด™เตพ เดšเต‡เตผเดคเตเดคเต Object เด‡เดจเดฟเดชเตเดชเดฑเดฏเตเดจเตเดจ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฃเด™เตเด™เตพ เดฎเดพเดคเตเดฐเด‚:

  • เดชเดพเด•เตเด•เต‡เดœเต เด‰เดชเดฏเต‹เด—เดฟเด•เตเด•เตเดจเตเดจเต เดนเตเดฐเดธเตเดตเดฎเดพเดฏ เด•เตเดฐเดฎเดฐเดนเดฟเดคเดฎเดพเดฏ เดคเดฒเดฎเตเดฑเดฏเตเด•เตเด•เดพเดฏเดฟ id เดชเตเดฐเตŠเดœเด•เตเดฑเตเดฑเตˆเตฝ.
  • เด’เดฐเต เดซเต€เตฝเดกเต เดšเต‡เตผเด•เตเด•เตเดจเตเดจเต parentID, เด…เดคเตเดตเดดเดฟ เดˆ เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเตฝ เดธเตƒเดทเตโ€ŒเดŸเดฟเดšเตเดš เด•เดณเดฟเด•เตเด•เดพเดฐเดจเต† เดจเดฟเด™เตเด™เตพเด•เตเด•เต เดŸเตเดฐเดพเด•เตเด•เตเดšเต†เดฏเตเดฏเดพเดจเดพเด•เตเด‚.
  • เด‡เดคเดฟเดฒเต‡เด•เตเด•เต เดฑเดฟเดŸเตเดŸเต‡เตบ เดฎเต‚เดฒเตเดฏเด‚ เดšเต‡เตผเด•เตเด•เตเดจเตเดจเต update(), เดเดคเต เดคเตเดฒเตเดฏเดฎเดพเดฃเต true, เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเตฝ เด…เดฐเต€เดจเดฏเตเด•เตเด•เต เดชเตเดฑเดคเตเดคเดพเดฃเต†เด™เตเด•เดฟเตฝ (เด…เดตเดธเดพเดจ เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เดžเด™เตเด™เตพ เด‡เดคเดฟเดจเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเต เดธเด‚เดธเดพเดฐเดฟเดšเตเดšเดคเดพเดฏเดฟ เด“เตผเด•เตเด•เตเดจเตเดจเตเดฃเตเดŸเต‹?).

เดจเดฎเตเด•เตเด•เต เดฎเตเดจเตเดจเต‹เดŸเตเดŸเต เดชเต‹เด•เดพเด‚ Player:

player.js

const ObjectClass = require('./object');
const Bullet = require('./bullet');
const Constants = require('../shared/constants');

class Player extends ObjectClass {
  constructor(id, username, x, y) {
    super(id, x, y, Math.random() * 2 * Math.PI, Constants.PLAYER_SPEED);
    this.username = username;
    this.hp = Constants.PLAYER_MAX_HP;
    this.fireCooldown = 0;
    this.score = 0;
  }

  // Returns a newly created bullet, or null.
  update(dt) {
    super.update(dt);

    // Update score
    this.score += dt * Constants.SCORE_PER_SECOND;

    // Make sure the player stays in bounds
    this.x = Math.max(0, Math.min(Constants.MAP_SIZE, this.x));
    this.y = Math.max(0, Math.min(Constants.MAP_SIZE, this.y));

    // Fire a bullet, if needed
    this.fireCooldown -= dt;
    if (this.fireCooldown <= 0) {
      this.fireCooldown += Constants.PLAYER_FIRE_COOLDOWN;
      return new Bullet(this.id, this.x, this.y, this.direction);
    }
    return null;
  }

  takeBulletDamage() {
    this.hp -= Constants.BULLET_DAMAGE;
  }

  onDealtDamage() {
    this.score += Constants.SCORE_BULLET_HIT;
  }

  serializeForUpdate() {
    return {
      ...(super.serializeForUpdate()),
      direction: this.direction,
      hp: this.hp,
    };
  }
}

เด•เดณเดฟเด•เตเด•เดพเตผ เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเด•เดณเต‡เด•เตเด•เดพเตพ เดธเด™เตเด•เต€เตผเดฃเตเดฃเดฎเดพเดฃเต, เด…เดคเดฟเดจเดพเตฝ เดˆ เด•เตเดฒเดพเดธเต เด•เตเดฑเดšเตเดšเต เดซเต€เตฝเดกเตเด•เตพ เด•เต‚เดŸเดฟ เดธเต‚เด•เตเดทเดฟเด•เตเด•เดฃเด‚. เด…เดตเดจเตเดฑเต† เดฐเต€เดคเดฟ update() เด•เต‚เดŸเตเดคเตฝ เดœเต‹เดฒเดฟ เดšเต†เดฏเตเดฏเตเดจเตเดจเต, เดชเตเดฐเดคเตเดฏเต‡เด•เดฟเดšเตเดšเตเด‚ เดชเตเดคเตเดคเดพเดฏเดฟ เดธเตƒเดทเตเดŸเดฟเดšเตเดš เดชเตเดฐเตŠเดœเด•เตเดฑเตเดฑเตˆเตฝ เด…เดตเดถเต‡เดทเดฟเด•เตเด•เตเดจเตเดจเดฟเดฒเตเดฒเต†เด™เตเด•เดฟเตฝ เดคเดฟเดฐเดฟเด•เต† เดจเตฝเด•เตเดจเตเดจเต fireCooldown (เดฎเตเดฎเตเดชเดคเตเดคเต† เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เดžเด™เตเด™เตพ เด‡เดคเดฟเดจเต†เด•เตเด•เตเดฑเดฟเดšเตเดšเต เดธเด‚เดธเดพเดฐเดฟเดšเตเดšเดคเดพเดฏเดฟ เด“เตผเด•เตเด•เตเดจเตเดจเตเดฃเตเดŸเต‹?). เด‡เดคเต เดฐเต€เดคเดฟ เดตเดฟเดชเตเดฒเต€เด•เดฐเดฟเด•เตเด•เตเด•เดฏเตเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเต serializeForUpdate(), เด•เดพเดฐเดฃเด‚ เดžเด™เตเด™เตพ เด—เต†เดฏเดฟเด‚ เด…เดชเตโ€Œเดกเต‡เดฑเตเดฑเดฟเตฝ เด•เดณเดฟเด•เตเด•เดพเดฐเดจเตเดณเตเดณ เด…เดงเดฟเด• เดซเต€เตฝเดกเตเด•เตพ เด‰เตพเดชเตเดชเต†เดŸเตเดคเตเดคเต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต.

เด…เดŸเดฟเดธเตเดฅเดพเดจ เด•เตเดฒเดพเดธเดฟเดจเตเดฑเต† เดฒเดญเตเดฏเดค Object - เด•เต‹เดกเต เด†เดตเตผเดคเตเดคเดจเด‚ เด’เดดเดฟเดตเดพเด•เตเด•เตเดจเตเดจเดคเดฟเดจเตเดณเตเดณ เด’เดฐเต เดชเตเดฐเดงเดพเดจ เด˜เดŸเตเดŸเด‚. เด‰เดฆเดพเดนเดฐเดฃเดคเตเดคเดฟเดจเต, เด•เตเดฒเดพเดธเต เด‡เดฒเตเดฒเดพเดคเต† Object เดŽเดฒเตเดฒเดพ เด—เต†เดฏเดฟเด‚ เด’เดฌเตเดœเด•เตเดฑเตเดฑเดฟเดจเตเด‚ เด’เดฐเต‡ เดจเดฟเตผเดตเตเดตเดนเดฃเด‚ เด‰เดฃเตเดŸเดพเดฏเดฟเดฐเดฟเด•เตเด•เดฃเด‚ distanceTo(), เด•เต‚เดŸเดพเดคเต† เด’เดจเตเดจเดฟเดฒเดงเดฟเด•เด‚ เดซเดฏเดฒเตเด•เดณเดฟเดฒเตเดŸเดจเต€เดณเด‚ เดˆ เดจเดŸเดชเตเดชเดพเด•เตเด•เดฒเตเด•เดณเต†เดฒเตเดฒเดพเด‚ เด•เต‹เดชเตเดชเดฟ-เดชเต‡เดธเตเดฑเตเดฑเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเต เด’เดฐเต เดชเต‡เดŸเดฟเดธเตเดตเดชเตเดจเดฎเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเด‚. เดตเดฒเดฟเดฏ เดชเดฆเตเดงเดคเดฟเด•เตพเด•เตเด•เต เด‡เดคเต เดตเดณเดฐเต† เดชเตเดฐเดงเดพเดจเดฎเดพเดฃเต, เดตเดฟเด•เดธเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเตเดฑเต† เดŽเดฃเตเดฃเด‚ เดตเดฐเตเดฎเตเดชเต‹เตพ Object เด•เตเดฒเดพเดธเตเด•เตพ เดตเดณเดฐเตเดจเตเดจเต.

4. เด•เต‚เดŸเตเดŸเดฟเดฏเดฟเดŸเดฟ เด•เดฃเตเดŸเต†เดคเตเดคเตฝ

เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเด•เตพ เด•เดณเดฟเด•เตเด•เดพเดฐเต† เดคเดŸเตเดŸเดฟเดฏเดคเต เดคเดฟเดฐเดฟเดšเตเดšเดฑเดฟเดฏเตเด• เดฎเดพเดคเตเดฐเดฎเดพเดฃเต เดžเด™เตเด™เตพเด•เตเด•เต เดšเต†เดฏเตเดฏเดพเตป เด…เดตเดถเต‡เดทเดฟเด•เตเด•เตเดจเตเดจเดคเต! เดฐเต€เดคเดฟเดฏเดฟเตฝ เดจเดฟเดจเตเดจเตเดณเตเดณ เดˆ เด•เต‹เดกเต เดธเตเดจเดฟเดชเตเดชเดฑเตเดฑเต เด“เตผเด•เตเด•เตเด• update() เด•เตเดฒเดพเดธเดฟเตฝ Game:

game.js

const applyCollisions = require('./collisions');

class Game {
  // ...

  update() {
    // ...

    // Apply collisions, give players score for hitting bullets
    const destroyedBullets = applyCollisions(
      Object.values(this.players),
      this.bullets,
    );
    destroyedBullets.forEach(b => {
      if (this.players[b.parentID]) {
        this.players[b.parentID].onDealtDamage();
      }
    });
    this.bullets = this.bullets.filter(
      bullet => !destroyedBullets.includes(bullet),
    );

    // ...
  }
}

เดžเด™เตเด™เตพ เดฐเต€เดคเดฟ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต applyCollisions(), เด‡เดคเต เด•เดณเดฟเด•เตเด•เดพเดฐเต† เด…เดŸเดฟเด•เตเด•เตเดจเตเดจ เดŽเดฒเตเดฒเดพ เดชเตเดฐเตŠเดœเด•เตเดฑเตเดฑเดฟเดฒเตเด•เดณเตเด‚ เดคเดฟเดฐเดฟเด•เต† เดจเตฝเด•เตเดจเตเดจเต. เดญเดพเด—เตเดฏเดตเดถเดพเตฝ, เด‡เดคเต เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเต เด…เดคเตเดฐ เดฌเตเดฆเตเดงเดฟเดฎเตเดŸเตเดŸเตเดณเตเดณ เด•เดพเดฐเตเดฏเดฎเดฒเตเดฒ, เด•เดพเดฐเดฃเด‚

  • เด•เต‚เดŸเตเดŸเดฟเดฏเดฟเดŸเดฟเด•เตเด•เตเดจเตเดจ เดŽเดฒเตเดฒเดพ เดตเดธเตเดคเตเด•เตเด•เดณเตเด‚ เดธเตผเด•เตเด•เดฟเดณเตเด•เดณเดพเดฃเต, เด•เต‚เดŸเตเดŸเดฟเดฏเดฟเดŸเดฟ เด•เดฃเตเดŸเต†เดคเตเดคเตฝ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตเดจเตเดจเดคเดฟเดจเตเดณเตเดณ เดเดฑเตเดฑเดตเตเด‚ เดฒเดณเดฟเดคเดฎเดพเดฏ เดฐเต‚เดชเดฎเดพเดฃเดฟเดคเต.
  • เดžเด™เตเด™เตพเด•เตเด•เต เด‡เดคเดฟเดจเด•เด‚ เด’เดฐเต เดฐเต€เดคเดฟเดฏเตเดฃเตเดŸเต distanceTo(), เดฎเตเดฎเตเดชเดคเตเดคเต† เดตเดฟเดญเดพเด—เดคเตเดคเดฟเดฒเต† เด•เตเดฒเดพเดธเตเดธเดฟเตฝ เดžเด™เตเด™เตพ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เดฟเดฏเดคเต Object.

เดžเด™เตเด™เดณเตเดŸเต† เด•เต‚เดŸเตเดŸเดฟเดฏเดฟเดŸเดฟ เด•เดฃเตเดŸเต†เดคเตเดคเตฝ เดจเดŸเดชเตเดชเดฟเดฒเดพเด•เตเด•เตเดจเตเดจเดคเต เด‡เด™เตเด™เดจเต†เดฏเดพเดฃเต:

collisions.js

const Constants = require('../shared/constants');

// Returns an array of bullets to be destroyed.
function applyCollisions(players, bullets) {
  const destroyedBullets = [];
  for (let i = 0; i < bullets.length; i++) {
    // Look for a player (who didn't create the bullet) to collide each bullet with.
    // As soon as we find one, break out of the loop to prevent double counting a bullet.
    for (let j = 0; j < players.length; j++) {
      const bullet = bullets[i];
      const player = players[j];
      if (
        bullet.parentID !== player.id &&
        player.distanceTo(bullet) <= Constants.PLAYER_RADIUS + Constants.BULLET_RADIUS
      ) {
        destroyedBullets.push(bullet);
        player.takeBulletDamage();
        break;
      }
    }
  }
  return destroyedBullets;
}

เดˆ เดฒเดณเดฟเดคเดฎเดพเดฏ เด•เต‚เดŸเตเดŸเดฟเดฏเดฟเดŸเดฟ เด•เดฃเตเดŸเต†เดคเตเดคเตฝ เดตเดธเตเดคเตเดคเดฏเต† เด…เดŸเดฟเดธเตเดฅเดพเดจเดฎเดพเด•เตเด•เดฟเดฏเตเดณเตเดณเดคเดพเดฃเต เดฐเดฃเตเดŸเต เดธเตผเด•เตเด•เดฟเดณเตเด•เตพ เด…เดตเดฏเตเดŸเต† เด•เต‡เดจเตเดฆเตเดฐเด™เตเด™เตพ เดคเดฎเตเดฎเดฟเดฒเตเดณเตเดณ เดฆเต‚เดฐเด‚ เด…เดตเดฏเตเดŸเต† เด†เดฐเด™เตเด™เดณเตเดŸเต† เด†เด•เต†เดคเตเดคเตเด•เดฏเต‡เด•เตเด•เดพเตพ เด•เตเดฑเดตเดพเดฃเต†เด™เตเด•เดฟเตฝ เด•เต‚เดŸเตเดŸเดฟเดฏเดฟเดŸเดฟเด•เตเด•เตเดจเตเดจเต. เดฐเดฃเตเดŸเต เดธเตผเด•เตเด•เดฟเดณเตเด•เดณเตเดŸเต† เด•เต‡เดจเตเดฆเตเดฐเด™เตเด™เตพ เดคเดฎเตเดฎเดฟเดฒเตเดณเตเดณ เดฆเต‚เดฐเด‚ เด…เดตเดฏเตเดŸเต† เด†เดฐเด™เตเด™เดณเตเดŸเต† เด†เด•เต†เดคเตเดคเตเด•เดฏเตเด•เตเด•เต เดคเตเดฒเตเดฏเดฎเดพเดฏเดฟเดฐเดฟเด•เตเด•เตเดจเตเดจ เด’เดฐเต เด•เต‡เดธเต เด‡เดคเดพ:

.io เดตเดฟเดญเดพเด—เดคเตเดคเดฟเตฝ เด’เดฐเต เดฎเตพเดŸเตเดŸเดฟเดชเตเดฒเต†เดฏเตผ เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตเดŸเดฟเด•เตเด•เตเดจเตเดจเต
เด‡เดตเดฟเดŸเต† เดจเดฟเด™เตเด™เตพ เด•เตเดฑเดšเตเดšเต เดตเดถเด™เตเด™เตพ เด•เต‚เดŸเดฟ เดธเต‚เด•เตเดทเตเดฎเดฎเดพเดฏเดฟ เดถเตเดฐเดฆเตเดงเดฟเด•เตเด•เต‡เดฃเตเดŸเดคเตเดฃเตเดŸเต:

  • เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเตฝ เด…เดคเต เดธเตƒเดทเตโ€ŒเดŸเดฟเดšเตเดš เด•เดณเดฟเด•เตเด•เดพเดฐเดจเต† เดฌเดพเดงเดฟเด•เตเด•เดฐเตเดคเต. เดคเดพเดฐเดคเดฎเตเดฏเด‚ เดšเต†เดฏเตเดฏเตเดจเตเดจเดคเดฟเดฒเต‚เดŸเต† เด‡เดคเต เดจเต‡เดŸเดพเดจเดพเด•เตเด‚ bullet.parentID ั player.id.
  • เด’เดฐเต‡ เดธเดฎเดฏเด‚ เด’เดจเตเดจเดฟเดฒเดงเดฟเด•เด‚ เด•เดณเดฟเด•เตเด•เดพเดฐเต† เด…เดŸเดฟเด•เตเด•เตเดจเตเดจ เด…เด™เตเด™เต‡เดฏเดฑเตเดฑเดคเตเดคเต† เดธเดพเดนเดšเดฐเตเดฏเดคเตเดคเดฟเตฝ เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเตฝ เด’เดฐเต เดคเดตเดฃ เดฎเดพเดคเตเดฐเดฎเต‡ เด…เดŸเดฟเด•เตเด•เดพเดตเต‚. เด“เดชเตเดชเดฑเต‡เดฑเตเดฑเตผ เด‰เดชเดฏเต‹เด—เดฟเดšเตเดšเต เดžเด™เตเด™เตพ เดˆ เดชเตเดฐเดถเตเดจเด‚ เดชเดฐเดฟเดนเดฐเดฟเด•เตเด•เตเด‚ break: เด’เดฐเต เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเตเดฎเดพเดฏเดฟ เด•เต‚เดŸเตเดŸเดฟเดฏเดฟเดŸเดฟเด•เตเด•เตเดจเตเดจ เด’เดฐเต เด•เดณเดฟเด•เตเด•เดพเดฐเดจเต† เด•เดฃเตเดŸเต†เดคเตเดคเดฟเด•เตเด•เดดเดฟเดžเตเดžเดพเตฝ, เดžเด™เตเด™เตพ เดคเดฟเดฐเดฏเตฝ เดจเดฟเตผเดคเตเดคเดฟ เด…เดŸเตเดคเตเดค เดชเตเดฐเตŠเดœเด•เตโ€ŒเดŸเตˆเดฒเดฟเดฒเต‡เด•เตเด•เต เดชเต‹เด•เตเด‚.

เด…เดตเดธเดพเดจเด‚

เด…เดคเตเดฐเดฏเต‡เดฏเตเดณเตเดณเต‚! เด’เดฐเต .io เดตเต†เดฌเต เด—เต†เดฏเดฟเด‚ เดธเตƒเดทเตโ€ŒเดŸเดฟเด•เตเด•เตเดจเตเดจเดคเดฟเดจเต เดจเดฟเด™เตเด™เตพ เด…เดฑเดฟเดฏเต‡เดฃเตเดŸเดคเต†เดฒเตเดฒเดพเด‚ เดžเด™เตเด™เตพ เด‰เตพเดชเตเดชเต†เดŸเตเดคเตเดคเดฟเดฏเดฟเดŸเตเดŸเตเดฃเตเดŸเต. เด…เดŸเตเดคเตเดคเดคเต เดŽเดจเตเดคเดพเดฃเต? เดจเดฟเด™เตเด™เดณเตเดŸเต† เดธเตเดตเดจเตเดคเด‚ .io เด—เต†เดฏเดฟเด‚ เดจเดฟเตผเดฎเตเดฎเดฟเด•เตเด•เตเด•!

เดŽเดฒเตเดฒเดพ เด‰เดฆเดพเดนเดฐเดฃ เด•เต‹เดกเตเด•เดณเตเด‚ เด“เดชเตเดชเตบ เดธเต‹เดดเตโ€Œเดธเต เด†เดฃเต เด•เต‚เดŸเดพเดคเต† เดชเต‹เดธเตเดฑเตเดฑเตเดšเต†เดฏเตเดคเดคเตเดฎเดพเดฃเต เดธเดพเดฎเต‚เดนเดฟเด•เด‚.

เด…เดตเดฒเด‚เดฌเด‚: www.habr.com

เด’เดฐเต เด…เดญเดฟเดชเตเดฐเดพเดฏเด‚ เดšเต‡เตผเด•เตเด•เตเด•