.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) เจ•เจฒเจพเจ‡เฉฐเจŸ เจฆเจพ เจเจ‚เจŸเจฐเฉ€ เจชเฉเจ†เจ‡เฉฐเจŸ เจนเฉˆเฅค เจตเฉˆเจฌเจชเฉˆเจ• เจ‡เฉฑเจฅเฉ‹เจ‚ เจธเจผเฉเจฐเฉ‚ เจนเฉ‹เจตเฉ‡เจ—เจพ เจ…เจคเฉ‡ เจฆเฉ‚เจœเฉ€เจ†เจ‚ เจ†เจฏเจพเจค เจ•เฉ€เจคเฉ€เจ†เจ‚ เจซเจพเจˆเจฒเจพเจ‚ เจจเฉ‚เฉฐ เจฎเฉเฉœ-เจฎเฉเฉœ เจ–เฉ‹เจœ เจ•เจฐเฉ‡เจ—เจพเฅค
  • เจธเจพเจกเฉ‡ เจตเฉˆเจฌเจชเฉˆเจ• เจฌเจฟเจฒเจก เจฆเจพ เจ†เจ‰เจŸเจชเฉเฉฑเจŸ JS เจกเจพเจ‡เจฐเฉˆเจ•เจŸเจฐเฉ€ เจตเจฟเฉฑเจš เจธเจฅเจฟเจค เจนเฉ‹เจตเฉ‡เจ—เจพ dist/. เจฎเฉˆเจ‚ เจ‡เจธ เจซเจพเจˆเจฒ เจจเฉ‚เฉฐ เจธเจพเจกเฉ€ เจ•เจพเจฒ เจ•เจฐเจพเจ‚เจ—เจพ เจœเฉ‡เจเจธ เจชเฉˆเจ•เฉ‡เจœ.
  • เจ…เจธเฉ€เจ‚ เจตเจฐเจคเจฆเฉ‡ เจนเจพเจ‚ เจฌเจพเจฌเจฒ, เจ…เจคเฉ‡ เจ–เจพเจธ เจคเฉŒเจฐ 'เจคเฉ‡ เจธเฉฐเจฐเจšเจจเจพ @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, เจ‰เจคเจชเจพเจฆเจจ เจฒเจˆ เจคเฉˆเจจเจพเจค เจ•เจฐเจจ เจตเฉ‡เจฒเฉ‡ เจชเฉˆเจ•เฉ‡เจœ เจ…เจ•เจพเจฐ เจจเฉ‚เฉฐ เจ…เจจเฉเจ•เฉ‚เจฒ เจฌเจฃเจพเจ‰เจฃ เจฒเจˆเฅค

เจธเจฅเจพเจจเจ• เจธเฉˆเฉฑเจŸเจ…เฉฑเจช

เจฎเฉˆเจ‚ เจคเฉเจนเจพเจกเฉ€ เจธเจฅเจพเจจเจ• เจฎเจธเจผเฉ€เจจ 'เจคเฉ‡ เจชเฉเจฐเฉ‹เจœเฉˆเจ•เจŸ เจจเฉ‚เฉฐ เจธเจฅเจพเจชเจฟเจค เจ•เจฐเจจ เจฆเฉ€ เจธเจฟเจซเจพเจฐเจธเจผ เจ•เจฐเจฆเจพ เจนเจพเจ‚ เจคเจพเจ‚ เจœเฉ‹ เจคเฉเจธเฉ€เจ‚ เจ‡เจธ เจชเฉ‹เจธเจŸ เจตเจฟเฉฑเจš เจธเฉ‚เจšเฉ€เจฌเฉฑเจง เจ•เจฆเจฎเจพเจ‚ เจฆเฉ€ เจชเจพเจฒเจฃเจพ เจ•เจฐ เจธเจ•เฉ‹เฅค เจธเฉˆเฉฑเจŸเจ…เฉฑเจช เจธเจงเจพเจฐเจจ เจนเฉˆ: เจชเจนเจฟเจฒเจพเจ‚, เจธเจฟเจธเจŸเจฎ เจ•เฉ‹เจฒ เจนเฉ‹เจฃเจพ เจšเจพเจนเฉ€เจฆเจพ เจนเฉˆ เจจเฉ‹เจก ะธ เจเจจเจชเฉ€เจเจฎ. เจ…เฉฑเจ—เฉ‡ เจคเฉเจนเจพเจจเฉ‚เฉฐ เจ•เฉ€ เจ•เจฐเจจ เจฆเฉ€ เจฒเฉ‹เฉœ เจนเฉˆ

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

