Fausia se ta'aloga i luga ole laiga multiplayer i le ituaiga .io

Fausia se ta'aloga i luga ole laiga multiplayer i le ituaiga .io
Fa'ailoa mai ile 2015 Akara.io na avea ma tupuaga o se ituaiga fou taaloga.io, o lona lauiloa ua tupu tele talu mai lena taimi. Ua ou oo i le si'itia o le lauiloa o taaloga .io a'u lava ia: i le tolu tausaga ua tuana'i, I faia ma faatau atu taaloga e lua i lenei ituaiga..

Afai e te le'i fa'alogo muamua i nei ta'aloga, e leai se totogi, ta'aloga i luga ole laiga multiplayer e faigofie ona ta'alo (leai se tala e mana'omia). E masani ona latou fa'afeto'ai le tele o tama ta'a'alo fa'afeagai i le malae e tasi. Isi ta'aloga ta'uta'ua .io: Slither.io и Diep.io.

I lenei pou o le a tatou iloa pe faapefea fatu se taaloga .io mai le sasa. Ina ia faia lenei mea, naʻo le malamalama o Javascript o le a lava: e tatau ona e malamalama i mea e pei o le syntax ES6, upu autu this и folafolaga. E tusa lava pe e te le iloa lelei le Javascript, e mafai lava ona e malamalama i le tele o le pou.

Faataitaiga o se taaloga .io

Mo fesoasoani a'oa'oga o le a matou fa'asino i ai fa'ata'ita'iga ta'aloga .io. Taumafai e ta'alo!

Fausia se ta'aloga i luga ole laiga multiplayer i le ituaiga .io
O le taʻaloga e fai si faigofie: e te pulea se vaʻa i se malae ma isi tagata taʻalo. O lau va'a e otometi lava ona fa'a'a'a'ia fa'apolokalame ma e taumafai e lavea isi ta'a'alo a'o 'alo'ese mai a latou fa'ata.

1. Va'aiga puupuu/fa'atulagaina o galuega

Laʻasaga la'u mai le fa'ailoga puna faataitaiga taaloga ina ia mafai ona e mulimuli mai ia te au.

O le faʻataʻitaʻiga e faʻaaogaina mea nei:

  • Faaali o le taʻiala sili ona lauiloa i luga o le upega tafaʻilagi mo Node.js e faʻatautaia le upega tafaʻilagi a le taaloga.
  • socket.io — faletusi websocket mo le fesuiaiga o faamatalaga i le va o le browser ma le server.
  • Webpack - pule o le module. E mafai ona e faitau pe aisea e faʻaaoga ai Webpack iinei.

O le mea lea e foliga mai ai le fausaga o le lisi o galuega:

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

lautele/

O loʻo i totonu o le faila mea uma public/ o le a fa'asalalauina fa'amau e le 'au'aunaga. IN public/assets/ o lo'o i ai ata na fa'aaogaina e la matou poloketi.

src /

O lo'o i totonu o le fa'ailoga mea uma src/. Suafa client/ и server/ tautala mo i latou lava ma shared/ o lo'o i ai se faila tumau e fa'aulufale mai e le kalani ma le server.

2. Fonotaga/poloketi tapula'a

E pei ona taʻua i luga, matou te faʻaogaina se pule o le module e fausia ai le poloketi Webpack. Sei o tatou vaʻai i la matou faʻatulagaga Webpack:

webpack.common.js:

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

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

O laina sili ona taua iinei o mea nei:

  • src/client/index.js o le nofoaga e ulufale ai le tagata o tausia Javascript (JS). Webpack o le a amata mai iinei ma toe suʻe isi faila faʻaulufale mai.
  • O le JS o le matou Webpack build o le a maua i totonu o le lisi dist/. O le a ou taʻua lenei faila o le matou JS afifi.
  • Matou te faʻaaogaina Papelu, aemaise le faatulagaga @babel/preset-env e fa'aliliu le tatou JS code mo su'esu'ega tuai.
  • Matou te faʻaogaina se faʻapipiʻi e aveese uma CSS faʻasino e JS faila ma tuʻufaʻatasia i latou i se nofoaga e tasi. O le a ou faaigoaina o matou CSS afifi.