เจ…เจคเฉ‡ เจคเฉเจธเฉ€เจ‚ เจœเจพเจฃ เจฒเจˆ เจคเจฟเจ†เจฐ เจนเฉ‹! เจตเจฟเจ•เจพเจธ เจธเจฐเจตเจฐ เจธเจผเฉเจฐเฉ‚ เจ•เจฐเจจ เจฒเจˆ, เจฌเฉฑเจธ เจšเจฒเจพเจ“

$ npm run develop

เจ…เจคเฉ‡ เจ†เจชเจฃเฉ‡ เจตเฉˆเฉฑเจฌ เจฌเฉเจฐเจพเจŠเจœเจผเจฐ 'เจคเฉ‡ เจœเจพเจ“ เจฒเฉ‹เจ•เจฒเจนเฉ‹เจธเจŸ: 3000. เจกเจฟเจตเฉˆเจฒเจชเจฎเฉˆเจ‚เจŸ เจธเจฐเจตเจฐ เจ†เจชเจฃเฉ‡ เจ†เจช JS เจ…เจคเฉ‡ CSS เจชเฉˆเจ•เฉ‡เจœเจพเจ‚ เจจเฉ‚เฉฐ เจฆเฉเจฌเจพเจฐเจพ เจฌเจฃเจพ เจฆเฉ‡เจตเฉ‡เจ—เจพ เจ•เจฟเจ‰เจ‚เจ•เจฟ เจ•เฉ‹เจก เจคเจฌเจฆเฉ€เจฒเฉ€เจ†เจ‚ เจนเฉเฉฐเจฆเฉ€เจ†เจ‚ เจนเจจ - เจธเจพเจฐเฉ€เจ†เจ‚ เจคเจฌเจฆเฉ€เจฒเฉ€เจ†เจ‚ เจฆเฉ‡เจ–เจฃ เจฒเจˆ เจชเฉฐเจจเฉ‡ เจจเฉ‚เฉฐ เจคเจพเจœเจผเจพ เจ•เจฐเฉ‹!

3. เจ•เจฒเจพเจ‡เฉฐเจŸ เจเจ‚เจŸเจฐเฉ€ เจชเฉเจ†เจ‡เฉฐเจŸ

เจ†เจ“ เจ—เฉ‡เจฎ เจ•เฉ‹เจก 'เจคเฉ‡ เจ†เจชเจฃเฉ‡ เจ†เจช เจนเฉ‡เจ เจพเจ‚ เจ‰เจคเจฐเฉ€เจเฅค เจชเจนเจฟเจฒเจพเจ‚ เจธเจพเจจเฉ‚เฉฐ เจ‡เฉฑเจ• เจชเฉฐเจจเฉ‡ เจฆเฉ€ เจฒเฉ‹เฉœ เจนเฉˆ index.html, เจœเจฆเฉ‹เจ‚ เจคเฉเจธเฉ€เจ‚ เจธเจพเจˆเจŸ 'เจคเฉ‡ เจœเจพเจ‚เจฆเฉ‡ เจนเฉ‹, เจคเจพเจ‚ เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจ‡เจธเจจเฉ‚เฉฐ เจชเจนเจฟเจฒเจพเจ‚ เจฒเฉ‹เจก เจ•เจฐเฉ‡เจ—เจพเฅค เจธเจพเจกเจพ เจชเฉฐเจจเจพ เจ•เจพเจซเจผเฉ€ เจธเจงเจพเจฐเจจ เจนเฉ‹เจตเฉ‡เจ—เจพ:

Index.html

เจ‡เฉฑเจ• เจ‰เจฆเจพเจนเจฐเจจ .io เจ—เฉ‡เจฎ  เจ–เฉ‡เจกเฉ‹

เจ‡เจธ เจ•เฉ‹เจก เจ‰เจฆเจพเจนเจฐเจจ เจจเฉ‚เฉฐ เจธเจชเจธเจผเจŸเจคเจพ เจฒเจˆ เจฅเฉ‹เฉœเฉเจนเจพ เจœเจฟเจนเจพ เจธเจฐเจฒ เจฌเจฃเจพเจ‡เจ† เจ—เจฟเจ† เจนเฉˆ, เจ…เจคเฉ‡ เจฎเฉˆเจ‚ เจชเฉ‹เจธเจŸ เจตเจฟเฉฑเจš เจนเฉ‹เจฐ เจฌเจนเฉเจค เจธเจพเจฐเฉ€เจ†เจ‚ เจ‰เจฆเจพเจนเจฐเจฃเจพเจ‚ เจจเจพเจฒ เจตเฉ€ เจ…เจœเจฟเจนเจพ เจนเฉ€ เจ•เจฐเจพเจ‚เจ—เจพเฅค เจคเฉเจธเฉ€เจ‚ เจนเจฎเฉ‡เจธเจผเจพ 'เจคเฉ‡ เจชเฉ‚เจฐเจพ เจ•เฉ‹เจก เจฆเฉ‡เจ– เจธเจ•เจฆเฉ‡ เจนเฉ‹ GitHub.

เจธเจพเจกเฉ‡ เจ•เฉ‹เจฒ:

  • HTML5 เจ•เฉˆเจจเจตเจธ เจคเฉฑเจค (<canvas>), เจœเจฟเจธเจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ…เจธเฉ€เจ‚ เจ—เฉ‡เจฎ เจจเฉ‚เฉฐ เจฐเฉˆเจ‚เจกเจฐ เจ•เจฐเจจ เจฒเจˆ เจ•เจฐเจพเจ‚เจ—เฉ‡เฅค
  • <link> เจธเจพเจกเฉ‡ CSS เจชเฉˆเจ•เฉ‡เจœ เจจเฉ‚เฉฐ เจœเฉ‹เฉœเจจ เจฒเจˆเฅค
  • <script> เจธเจพเจกเฉ‡ Javascript เจชเฉˆเจ•เฉ‡เจœ เจจเฉ‚เฉฐ เจœเฉ‹เฉœเจจ เจฒเจˆ.
  • เจ‰เจชเจญเฉ‹เจ—เจคเจพ เจจเจพเจฎ เจฆเฉ‡ เจจเจพเจฒ เจฎเฉเฉฑเจ– เจฎเฉ‡เจจเฉ‚ <input> เจ…เจคเฉ‡ "PLAY" เจฌเจŸเจจ (<button>).

เจ‡เฉฑเจ• เจตเจพเจฐ เจนเฉ‹เจฎ เจชเฉ‡เจœ เจฒเฉ‹เจก เจนเฉ‹เจฃ เจคเฉ‹เจ‚ เจฌเจพเจ…เจฆ, เจฌเฉเจฐเจพเจŠเจœเจผเจฐ เจœเจพเจตเจพเจธเจ•เฉเจฐเจฟเจชเจŸ เจ•เฉ‹เจก เจจเฉ‚เฉฐ เจšเจฒเจพเจ‰เจฃเจพ เจธเจผเฉเจฐเฉ‚ เจ•เจฐ เจฆเฉ‡เจตเฉ‡เจ—เจพ, เจเจ‚เจŸเจฐเฉ€ เจชเฉเจ†เจ‡เฉฐเจŸ JS เจซเจพเจˆเจฒ เจจเจพเจฒ เจธเจผเฉเจฐเฉ‚ เจ•เจฐเจฆเฉ‡ เจนเฉ‹เจ: 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. "PLAY" เจฌเจŸเจจ เจ•เจฒเจฟเฉฑเจ• เจนเฉˆเจ‚เจกเจฒเจฐ เจจเฉ‚เฉฐ เจธเฉˆเจŸ เจ…เจช เจ•เจฐเจจเจพเฅค เจœเจฆเฉ‹เจ‚ เจฌเจŸเจจ เจฆเจฌเจพเจ‡เจ† เจœเจพเจ‚เจฆเจพ เจนเฉˆ, เจ•เฉ‹เจก เจ—เฉ‡เจฎ เจจเฉ‚เฉฐ เจธเจผเฉเจฐเฉ‚ เจ•เจฐเจฆเจพ เจนเฉˆ เจ…เจคเฉ‡ เจธเจฐเจตเจฐ เจจเฉ‚เฉฐ เจฆเฉฑเจธเจฆเจพ เจนเฉˆ เจ•เจฟ เจ…เจธเฉ€เจ‚ เจ–เฉ‡เจกเจฃ เจฒเจˆ เจคเจฟเจ†เจฐ เจนเจพเจ‚เฅค