Atonu na e maitauina igoa uiga ese o faila faila '[name].[contenthash].ext'. O loo i ai sui igoa faila Upega tafaʻilagi: [name] o le a suia i le igoa o le mea e tuʻuina atu (i la matou tulaga o le game), ma [contenthash] o le a suia i se hash o le faila faila. Matou te faia lenei mea fa'alelei le poloketi mo le hashing - e mafai ona matou ta'u atu i tagata su'esu'e e teu a matou afifi JS e le gata ona afai e sui se afifi, e sui foi lona igoa faila (suiga contenthash). O le taunuuga mae'a o le igoa faila o le vaaiga game.dbeee76e91a97d0c7207.js.

faila webpack.common.js - O le faila fa'avae fa'avae lea matou te fa'aulufale mai i totonu o le atina'e ma fa'amae'aina le fa'atulagaina o galuega. Mo se faʻataʻitaʻiga, o le faʻatulagaina lea o le atinaʻe:

webpack.dev.js

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

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

Mo le lelei, matou te faʻaaogaina i le faagasologa o le atinaʻe webpack.dev.js, ma sui i webpack.prod.js, ia fa'amalieina le tele o afifi pe a fa'apipi'i i le gaosiga.

Seti fa'apitonu'u

Ou te fautuaina le faʻapipiʻiina o le poloketi i luga o lau masini faʻapitonuʻu ina ia mafai ona e mulimuli i laasaga o loʻo lisiina i lenei pou. E faigofie le seti: muamua, e tatau ona i ai le faiga Node и NPM. Sosoo ai e tatau ona e faia

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

ma ua e sauni e alu! Ina ia amata le server atinae, na o le tamoe

$ npm run develop

ma alu i lau 'upega tafaʻilagi localhost: 3000. O le a otometi lava ona toe fausia e le server development ia afifi JS ma CSS pe a o'o mai suiga fa'ailoga - na'o le toe fa'afouina o le itulau e va'ai i suiga uma!

3. Mea e ulufale ai tagata fa'atau

Se'i tatou o ifo i le ta'aloga lava ia. Muamua tatou te manaʻomia se itulau index.html, pe a e asiasi i le 'upega tafaʻilagi, o le a faʻapipiʻi muamua e le browser. O la matou itulau o le a fai si faigofie:

index.html

O se fa'ata'ita'iga .io ta'aloga  TALI

O lenei faʻataʻitaʻiga faʻataʻitaʻiga ua faʻafaigofieina laʻititi mo le manino, ma o le a ou faia tutusa i le tele o isi faʻataʻitaʻiga i le pou. E mafai ona e va'ai i le code atoa i Github.

E iai sau sikaipi:

  • HTML5 Elemene tapoleni (<canvas>), lea o le a matou faʻaaogaina e tuʻuina atu ai le taʻaloga.
  • <link> e fa'aopoopo le matou pusa CSS.
  • <script> e fa'aopoopo le matou Javascript package.
  • Menu autu ma le username <input> ma le faamau “TALI” (<button>).

O le taimi lava e utaina ai le itulau autu, o le a amata e le browser ona faʻaogaina le Javascript code, amata i le faila JS faila: 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);
  };
});

Atonu e foliga faigata lenei mea, ae o le mea moni e le tele se mea e tupu iinei:

  1. Auina mai nisi faila JS.
  2. Fa'aulufale mai CSS (ina ia iloa e le Webpack e fa'aofi i totonu o la matou pusa CSS).
  3. Tatala connect() e faʻavae se fesoʻotaʻiga i le server ma amata downloadAssets() e la'u mai ata e mana'omia e fa'atino ai le ta'aloga.
  4. A mae'a le laasaga 3 o lo'o fa'aalia le lisi autu (playMenu).
  5. Fa'atulaga le "PLAY" kiliki le fa'amau. A oomi le ki, o le code e amataina le taaloga ma taʻu atu i le server ua matou sauni e taʻalo.

O le "aano o manufasi" autu o le matou client-server logic o loʻo i totonu o faila na faʻaulufale mai e le faila index.js. O lea la o le a tatou vaavaai atu ia i latou uma i le faasologa.

4. Fetufaaiga o fa'amaumauga a tagata o tausia

I lenei taʻaloga matou te faʻaogaina se faletusi lauiloa e fesoʻotaʻi ma le server socket.io. Socket.io o loʻo iai le lagolago faʻapipiʻi Upega tafaʻilagi, lea e fetaui lelei mo fesoʻotaʻiga e lua: e mafai ona matou lafoina feʻau i le 'auʻaunaga и e mafai e le 'auʻaunaga ona lafo mai ni feʻau ia i matou i luga o le fesoʻotaʻiga tutusa.

E tasi le matou faila src/client/networking.jso ai na te tausia tagata uma feso'ota'iga ma le 'au'aunaga:

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);
};