เจธเจพเจกเฉ‡ เจ•เจฒเจพเจ‡เฉฐเจŸ-เจธเจฐเจตเจฐ เจคเจฐเจ• เจฆเจพ เจฎเฉเฉฑเจ– "เจฎเฉ€เจŸ" เจ‰เจนเจจเจพเจ‚ เจซเจพเจˆเจฒเจพเจ‚ เจตเจฟเฉฑเจš เจนเฉˆ เจœเฉ‹ เจซเจพเจˆเจฒ เจฆเฉเจ†เจฐเจพ เจ†เจฏเจพเจค เจ•เฉ€เจคเฉ€เจ†เจ‚ เจ—เจˆเจ†เจ‚ เจธเจจ 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 ms (30 เจชเฉเจฐเจคเฉ€ เจธเจ•เจฟเฉฐเจŸ) เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจ—เฉ‡เจฎ เจ…เจชเจกเฉ‡เจŸ เจชเฉเจฐเจพเจชเจค เจนเฉ‹เจตเฉ‡เจ—เจพ:

.io เจธเจผเฉˆเจฒเฉ€ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจฎเจฒเจŸเฉ€เจชเจฒเฉ‡เจ…เจฐ เจตเฉˆเฉฑเจฌ เจ—เฉ‡เจฎ เจฌเจฃเจพเจ‰เจฃเจพ
เจฌเจฆเจ•เจฟเจธเจฎเจคเฉ€ เจจเจพเจฒ, เจ•เฉเจ เจตเฉ€ เจธเฉฐเจชเฉ‚เจฐเจจ เจจเจนเฉ€เจ‚ เจนเฉˆ. เจ‡เฉฑเจ• เจนเฉ‹เจฐ เจฏเจฅเจพเจฐเจฅเจตเจพเจฆเฉ€ เจคเจธเจตเฉ€เจฐ เจนเฉ‹เจตเฉ‡เจ—เฉ€:
.io เจธเจผเฉˆเจฒเฉ€ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจฎเจฒเจŸเฉ€เจชเจฒเฉ‡เจ…เจฐ เจตเฉˆเฉฑเจฌ เจ—เฉ‡เจฎ เจฌเจฃเจพเจ‰เจฃเจพ
เจœเจฆเฉ‹เจ‚ เจฒเฉ‡เจŸเฉˆเจ‚เจธเฉ€ เจฆเฉ€ เจ—เฉฑเจฒ เจ†เจ‰เจ‚เจฆเฉ€ เจนเฉˆ เจคเจพเจ‚ เจ‡เฉฑเจ• เจญเฉ‹เจฒเจพ เจ…เจฎเจฒ เจธเจญ เจคเฉ‹เจ‚ เจฎเจพเฉœเจพ เจนเฉเฉฐเจฆเจพ เจนเฉˆเฅค เจœเฉ‡เจ•เจฐ เจ•เฉ‹เจˆ เจ—เฉ‡เจฎ เจ…เฉฑเจชเจกเฉ‡เจŸ 50ms เจฆเฉ‡เจฐเฉ€ เจจเจพเจฒ เจชเฉเจฐเจพเจชเจค เจนเฉเฉฐเจฆเจพ เจนเฉˆ, เจคเจพเจ‚ เจ—เจพเจนเจ• เจนเฉŒเจฒเฉ€ เจนเฉ‹ เจ—เจฟเจ† เจนเฉˆ เจ‡เฉฑเจ• เจตเจพเจงเฉ‚ 50ms เจฆเฉเจ†เจฐเจพ เจ•เจฟเจ‰เจ‚เจ•เจฟ เจ‡เจน เจ…เจœเฉ‡ เจตเฉ€ เจชเจฟเจ›เจฒเฉ‡ เจ…เจชเจกเฉ‡เจŸ เจคเฉ‹เจ‚ เจ—เฉ‡เจฎ เจธเจŸเฉ‡เจŸ เจจเฉ‚เฉฐ เจชเฉ‡เจธเจผ เจ•เจฐ เจฐเจฟเจนเจพ เจนเฉˆเฅค เจคเฉเจธเฉ€เจ‚ เจ•เจฒเจชเจจเจพ เจ•เจฐ เจธเจ•เจฆเฉ‡ เจนเฉ‹ เจ•เจฟ เจ‡เจน เจ–เจฟเจกเจพเจฐเฉ€ เจฒเจˆ เจ•เจฟเฉฐเจจเจพ เจ…เจธเฉเจตเจฟเจงเจพเจœเจจเจ• เจนเฉˆ: เจฎเจจเจฎเจพเจจเฉ‡ เจฎเฉฐเจฆเฉ€ เจฆเฉ‡ เจ•เจพเจฐเจจ, เจ–เฉ‡เจก เจเจŸเจ•เฉ‡เจฆเจพเจฐ เจ…เจคเฉ‡ เจ…เจธเจฅเจฟเจฐ เจœเจพเจชเจฆเฉ€ เจนเฉˆเฅค