O lenei code e fa'apu'upu'u teisi foi mo le manino.

E tolu mea taua e tupu i lenei faila:

  • Matou te taumafai e faʻafesoʻotaʻi i le server. connectedPromise na'o le fa'atagaina pe a matou fa'atuina se feso'ota'iga.
  • Afai e manuia le feso'ota'iga, matou te resitalaina galuega toe fo'i (processGameUpdate() и onGameOver()) mo feʻau e mafai ona matou mauaina mai le 'auʻaunaga.
  • Matou te auina atu i fafo play() и updateDirection()ina ia mafai e isi faila ona faʻaaogaina.

5. Fa'asinomaga Client

Ua oo i le taimi e faaali ai le ata i luga o le lau!

...ae tatou te leʻi faia lenei mea, e manaʻomia ona tatou siiina uma ata (punaoa) e manaʻomia mo lenei. Sei o tatou tusi se pule o punaoa:

aseta.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];

O le puleaina o punaoa e le faigata tele ona faʻatinoina! O le manatu autu o le teuina o se mea assets, lea o le a fusifusia ai le faila igoa ki i le mea taua Image. A uta le punaoa, matou te teuina i se mea assets mo le mauaina vave i le lumanaʻi. O afea e faʻatagaina ai le laʻuina o punaoa taʻitasi (o lona uiga, o le a download uma punaoa), matou te faatagaina downloadPromise.

A uma ona la'uina mai punaoa, e mafai ona e amata fa'aliliuina. E pei ona taʻua muamua, e tusi i luga o se itulau web matou te faʻaaogaina HTML5 tapoleni (<canvas>). O la matou taʻaloga e faigofie tele, o lea e naʻo matou manaʻomia le tuʻuina atu o mea nei:

  1. Talaaga
  2. Vaa tagata taalo
  3. O isi tagata taaalo i le taaloga
  4. atigi atigi

O vaega taua nei src/client/render.js, lea e tusi tonu ai vaega e fa o loo lisiina i luga:

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);
}

E faapuupuuina foi lenei code mo le manino.

render() o le galuega autu o lenei faila. startRendering() и stopRendering() pulea le fa'agaoioia o le fa'asologa o fa'aliliuga ile 60 FPS.

Fa'atinoga fa'apitoa o galuega fesoasoani fesoasoani ta'ito'atasi (mo se fa'ata'ita'iga renderBullet()) e le taua tele, ae o se tasi lea o faʻataʻitaʻiga faigofie:

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,
  );
}

Manatua o loʻo matou faʻaaogaina le metotia getAsset(), lea sa vaaia muamua i asset.js!

Afai e te fiafia e su'esu'e isi galuega fesoasoani fesoasoani, ona faitau lea o le vaega o totoe src/client/render.js.

6. Fa'asoa mai tagata fa'atau

Ua oo i le taimi e fai ai se taaloga ta'alo! O le faʻatonuga o le a faigofie tele: e sui le itu o le gaioiga, e mafai ona e faʻaogaina le kiore (i luga o se komepiuta) pe paʻi i le lau (i luga o se masini feaveaʻi). Ina ia faʻatinoina lenei mea o le a matou lesitala Faʻalogologo Mea na Tutupu mo mea o le Isu ma le Pa'i.
O le a taulimaina nei mea uma 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() o Event Listeners e valaau updateDirection() (o networking.js) pe a tupu se mea faʻapipiʻi (mo se faʻataʻitaʻiga, pe a lue le isumu). updateDirection() e feagai ma le fefaʻatauaʻiga o feʻau ma le 'auʻaunaga, lea e faʻagasolo ai le mea na tupu ma faʻafouina le taʻaloga e tusa ai.

7. Tulaga Client

O lenei vaega e sili ona faigata i le vaega muamua o le pou. Aua e te lotovaivai pe afai e te le malamalama i le taimi muamua e te faitau ai! E mafai fo'i ona e faamisi ma toe sau i ai mulimuli ane.

O le vaega mulimuli o le paso e mana'omia e fa'atumu ai le code client-server o le tulaga. Manatua le snippet code mai le Client Rendering vaega?

render.js

import { getCurrentState } from './state';

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

  // Do the rendering
  // ...
}

getCurrentState() e tatau ona mafai ona tuʻuina mai ia i matou le tulaga o taʻaloga o loʻo i ai nei i le kalani i soo se taimi fa'avae i fa'afouga na maua mai le 'au'aunaga. O se fa'ata'ita'iga lea o se fa'afouga ta'aloga e ono lafo mai e le 'au'aunaga:

{
  "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
    }
  ]
}

O fa'afouga ta'aloga ta'itasi o lo'o iai fa'ato'aga tutusa e lima:

  • t: Fa'ailoga taimi o lo'o ta'u mai ai le taimi na faia ai lenei fa'afouga.
  • me: Fa'amatalaga e uiga i le tagata ta'alo o lo'o mauaina lenei fa'afouga.
  • isi: Se fa'asologa o fa'amatalaga e uiga i isi ta'aalo o lo'o auai i le ta'aloga lava e tasi.
  • pulu: fa'asologa o fa'amatalaga e uiga i projectiles i le ta'aloga.
  • leaderboard: Fa'amatalaga ta'ita'i o lo'o iai nei. Matou te le amanaia i latou i lenei pou.

7.1 Tulaga valea ole tagata fa'atau

Fa'atino fa'avalevalea getCurrentState() e mafai na'o le toe fa'afo'i sa'o mai fa'amatalaga mai le fa'afouga ta'aloga sili ona lata mai.

naive-state.js

let lastGameUpdate = null;

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

export function getCurrentState() {
  return lastGameUpdate;
}

Matagofie ma manino! Ae pe ana faapea e faigofie. O se tasi o mafuaʻaga o lenei faʻatinoga e faʻafitauli: e fa'atapula'aina le fua fa'avaa fa'asolo i le saoasaoa o le uati a le server.

Fua Fa'atatau: numera o fa'avaa (ie vala'au render()) i le sekone, poʻo le FPS. O ta'aloga e masani ona taumafai e ausia le 60 FPS.

Fua Fa'ailoga: Ole taimi e lafo ai e le server fa'afouga ta'aloga i tagata fa'atau. E masani ona maualalo ifo nai lo le fua fa'avaa. I la matou ta'aloga, e tamo'e le server i le 30 ticks i le sekone.

Afai tatou te tuʻuina atu le faʻafouga fou o taʻaloga, ona le mafai lea e le FPS ona sili atu i le 30 ona matou te le maua lava le sili atu i le 30 faʻafouga i le sekone mai le 'auʻaunaga. E tusa lava pe tatou te valaau render() 60 taimi i le sekone, ona toe fai lea o le afa o nei telefoni i le mea lava e tasi, e leai se mea e faia. O le isi faʻafitauli i se faʻatinoga faʻavalevalea o le mea lea e fa'atuai. I le saoasaoa lelei o le Initaneti, o le a maua e le kalani se fa'afouga ta'aloga i le 33 ms (30 i le sekone):

Fausia se ta'aloga i luga ole laiga multiplayer i le ituaiga .io
Ae paga lea, e leai se mea e atoatoa. O se ata sili atu ona moni o le a:
Fausia se ta'aloga i luga ole laiga multiplayer i le ituaiga .io
O se fa'atinoga fa'avalea e sili ona leaga pe a o'o mai i le fa'agasolo. Afai e maua se fa'afouga ta'aloga ma le 50ms tuai, ona ua fa'agesegese le tagata o tausia e se 50ms faaopoopo ona o loʻo faʻaalia pea le taʻaloga mai le faʻafouga muamua. E mafai ona e mafaufauina le faigata o lenei mea mo le tagata taʻalo: ona o le faʻagesegese faʻafuaseʻi, o le taaloga o le a foliga mai e le mautonu ma le mautu.

7.2 Fa'aleleia tulaga o tagata o tausia

O le a matou faia ni faʻaleleia atili i le faʻatinoga faʻavalevalea. Muamua, matou te faʻaaogaina fa'atuai tu'u e 100 ms. O lona uiga o le tulaga "i le taimi nei" o le kalani o le a 100ms i tua atu o le taʻaloga i luga o le server. Mo se faʻataʻitaʻiga, pe afai o le taimi o le server 150, ona tu'uina atu lea e le kalani le tulaga sa i ai le server i le taimi 50:

Fausia se ta'aloga i luga ole laiga multiplayer i le ituaiga .io
E maua mai ai ia i matou se 100ms buffer e ola ai i le taimi le mautonu o faʻafouga taʻaloga:

Fausia se ta'aloga i luga ole laiga multiplayer i le ituaiga .io
O le tau mo lenei mea o le a tumau tu'u fa'aoga e 100 ms. O se taulaga la'ititi lea mo ta'aloga lamolemole - o le tele o ta'aalo (aemaise lava ta'aloga) latou te le'o matauina lenei tuai. E sili atu ona faigofie mo tagata ona fetuutuunai i se 100ms le tumau nai lo le taʻalo ma le le mautonu.