7.2 เจธเฉเจงเจฐเฉ€ เจ•เจฒเจพเจ‡เฉฐเจŸ เจธเจŸเฉ‡เจŸ

เจ…เจธเฉ€เจ‚ เจญเฉ‹เจฒเฉ‡เจชเจฃ เจจเฉ‚เฉฐ เจฒเจพเจ—เฉ‚ เจ•เจฐเจจ เจฒเจˆ เจ•เฉเจ เจธเฉเจงเจพเจฐ เจ•เจฐเจพเจ‚เจ—เฉ‡เฅค เจชเจนเจฟเจฒเจพเจ‚, เจ…เจธเฉ€เจ‚ เจตเจฐเจคเจฆเฉ‡ เจนเจพเจ‚ เจฐเฉˆเจ‚เจกเจฐเจฟเฉฐเจ— เจฆเฉ‡เจฐเฉ€ 100 ms เจฆเฉเจ†เจฐเจพ เจ‡เจธเจฆเจพ เจฎเจคเจฒเจฌ เจนเฉˆ เจ•เจฟ เจ•เจฒเจพเจ‡เฉฐเจŸ เจฆเฉ€ "เจฎเฉŒเจœเฉ‚เจฆเจพ" เจธเจฅเจฟเจคเฉ€ เจนเจฎเฉ‡เจธเจผเจพเจ‚ เจธเจฐเจตเจฐ 'เจคเฉ‡ เจ—เฉ‡เจฎ เจธเจŸเฉ‡เจŸ เจคเฉ‹เจ‚ 100ms เจชเจฟเฉฑเจ›เฉ‡ เจนเฉ‹เจตเฉ‡เจ—เฉ€เฅค เจ‰เจฆเจพเจนเจฐเจจ เจฒเจˆ, เจœเฉ‡เจ•เจฐ เจธเจฐเจตเจฐ เจฆเจพ เจธเจฎเจพเจ‚ เจนเฉˆ 150, เจซเจฟเจฐ เจ•เจฒเจพเจ‡เฉฐเจŸ เจ‰เจธ เจธเจฅเจฟเจคเฉ€ เจจเฉ‚เฉฐ เจฐเฉˆเจ‚เจกเจฐ เจ•เจฐเฉ‡เจ—เจพ เจœเจฟเจธ เจตเจฟเฉฑเจš เจธเจฐเจตเจฐ เจ‰เจธ เจธเจฎเฉ‡เจ‚ เจธเฉ€ 50:

.io เจธเจผเฉˆเจฒเฉ€ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจฎเจฒเจŸเฉ€เจชเจฒเฉ‡เจ…เจฐ เจตเฉˆเฉฑเจฌ เจ—เฉ‡เจฎ เจฌเจฃเจพเจ‰เจฃเจพ
เจ‡เจน เจธเจพเจจเฉ‚เฉฐ เจ—เฉ‡เจฎ เจ…เฉฑเจชเจกเฉ‡เจŸ เจฆเฉ‡ เจ…เจฃเจชเจ›เจพเจคเฉ‡ เจธเจฎเฉ‡เจ‚ เจคเฉ‹เจ‚ เจฌเจšเจฃ เจฒเจˆ 100ms เจฌเจซเจฐ เจฆเจฟเฉฐเจฆเจพ เจนเฉˆ:

.io เจธเจผเฉˆเจฒเฉ€ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจฎเจฒเจŸเฉ€เจชเจฒเฉ‡เจ…เจฐ เจตเฉˆเฉฑเจฌ เจ—เฉ‡เจฎ เจฌเจฃเจพเจ‰เจฃเจพ
เจ‡เจธ เจฆเฉ€ เจ•เฉ€เจฎเจค เจธเจฅเจพเจˆ เจนเฉ‹เจตเฉ‡เจ—เฉ€ เจ‡เฉฐเจชเฉเฉฑเจŸ เจฒเฉˆเจ— 100 ms เจฆเฉเจ†เจฐเจพ เจ‡เจน เจจเจฟเจฐเจตเจฟเจ˜เจจ เจ—เฉ‡เจฎเจชเจฒเฉ‡ เจฒเจˆ เจ‡เฉฑเจ• เจฎเจพเจฎเฉ‚เจฒเฉ€ เจ•เฉเจฐเจฌเจพเจจเฉ€ เจนเฉˆ - เจœเจผเจฟเจ†เจฆเจพเจคเจฐ เจ–เจฟเจกเจพเจฐเฉ€ (เจ–เจพเจธ เจ•เจฐเจ•เฉ‡ เจ†เจฎ เจฒเฉ‹เจ•) เจ‡เจธ เจฆเฉ‡เจฐเฉ€ เจตเฉฑเจฒ เจงเจฟเจ†เจจ เจจเจนเฉ€เจ‚ เจฆเฉ‡เจฃเจ—เฉ‡เฅค เจฒเฉ‹เจ•เจพเจ‚ เจฒเจˆ 100ms เจฒเฉ‡เจŸเฉˆเจ‚เจธเฉ€ เจจเฉ‚เฉฐ เจ…เจชเฉเจฐเจฎเจพเจฃเจฟเจค เจฒเฉ‡เจŸเฉˆเจ‚เจธเฉ€ เจจเจพเจฒ เจ–เฉ‡เจกเจฃ เจจเจพเจฒเฉ‹เจ‚ เจตเจฟเจตเจธเจฅเจฟเจค เจ•เจฐเจจเจพ เจฌเจนเฉเจค เจธเฉŒเจ–เจพ เจนเฉˆเฅค

เจ…เจธเฉ€เจ‚ เจ‡เจ• เจนเฉ‹เจฐ เจคเจ•เจจเฉ€เจ• เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐ เจธเจ•เจฆเฉ‡ เจนเจพเจ‚ เจœเจฟเจธ เจจเฉ‚เฉฐ เจ•เจฟเจนเจพ เจœเจพเจ‚เจฆเจพ เจนเฉˆ "เจ—เจพเจนเจ•-เจชเจพเจธเฉ‡ เจฆเฉ€ เจญเจตเจฟเฉฑเจ–เจฌเจพเจฃเฉ€", เจœเฉ‹ เจธเจฎเจเฉ€ เจ—เจˆ เจฒเฉ‡เจŸเฉˆเจ‚เจธเฉ€ เจจเฉ‚เฉฐ เจ˜เจŸเจพเจ‰เจฃ เจฆเจพ เจตเจงเฉ€เจ† เจ•เฉฐเจฎ เจ•เจฐเจฆเจพ เจนเฉˆ, เจชเจฐ เจ‡เจธ เจชเฉ‹เจธเจŸ เจตเจฟเฉฑเจš เจšเจฐเจšเจพ เจจเจนเฉ€เจ‚ เจ•เฉ€เจคเฉ€ เจœเจพเจตเฉ‡เจ—เฉ€เฅค

เจ‡เฉฑเจ• เจนเฉ‹เจฐ เจธเฉเจงเจพเจฐ เจœเฉ‹ เจ…เจธเฉ€เจ‚ เจตเจฐเจคเจฆเฉ‡ เจนเจพเจ‚ เจ‰เจน เจนเฉˆ เจฐเฉ‡เจ–เจฟเจ• เจ‡เฉฐเจŸเจฐเจชเฉ‹เจฒเฉ‡เจธเจผเจจ. เจฐเฉˆเจ‚เจกเจฐเจฟเฉฐเจ— เจฒเฉˆเจ— เจฆเฉ‡ เจ•เจพเจฐเจจ, เจ…เจธเฉ€เจ‚ เจ†เจฎ เจคเฉŒเจฐ 'เจคเฉ‡ เจ•เจฒเจพเจ‡เฉฐเจŸ เจตเจฟเฉฑเจš เจฎเฉŒเจœเฉ‚เจฆเจพ เจธเจฎเฉ‡เจ‚ เจคเฉ‹เจ‚ เจ˜เฉฑเจŸเฉ‹-เจ˜เฉฑเจŸ เจ‡เฉฑเจ• เจ…เฉฑเจชเจกเฉ‡เจŸ เจ…เฉฑเจ—เฉ‡ เจนเฉเฉฐเจฆเฉ‡ เจนเจพเจ‚เฅค เจœเจฆเฉ‹เจ‚ เจฌเฉเจฒเจพเจ‡เจ† เจ—เจฟเจ† 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(). เจœเจฟเจตเฉ‡เจ‚ เจ•เจฟ เจ…เจธเฉ€เจ‚ เจชเจนเจฟเจฒเจพเจ‚ เจฆเฉ‡เจ–เจฟเจ† เจธเฉ€, เจนเจฐเฉ‡เจ• เจ—เฉ‡เจฎ เจ…เจชเจกเฉ‡เจŸ เจตเจฟเฉฑเจš เจ‡เฉฑเจ• เจธเจฐเจตเจฐ เจŸเจพเจˆเจฎเจธเจŸเฉˆเจ‚เจช เจธเจผเจพเจฎเจฒ เจนเฉเฉฐเจฆเจพ เจนเฉˆเฅค เจ…เจธเฉ€เจ‚ เจธเจฐเจตเจฐ เจฆเฉ‡ เจชเจฟเฉฑเจ›เฉ‡ เจšเจฟเฉฑเจคเจฐ เจจเฉ‚เฉฐ 100ms เจฐเฉˆเจ‚เจกเจฐ เจ•เจฐเจจ เจฒเจˆ เจฐเฉˆเจ‚เจกเจฐ เจฒเฉ‡เจŸเฉˆเจ‚เจธเฉ€ เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐเจจเจพ เจšเจพเจนเฉเฉฐเจฆเฉ‡ เจนเจพเจ‚, เจชเจฐ เจธเจพเจจเฉ‚เฉฐ เจธเจฐเจตเจฐ 'เจคเฉ‡ เจฎเฉŒเจœเฉ‚เจฆเจพ เจธเจฎเจพเจ‚ เจ•เจฆเฉ‡ เจจเจนเฉ€เจ‚ เจชเจคเจพ เจนเฉ‹เจตเฉ‡เจ—เจพ, เจ•เจฟเจ‰เจ‚เจ•เจฟ เจ…เจธเฉ€เจ‚ เจจเจนเฉ€เจ‚ เจœเจพเจฃ เจธเจ•เจฆเฉ‡ เจ•เจฟ เจ•เจฟเจธเฉ‡ เจตเฉ€ เจ…เฉฑเจชเจกเฉ‡เจŸ เจจเฉ‚เฉฐ เจธเจพเจกเฉ‡ เจคเฉฑเจ• เจชเจนเฉเฉฐเจšเจฃ เจตเจฟเฉฑเจš เจ•เจฟเฉฐเจจเจพ เจธเจฎเจพเจ‚ เจฒเฉฑเจ—เจพเฅค เจ‡เฉฐเจŸเจฐเจจเฉˆเจŸ เจ…เจชเฉเจฐเจคเฉฑเจ– เจนเฉˆ เจ…เจคเฉ‡ เจ‡เจธเจฆเฉ€ เจ—เจคเฉ€ เจฌเจนเฉเจค เจฌเจฆเจฒ เจธเจ•เจฆเฉ€ เจนเฉˆ!

เจ‡เจธ เจธเจฎเฉฑเจธเจฟเจ† เจจเฉ‚เฉฐ เจนเฉฑเจฒ เจ•เจฐเจจ เจฒเจˆ, เจ…เจธเฉ€เจ‚ เจ‡เฉฑเจ• เจตเจพเจœเจฌ เจ…เจจเฉเจฎเจพเจจ เจฆเฉ€ เจตเจฐเจคเฉ‹เจ‚ เจ•เจฐ เจธเจ•เจฆเฉ‡ เจนเจพเจ‚: เจ…เจธเฉ€เจ‚ เจ†เจ“ เจฆเจฟเจ–เจพเจ‰เจ‚เจฆเฉ‡ เจนเจพเจ‚ เจ•เจฟ เจชเจนเจฟเจฒเจพ เจ…เจชเจกเฉ‡เจŸ เจคเฉเจฐเฉฐเจค เจ† เจ—เจฟเจ†. เจœเฉ‡ เจ‡เจน เจธเฉฑเจš เจธเฉ€, เจคเจพเจ‚ เจธเจพเจจเฉ‚เฉฐ เจ‰เจธ เจ–เจพเจธ เจชเจฒ 'เจคเฉ‡ เจธเจฐเจตเจฐ เจฆเจพ เจธเจฎเจพเจ‚ เจชเจคเจพ เจนเฉ‹เจตเฉ‡เจ—เจพ! เจ…เจธเฉ€เจ‚ เจธเจฐเจตเจฐ เจŸเจพเจˆเจฎเจธเจŸเฉˆเจ‚เจช เจจเฉ‚เฉฐ เจธเจŸเฉ‹เจฐ เจ•เจฐเจฆเฉ‡ เจนเจพเจ‚ 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 'เจคเฉ‡ GitHub.