E mafai ona tatou faʻaogaina se isi metotia e taʻua "va'aiga a le tagata fa'atau", lea e faia se galuega lelei e faʻaitiitia ai le le mautonu, ae o le a le talanoaina i lenei pou.

O le isi faʻaleleia atili matou te faʻaaogaina o le feso'ota'iga laina. Ona o le tu'uina atu o le tuai, e masani lava ona tasi le fa'afouga i luma atu o le taimi nei i le kalani. Ina ua valaauina getCurrentState(), e mafai ona tatou faataunuuina feso'ota'iga laina i le va o fa'afouga ta'aloga a'o le'i mae'a le taimi nei i le kalani:

Fausia se ta'aloga i luga ole laiga multiplayer i le ituaiga .io
Ole mea lea e fo'ia ai le fa'afitauli o le fua fa'avaa: e mafai nei ona tatou tu'uina atu fa'avaa tulaga ese i so'o se fua fa'avaa tatou te mana'omia!

7.3 Fa'atino se tulaga fa'aleleia atili o tagata o tausia

Faataitaiga faatinoga i src/client/state.js e fa'aaoga uma le fa'atuai o le tu'uina atu ma le fa'asoa laina, ae e le umi se taimi. Sei o tatou vaevaeina le code i ni vaega se lua. O le mea muamua lenei:

state.js, vaega 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;
}

O le mea muamua e tatau ona e faia o le iloa lea o le mea e fai currentServerTime(). E pei ona tatou vaʻaia muamua, o faʻafouga taʻaloga uma e aofia ai se faʻamaufaʻailoga taimi. Matou te mananaʻo e faʻaoga le tuʻuina atu o le latency e tuʻuina atu ai le ata 100ms i tua o le 'auʻaunaga, ae matou te le iloa lava le taimi nei i luga o le server, aua e le mafai ona matou iloa pe o le a le umi na alu ai mo soʻo se faʻafouga e oʻo mai ia i matou. O le Initaneti e le taumateina ma o lona saoasaoa e mafai ona matua ese!

Ina ia foia lenei faafitauli, e mafai ona tatou faʻaogaina se faʻatatau talafeagai: matou se'i fa'afoliga na o'o mai loa le fa'afouga muamua. Afai e moni lenei mea, ona matou iloa lea o le taimi o le server i lena taimi faapitoa! Matou te teuina le timestamp server i totonu firstServerTimestamp ma laveai i matou lotoifale (client) timestamp i le taimi lava e tasi i totonu gameStart.

Oi, faatali mo sina minute. E le tatau ona i ai se taimi i luga o le server = taimi i luga o le kalani? Aisea tatou te fa'aeseese ai i le va o le "server timestamp" ma le "client timestamp"? O se fesili sili lenei! E aliali mai e le tutusa ia mea. Date.now() o le a toe fa'afo'i fa'ailoga taimi eseese i le kalani ma le 'au'aunaga ma e fa'alagolago lea i mea fa'apitonu'u i nei masini. Aua ne'i manatu o le a tutusa fa'ailoga taimi i masini uma.

O lea ua tatou malamalama i le mea e fai currentServerTime(): e toe foi mai fa'amaufa'ailoga taimi o le taimi fa'aalia o lo'o iai nei. I se isi faaupuga, o le taimi nei o le server (firstServerTimestamp <+ (Date.now() - gameStart)) to'ese le tuai fa'aliliu (RENDER_DELAY).

Se'i o tatou va'ai pe fa'afefea ona tatou taulimaina fa'afouga ta'aloga. A maua se faʻafouga mai le 'auʻaunaga, e taʻua processGameUpdate(), ma matou fa'asaoina le fa'afouga fou i se fa'asologa gameUpdates. Ma, e siaki le faʻaogaina o manatua, matou te aveese uma faʻafouga tuai i fa'afou fa'avaeaua tatou te le toe manaomia.

O le a le "faafouga autu"? Lenei o le faʻafouga muamua matou te maua e ala i le faʻagasolo i tua mai le taimi o loʻo iai nei. Manatua le ata lea?

Fausia se ta'aloga i luga ole laiga multiplayer i le ituaiga .io
O le fa'afouga o le ta'aloga sa'o i le itu agavale o le "Client Render Time" o le fa'afouga fa'avae.

O le a le mea e fa'aoga ai le fa'afouga fa'avae? Aisea e mafai ai ona tatou lafoa'i fa'afouga ile fa'avae? Ina ia malamalama i lenei mea, tatou mulimuli ane sei tatou tilotilo i le faatinoga getCurrentState():

state.js, vaega 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),
    };
  }
}

Matou te taulimaina mataupu e tolu:

  1. base < 0 o lona uiga e leai ni faʻafouga seʻia oʻo i le taimi o le faʻaaliga o loʻo iai nei (silasila i le faʻatinoga i luga getBaseUpdate()). E mafai ona tupu sa'o i le amataga o le ta'aloga ona o le fa'aletonu o le fa'aliliuina. I lenei tulaga, matou te faʻaogaina le faʻafouga aupito lata mai na maua.
  2. base o le fa'afouga aupito lata mai lea ua tatou maua. E ono tupu lenei mea ona o le le lava o feso'ota'iga po'o le leaga o le feso'ota'iga initaneti. I lenei tulaga foi matou te faʻaaogaina le faʻafouga fou ua matou maua.
  3. E i ai le matou fa'afouga a'o le'i mae'a ma le taimi e tu'uina atu ai nei, ina ia mafai fefiloi!

O mea uma o totoe i totonu state.js o se fa'atinoga o fa'atasiga laina e faigofie (ae le manaia) numera. Afai e te manaʻo e suʻesuʻe oe lava ia, ona tatala lea state.js i Github.

Vaega 2. Backend server

I lenei vaega o le a tatou vaʻavaʻai i le Node.js backend o loʻo pulea a tatou fa'ata'ita'iga o se ta'aloga .io.

1. Mea e ulufale ai le server

Ina ia pulea le 'upega tafaʻilagi o le a matou faʻaogaina se taʻutaʻua upega tafaʻilagi mo Node.js taʻua Faaali. O le a fa'apipi'iina e la matou 'au'aunaga fa'ailoga faila src/server/server.js:

server.js, vaega 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}`);

Manatua i le vaega muamua na matou talanoaina Webpack? O le mea lea o le a matou faʻaogaina ai a matou Webpack configurations. O le a matou faʻaaogaina i ni auala se lua:

  • Faʻaaoga webpack-dev-middleware e otometi ona toe fausia a tatou afifi atinae, pe
  • Fa'aliliuina fa'amau se faila dist/, i totonu o le Webpack o le a tusia ai a tatou faila pe a uma le gaosiga o le fausiaina.

O le isi galuega taua server.js e aofia ai le setiina o le server socket.iolea e na'o le feso'ota'i atu i le 'au'aunaga Express:

server.js, vaega 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);
});

A maeʻa ona faʻatūina se socket.io soʻotaga ma le 'auʻaunaga, matou te faʻapipiʻi mea e fai mo le socket fou. O lo'o fa'agasolo e le au fai fa'alavelave fe'au na maua mai tagata fa'atau e ala i le tu'uina atu i se mea e tasi game:

server.js, vaega 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);
}

O loʻo matou fatuina se taʻaloga .io, o lea e naʻo le tasi le kopi matou te manaʻomia Game (“Taaloga”) – e taaalo uma tagata taaalo i le malae e tasi! I le isi vaega o le a tatou vaʻai pe faʻapefea ona galue lenei vasega Game.

2. Ta'aloga ta'aloga

Vasega Game o lo'o i ai le manatu pito sili ona taua a le server-side. E lua ana galuega autu: pulega ta'aalo и fa'ata'ita'iga ta'aloga.

Tatou amata i le galuega muamua - pulea le au taaalo.

game.js, vaega 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);
    }
  }

  // ...
}

I lenei taaloga o le a tatou iloa ai tagata taaalo e ala i le malae id la latou socket socket.io (afai e te le mautonu, ona toe foʻi lea i server.js). Socket.io lava ia e tuʻuina atu soʻo taʻitasi se tulaga ese id, o lea e le tatau ai ona tatou popole i ai. ou te valaau atu ia te ia ID tagata taalo.

Faatasi ai ma lena mea i le mafaufau, seʻi o tatou suʻesuʻeina faʻataʻitaʻiga fesuiaiga i totonu o le vasega Game:

  • sockets o se mea e fusifusia ai le ID tagata ta'alo i le socket e feso'ota'i ma le tagata ta'alo. E mafai ai ona matou maua sockets e latou ID taʻaloga i le taimi.
  • players o se mea faitino e fusifusia ai le ID tagata taʻalo i le code> Mea taʻalo

bullets o se seti o mea faitino Bullet, e leai se fa'atonuga fa'apitoa.
lastUpdateTime - Ole fa'ailoga taimi lea ole fa'afouga ta'aloga mulimuli. O le a tatou vaʻai pe faʻapefea ona faʻaaogaina vave.
shouldSendUpdate o se fesuiaiga ausilali. O le a tatou vaʻai foʻi i lona faʻaaogaina lata mai.
Metotia addPlayer(), removePlayer() и handleInput() e le manaʻomia ona faʻamatalaina, o loʻo faʻaaogaina i totonu server.js. Afai e te manaʻomia se toe faʻaleleia, toe foʻi i tua teisi maualuga.

Laina mulimuli constructor() amata i luga fa'afouga ta'amilosaga ta'aloga (fa'atasi ai ma le 60 fa'afouga/s):

game.js, vaega 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;
    }
  }

  // ...
}

Metotia update() atonu o lo'o i ai le vaega pito sili ona taua o le manatu o le server-side. Sei o tatou lisi mea uma e fai i le faasologa:

  1. Fa'atatau le taimi dt talu mai le taimi mulimuli update().
  2. Fa'afou ta'iala ta'itasi ma fa'aumatia pe a mana'omia. O le a tatou vaʻai i le faʻatinoga o lenei faʻatinoga mulimuli ane. Mo le taimi nei ua lava lo tatou iloa o lena mea bullet.update() toe fo'i mai true, pe afai e tatau ona faʻaumatia le projectile (na alu o ia i fafo o le malae).
  3. Fa'afou ta'a'alo ta'itasi ma fai se projectile pe a mana'omia. O le a tatou vaʻai foi i lenei faʻatinoga mulimuli ane - player.update() mafai ona toe faafoi se mea Bullet.
  4. Siaki mo fete'ena'iga i le va o projectiles ma tagata ta'alo o lo'o fa'aogaina applyCollisions(), lea e toe fa'afo'i mai ai se fa'aputuga o mata'itusi e taia ai tagata ta'aalo. Mo ta'aloga ta'itasi e toe fa'afo'i mai, matou te fa'aopoopoina le sikoa a le tagata ta'alo na fanaina (fa'aaoga player.onDealtDamage()), ona aveese lea o le projectile mai le laina bullets.
  5. Fa'ailoa ma fa'aumatia tagata ta'aalo uma.
  6. Auina atu se fa'afouga ta'aloga i ta'aalo uma i sekone ta'itasi taimi pe a valaauina update(). O le fesuiaiga o ausilali o loʻo taʻua i luga e fesoasoani ia i tatou e siaki lenei mea shouldSendUpdate. Aua update() valaau 60 taimi / s, matou auina atu faafouga taaloga 30 taimi / s. O lea, taimi ole uati server o le 30 uati taamilosaga / s (sa matou talanoa e uiga i le taimi o le uati i le vaega muamua).

Aisea e lafo ai na'o fa'afouga ta'aloga i le taimi ? Ina ia faasaoina le alaleo. 30 faʻafouga taʻaloga i le sekone e tele!

Aisea e le na o le valaau atu i lena taimi? update() 30 taimi i le sekone? Ina ia faʻaleleia le faʻataʻitaʻiga o taʻaloga. O le tele o taimi e ta'ua ai update(), o le a sili atu le saʻo o le faʻataʻitaʻiga o le taʻaloga. Ae aua e te soona faaseseina i le tele o luitau update(), aua o se galuega taugata faʻatusatusa - 60 i le sekone ua lava.

O le isi vaega o le vasega Game e aofia ai auala fesoasoani o loʻo faʻaaogaina i update():

game.js, vaega 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() E faigofie lava - e fa'avasega tagata ta'alo i sikoa, ave le lima pito i luga, ma toe fa'afo'i le igoa ole igoa ma sikoa mo ta'itasi.

createUpdate() faʻaaogaina i update() e fatu ai fa'afouga ta'aloga e tufatufa atu i tagata ta'aalo. O lana galuega autu o le valaau metotia serializeForUpdate(), fa'atinoina mo vasega Player и Bullet. Manatua e na'o le tu'uina atu o fa'amatalaga i tagata ta'alo ta'itasi e uiga i lata ane tagata taʻalo ma projectiles - e leai se manaʻoga e tuʻuina atu faʻamatalaga e uiga i mea taʻaloga e mamao ese mai le tagata taʻalo!

3. Taaloga mea faitino i luga o le server

I la tatou ta'aloga, e matua'i tutusa lava ta'aloga ma ta'a'alo: o mea ta'a'alo fa'ata'amilo e fealua'i. Ina ia faʻaogaina lenei mea tutusa i le va o taʻaloga ma projectiles, tatou amata i le faʻatinoina o se vasega faavae 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,
    };
  }
}

E leai se mea faigata e tupu iinei. O lenei vasega o le a avea ma amataga lelei mo le faʻalauteleina. Sei o tatou vaai pe faapefea le vasega Bullet faʻaaoga Object:

pulu.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 puupuu tele! Ua matou faaopoopo i Object na'o fa'aopoopoga nei:

  • Fa'aaogaina o le afifi pupuu mo tupulaga fai fua id fa'ailoga.
  • Fa'aopoopoina se fanua parentID, ina ia mafai ona e siaki le tagata taʻalo na faia lenei poloketi.
  • Fa'aopoopo le tau fa'afo'i i update(), lea e tutusa true, pe afai o le projectile o loʻo i fafo atu o le malae (manatua na matou talanoa e uiga i lenei mea i le vaega mulimuli?).

Sei o tatou agai i luma 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,
    };
  }
}

O tagata taaalo e sili atu le lavelave nai lo projectiles, o lea e tatau ai i lenei vasega ona teuina ni nai fanua. O lana metotia update() e tele atu galuega, ae maise le toe fa'afo'iina o le projectile fou pe a leai se mea o totoe fireCooldown (manatua na tatou talanoa e uiga i lenei mea i le vaega muamua?). E faʻalauteleina ai foi le auala serializeForUpdate(), aua tatou te manaʻomia le faʻaopoopoina o fanua faʻaopoopo mo le tagata taʻalo i le faʻafouina o le taʻaloga.

Avanoa o se vasega faavae Object - o se laasaga taua e aloese ai mai le toe fai tulafono. Mo se faataitaiga, e aunoa ma se vasega Object o mea ta'aloga uma e tatau ona tutusa le fa'atinoga distanceTo(), ma kopi-fa'apipi'i uma nei fa'atinoga i le tele o faila o le a avea ma se miti leaga. E taua tele lenei mea mo galuega tetele, pe a o le numera o le faʻalauteleina Object ua faatupulaia vasega.

4. Su'esu'eina o fa'alavelave

Pau lava le mea tatou te faia o le iloa lea pe a taia e le au taʻavale le au taʻaalo! Manatua lenei snippet code mai le metotia update() i le vasega Game:

taaloga.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),
    );

    // ...
  }
}

E tatau ona tatou faʻatinoina le metotia applyCollisions(), lea e toe fa'afo'i mai ai projectiles uma na lavea ai tagata ta'aalo. O le mea e lelei ai, e le faigata tele ona fai aua

  • O mea feto'ai uma o li'o, ma o le foliga sili lea ona faigofie e fa'atino ai le su'eina o fa'alavelave.
  • Ua uma ona i ai sa matou metotia distanceTo(), lea na matou faʻatinoina i le vasega i le vaega muamua Object.

O le mea lea e foliga mai ai le faʻatinoina o le faʻalavelave faʻafuaseʻi:

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;
}

O lenei su'esu'ega fa'afefe faigofie e fa'avae i le mea moni lena e lua li'o e feto'ai pe afai o le mamao i le va o latou nofoaga tutotonu e itiiti ifo i le aofa'i o o latou radii. O se tulaga lea o le mamao i le va o totonugalemu o li'o e lua e tutusa lelei ma le aofa'i o latou radii:

Fausia se ta'aloga i luga ole laiga multiplayer i le ituaiga .io
O iinei e tatau ona e gauai totoʻa i ni nai vaega:

  • E le tatau ona lavea le tagata taalo na faia. E mafai ona ausia lenei mea e ala i le faʻatusatusa bullet.parentID с player.id.
  • E na'o le tasi lava le lavea o le projectile i le tulaga ogaoga o le taia o le tele o tagata taaalo i le taimi e tasi. O le a matou foia lenei faʻafitauli e faʻaaoga ai le tagata faʻaoga break: O le taimi lava e maua ai se tagata taalo o loʻo fetoʻai ma se mea faʻapipiʻi, matou te tuʻu le suʻega ae faʻaauau i le isi mea e sosoo ai.

Le iuga

Pau lava lena! Ua matou ufiufi mea uma e te manaʻomia e te iloa e fai ai se taʻaloga i luga ole laiga .io. O le a le isi mea? Fausia lau lava .io taaloga!

O faʻataʻitaʻiga code uma e tatala ma faʻapipiʻi i luga Github.

puna: www.habr.com

Faaopoopo i ai se faamatalaga