เจญเจพเจ— 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-dev-midleware เจธเจพเจกเฉ‡ เจตเจฟเจ•เจพเจธ เจชเฉˆเจ•เฉ‡เจœเจพเจ‚ เจจเฉ‚เฉฐ เจ†เจŸเฉ‹เจฎเฉˆเจŸเจฟเจ•เจฒเฉ€ เจฆเฉเจฌเจพเจฐเจพ เจฌเจฃเจพเจ‰เจฃ เจฒเจˆ, เจœเจพเจ‚
  • เจ‡เฉฑเจ• เจซเฉ‹เจฒเจกเจฐ เจจเฉ‚เฉฐ เจธเจฅเจฟเจฐ เจฐเฉ‚เจช เจตเจฟเฉฑเจš เจŸเฉเจฐเจพเจ‚เจธเจซเจฐ เจ•เจฐเฉ‹ 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 เจ‡เฉฑเจ• เจตเจธเจคเฉ‚ เจนเฉˆ เจœเฉ‹ เจชเจฒเฉ‡เจ…เจฐ ID เจจเฉ‚เฉฐ เจธเจพเจ•เจŸ เจจเจพเจฒ เจœเฉ‹เฉœเจฆเฉ€ เจนเฉˆ เจœเฉ‹ เจชเจฒเฉ‡เจ…เจฐ เจจเจพเจฒ เจœเฉเฉœเจฟเจ† เจนเฉ‹เจ‡เจ† เจนเฉˆเฅค เจ‡เจน เจธเจพเจจเฉ‚เฉฐ เจธเจฎเฉ‡เจ‚ เจฆเฉ‡ เจจเจพเจฒ เจ‰เจนเจจเจพเจ‚ เจฆเฉ‡ เจชเจฒเฉ‡เจ…เจฐ เจ†เจˆเจกเฉ€ เจฆเฉเจ†เจฐเจพ เจธเจพเจ•เจŸเจพเจ‚ เจคเฉฑเจ• เจชเจนเฉเฉฐเจš เจ•เจฐเจจ เจฆเฉ€ เจ†เจ—เจฟเจ† เจฆเจฟเฉฐเจฆเจพ เจนเฉˆเฅค
  • 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 เจ˜เฉœเฉ€ เจšเฉฑเจ•เจฐ/s เจนเฉˆ (เจ…เจธเฉ€เจ‚ เจชเจนเจฟเจฒเฉ‡ เจญเจพเจ— เจตเจฟเฉฑเจš เจ˜เฉœเฉ€ เจฆเฉ€ เจฌเจพเจฐเฉฐเจฌเจพเจฐเจคเจพ เจฌเจพเจฐเฉ‡ เจ—เฉฑเจฒ เจ•เฉ€เจคเฉ€ เจนเฉˆ)เฅค

เจธเจฟเจฐเจซเจผ เจ—เฉ‡เจฎ เจ…เฉฑเจชเจกเฉ‡เจŸ เจ•เจฟเจ‰เจ‚ เจญเฉ‡เจœเฉ‹ เจธเจฎเฉ‡เจ‚ เจฆเฉเจ†เจฐเจพ ? เจšเฉˆเจจเจฒ เจจเฉ‚เฉฐ เจฌเจšเจพเจ‰เจฃ เจฒเจˆเฅค 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 เจ—เฉ‡เจฎ เจฌเจฃเจพเจ“!

เจธเจพเจฐเจพ เจ‰เจฆเจพเจนเจฐเจจ เจ•เฉ‹เจก เจ“เจชเจจ เจธเฉ‹เจฐเจธ เจนเฉˆ เจ…เจคเฉ‡ เจ‡เจธ 'เจคเฉ‡ เจชเฉ‹เจธเจŸ เจ•เฉ€เจคเจพ เจ—เจฟเจ† เจนเฉˆ GitHub.

เจธเจฐเฉ‹เจค: www.habr.com

เจ‡เฉฑเจ• เจŸเจฟเฉฑเจชเจฃเฉ€ เจœเฉ‹เฉœเฉ‹