Ịmepụta Egwuregwu Weebụ ọtụtụ .io

Ịmepụta Egwuregwu Weebụ ọtụtụ .io
E wepụtara na 2015 Agar.io ghọrọ nna nke ụdị ọhụrụ egwuregwu .ionke toro na ewu ewu kemgbe ahụ. Mụ onwe m enwetala ịrị elu na ewu ewu nke egwuregwu .io: n'ime afọ atọ gara aga, enwere m kere ma ree egwuregwu abụọ nke ụdị a..

Ọ bụrụ na ị nụtụbeghị egwuregwu ndị a mbụ, ndị a bụ egwuregwu webụ ọtụtụ egwuregwu n'efu dị mfe igwu egwu (enweghị akaụntụ achọrọ). Ha na-echekarị ọtụtụ ndị egwuregwu na-emegide n'otu ogige ihu. Egwuregwu io ndị ọzọ ama ama: Slither.io и Diep.io.

Na nke a post, anyị ga-enyocha otú mepụta egwuregwu .io site na ọkọ. Maka nke a, naanị ihe ọmụma nke Javascript ga-ezuru: ịkwesịrị ịghọta ihe dịka syntax ES6, isiokwu this и nkwa. Ọbụna ma ọ bụrụ na ihe ọmụma gị nke Javascript ezughị oke, ị ka nwere ike ịghọta ọtụtụ n'ime post.

.io egwuregwu atụ

Maka enyemaka mmụta, anyị ga-ezo aka ihe atụ egwuregwu io. Gbalịa ịkpọ ya!

Ịmepụta Egwuregwu Weebụ ọtụtụ .io
Egwuregwu ahụ dị nnọọ mfe: ị na-achịkwa ụgbọ mmiri n'ọgbọ egwuregwu ebe ndị egwuregwu ndị ọzọ nọ. Ụgbọ mmiri gị na-agba ọkụ na-akpaghị aka ma ị na-agbalị ịkụ ndị egwuregwu ndị ọzọ ka ị na-ezere projectiles ha.

1. Nchịkọta nkenke / nhazi nke oru ngo

Ekwadoro m budata koodu isi mmalite egwuregwu ihe atụ ka i wee soro m.

Ihe atụ na-eji ihe ndị a:

  • Gwa bụ usoro weebụ Node.js kachasị ewu ewu na-ejikwa sava weebụ egwuregwu.
  • oghere.io - ọbá akwụkwọ websocket maka ịgbanwe data n'etiti ihe nchọgharị na ihe nkesa.
  • Ihe ntanetị - modul njikwa. Ị nwere ike ịgụ maka ihe kpatara eji jiri Webpack. ebe a.

Nke a bụ ihe nhazi akwụkwọ ndekọ aha ọrụ dị ka:

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

ọha/

Ihe niile dị na folda public/ ihe nkesa ga-edobere statically. N'ime public/assets/ nwere onyonyo nke oru ngo anyi ji.

src /

Koodu isi mmalite niile dị na folda ahụ src/. Aha client/ и server/ na-ekwu maka onwe ha na shared/ nwere faịlụ agbanwe agbanwe nke ma onye ahịa na nkesa na-ebubata.

2. Mgbakọ / ntọala ọrụ

Dịka e kwuru n'elu, anyị na-eji njikwa modul rụọ ọrụ ahụ. Ihe ntanetị. Ka anyị leba anya na nhazi Webpack anyị:

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

Ahịrị kacha mkpa ebe a bụ:

  • src/client/index.js bụ ebe ntinye nke Javascript (JS) ahịa. Mpempe weebụ ga-amalite site na ebe a wee chọọ faịlụ ndị ọzọ ebubatara ugboro ugboro.
  • Mpụta JS nke ihe nrụpụta Webpack anyị ga-adị na ndekọ aha dist/. Aga m akpọ faịlụ a nke anyị ngwugwu js.
  • Anyị na -eji Babel, na karịsịa nhazi @babel/preset-env iji sụgharịa koodu JS anyị maka ihe nchọgharị ochie.
  • Anyị na-eji ngwa mgbakwunye wepụ CSS niile nke faịlụ JS zoro ma jikọta ha n'otu ebe. Aga m akpọ ya nke anyị css ngwugwu.

O nwere ike ịbụ na ị hụla aha faịlụ ngwungwu dị iche iche '[name].[contenthash].ext'. Ha nwere nnọchi aha faịlụ Ibe weebụ: [name] a ga-eji aha ntinye ntinye dochie ya (n'ọnọdụ anyị, nke a game), na [contenthash] a ga-eji hash nke ọdịnaya faịlụ dochie anya. Anyị na-eme ya bulie oru ngo maka hashing - ị nwere ike ịgwa ndị nchọgharị ka ha chekwaa ngwugwu JS anyị ruo mgbe ebighị ebi, n'ihi na Ọ bụrụ na ngwugwu agbanwee, mgbe ahụ aha faịlụ ya na-agbanwekwa (mgbanwe contenthash). Nsonaazụ ikpeazụ ga-abụ aha faịlụ nlele game.dbeee76e91a97d0c7207.js.

file webpack.common.js bụ faịlụ nhazi ntọala nke anyị na-ebubata n'ime mmepe na nhazi ọrụ nhazi. Nke a bụ nhazi mmepe ihe atụ:

webpack.dev.js

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

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

Maka ịrụ ọrụ nke ọma, anyị na-eji usoro mmepe webpack.dev.js, ma gbanwee gaa webpack.prod.jsiji kwalite nha ngwugwu mgbe a na-ebuga na mmepụta.

Ntọala mpaghara

Ana m akwado ịwụnye ọrụ ahụ na igwe mpaghara ka ị nwee ike ịgbaso usoro ndị edepụtara na post a. Nhazi ahụ dị mfe: nke mbụ, usoro ahụ ga-abụrịrị arụnyere ọnụ и NPM. Ọzọ ị ga-eme

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

na ị dịla njikere ịga! Iji malite ihe nkesa mmepe, naanị gbaa ọsọ

$ npm run develop

wee gaa na ihe nchọgharị weebụ localhost: 3000. Ihe nkesa mmepe ga-ewughachi ngwugwu JS na CSS na-akpaghị aka ka koodu na-agbanwe - naanị megharịa ibe ahụ ka ịhụ mgbanwe niile!

3. Ihe ntinye ndị ahịa

Ka anyị gbadaa na koodu egwuregwu n'onwe ya. Mbụ anyị chọrọ ibe index.html, mgbe ị na-eleta saịtị ahụ, ihe nchọgharị ahụ ga-ebu ụzọ buru ya. Ibe anyị ga-adị mfe:

index.html

Ihe atụ .io egwuregwu  Gwuo egwu

Emeela ka ihe atụ koodu a dị mfe maka idoanya, m ga-eme otu ihe ahụ na ọtụtụ n'ime ihe atụ post ndị ọzọ. Enwere ike ịlele koodu zuru oke mgbe niile na Github.

Anyị nwere:

  • HTML5 kanvas element (<canvas>) nke anyị ga-eji mee egwuregwu ahụ.
  • <link> ịgbakwunye ngwugwu CSS anyị.
  • <script> ka ịgbakwunye ngwugwu Javascript anyị.
  • Isi menu nwere aha njirimara <input> na bọtịnụ PLAY (<button>).

Ozugbo ibe ụlọ buru ibu, ihe nchọgharị ahụ ga-amalite ime koodu Javascript, malite na ntinye JS faịlụ: 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);
  };
});

Nke a nwere ike ịdị mgbagwoju anya, mana ọ nweghị ọtụtụ ihe na-eme ebe a:

  1. Na-ebubata ọtụtụ faịlụ JS ndị ọzọ.
  2. Mbubata CSS (yabụ Webpack maara na ọ ga-etinye ha na ngwugwu CSS anyị).
  3. Mwepụta connect() iji guzobe njikọ na ihe nkesa na-agba ọsọ downloadAssets() iji budata onyonyo achọrọ iji nye egwuregwu ahụ.
  4. Mgbe emechara nke 3 a na-egosipụta isi menu (playMenu).
  5. Ịtọlite ​​njikwa maka ịpị bọtịnụ "PLAY". Mgbe ịpịrị bọtịnụ ahụ, koodu ahụ na-amalite egwuregwu ahụ wee gwa ihe nkesa na anyị dị njikere igwu egwu.

Isi "anụ" nke ezi uche nke onye ahịa-ihe nkesa anyị dị na faịlụ ndị ahụ faịlụ ahụ webatara index.js. Ugbu a, anyị ga-atụle ha niile n'usoro.

4. Exchange nke ndị ahịa data

N'egwuregwu a, anyị na-eji ọbá akwụkwọ a ma ama na-ekwurịta okwu na ihe nkesa oghere.io. Socket.io nwere nkwado obodo ntọala webụ, nke dabara nke ọma maka nkwukọrịta ụzọ abụọ: anyị nwere ike izipu ozi na ihe nkesa и ihe nkesa ahụ nwere ike izigara anyị ozi n'otu njikọ ahụ.

Anyị ga-enwe otu faịlụ src/client/networking.jsonye ga-elekọta onye ọ bụla nkwurịta okwu na ihe nkesa:

netwọk.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);
};

E mechaala koodu a ntakịrị maka idoanya.

Enwere isi omume atọ na faịlụ a:

  • Anyị na-agbalị jikọọ na ihe nkesa. connectedPromise na-ekwe naanị mgbe anyị guzobe njikọ.
  • Ọ bụrụ na njikọ ahụ na-aga nke ọma, anyị na-edebanye aha ọrụ ịkpọghachi (processGameUpdate() и onGameOver()) maka ozi anyị nwere ike ịnata na sava.
  • Anyị na-ebupụ play() и updateDirection()ka faịlụ ndị ọzọ nwee ike iji ha.

5. Ntugharị ndị ahịa

Ọ bụ oge igosi foto na ihuenyo!

…mana tupu anyị enwee ike ime nke ahụ, anyị kwesịrị ibudata onyonyo (akụrụngwa) niile achọrọ maka nke a. Ka anyị dee onye njikwa akụrụngwa:

akụ.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];

Ijikwa akụrụngwa abụghị nke siri ike itinye! Isi echiche bụ ịchekwa ihe assets, nke ga-ejikọta igodo faịlụ aha na uru nke ihe ahụ Image. Mgbe etinyere akụrụngwa, anyị na-echekwa ya na ihe assets maka ịnweta ngwa ngwa n'ọdịnihu. Kedu mgbe a ga-ahapụ ihe enyemaka nke ọ bụla ka ọ budata (ya bụ, niile akụrụngwa), anyị na-ekwe downloadPromise.

Mgbe nbudata ihe onwunwe, ị nwere ike ịmalite ịtụgharị. Dị ka e kwuru na mbụ, ise na ibe weebụ, anyị na-eji HTML5 Canvas (<canvas>). Egwuregwu anyị dị mfe, yabụ naanị anyị kwesịrị ise ihe ndị a:

  1. Azụ
  2. Ụgbọ mmiri egwuregwu
  3. Ndị egwuregwu ndị ọzọ na egwuregwu ahụ
  4. Shell

Nke a bụ snippets ndị dị mkpa src/client/render.js, nke na-akọwa kpọmkwem ihe anọ e depụtara n'elu:

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

A na-ebelata koodu a maka idoanya.

render() bụ isi ọrụ nke faịlụ a. startRendering() и stopRendering() jikwaa ịgbalite loop render na 60 FPS.

Mmejuputa a kpọkọtara ọnụ nke ọrụ inyeaka na-enye onye ọ bụla (dịka. renderBullet()) abụghị ihe dị mkpa, mana ebe a bụ otu ihe atụ dị mfe:

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

Rịba ama na anyị na-eji usoro a getAsset(), nke a hụrụ na mbụ asset.js!

Ọ bụrụ na ị nwere mmasị n'ịmụta gbasara ndị enyemaka inyeaka ndị ọzọ, gụọ nke ọzọ. src/onye ahịa/render.js.

6. Ntinye onye ahịa

Oge erugo ime egwuregwu enwere ike igwu egwu! Atụmatụ njikwa ga-adị nnọọ mfe: ịgbanwe ntụziaka nke ije, ị nwere ike iji òké (na kọmputa) ma ọ bụ metụ ihuenyo (na a mobile ngwaọrụ). Iji mejuputa nke a, anyị ga-edebanye aha Mmemme Ndị Na-ege Ntị maka mmemme Mouse na Touch.
Ga-elekọta ihe a niile src/client/input.js:

ntinye.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() bụ Ndị na-ege ihe omume na-akpọ updateDirection() (nke networking.js) mgbe mmemme ntinye pụtara (dịka ọmụmaatụ, mgbe ebuliri òké). updateDirection() na-ejikwa ihe nkesa ozi na-edozi ozi, nke na-ejikwa mmemme ntinye ma na-emelite ọnọdụ egwuregwu ahụ.

7. Ọnọdụ ndị ahịa

Nkebi a bụ ihe kacha sie ike na akụkụ mbụ nke post. Adala mbà ma ọ bụrụ na ị ghọtaghị ya na mbụ ị gụrụ ya! Ị nwere ike mafe ya wee laghachi na ya ma emechaa.

Ibe ikpeazụ nke mgbaghoju anya dị mkpa iji mechaa onye ahịa/ koodu nkesa bụ ala. Cheta snippet koodu sitere na ngalaba Rendering ndị ahịa?

enye.js

import { getCurrentState } from './state';

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

  // Do the rendering
  // ...
}

getCurrentState() kwesịrị inwe ike inye anyị ọnọdụ egwuregwu ugbu a na onye ahịa n'oge ọ bụla dabere na mmelite enwetara site na ihe nkesa. Nke a bụ ọmụmaatụ mmelite egwuregwu nke sava nwere ike izipu:

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

Mmelite egwuregwu ọ bụla nwere ogige ise yiri ya:

  • t: Ihe nkesa timestamp na-egosi mgbe emelitere mmelite a.
  • meOzi gbasara onye ọkpụkpọ na-enweta mmelite a.
  • ndị ọzọ: Ọtụtụ ozi gbasara ndị egwuregwu ndị ọzọ na-ekere òkè n'otu egwuregwu ahụ.
  • mgbọ: ọtụtụ ozi gbasara projectiles na egwuregwu.
  • onye ndu: Data bọọdụ ndu ugbu a. Na post a, anyị agaghị atụle ha.

7.1 steeti ndị ahịa enweghị isi

Mmejuputa adịghị mma getCurrentState() nwere ike iweghachite data nke mmelite egwuregwu enwetara nso nso a.

naive-state.js

let lastGameUpdate = null;

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

export function getCurrentState() {
  return lastGameUpdate;
}

Ọ dị mma ma doo anya! Ma ọ bụrụ naanị na ọ dị mfe. Otu n'ime ihe kpatara mmejuputa a bụ nsogbu: ọ na-amachi ọnụego etiti nrụpụta na ọnụego elekere ihe nkesa.

Ọnụego Frame: ọnụọgụ okpokolo agba (ya bụ oku render()) kwa sekọnd, ma ọ bụ FPS. Egwuregwu na-agbakarị mbọ iji nweta opekata mpe 60 FPS.

Ọnụ ego akara: Ugboro ugboro nke ihe nkesa na-eziga mmelite egwuregwu na ndị ahịa. Ọ na-adịkarị ala karịa ọnụego etiti. Na egwuregwu anyị, ihe nkesa na-agba ọsọ na ugboro 30 cycles kwa nkeji.

Ọ bụrụ na anyị na-enye mmelite kachasị ọhụrụ nke egwuregwu ahụ, FPS agaghị agafe 30, n'ihi na anyị anaghị enweta mmelite karịa 30 kwa sekọnd site na sava ahụ. Ọ bụrụgodị na anyị na-akpọ render() Ugboro 60 kwa nkeji, ọkara nke oku ndị a ga-emegharị otu ihe, na-eme ihe ọ bụla. Nsogbu ọzọ na mmejuputa naive bụ na ya na-adị mfe igbu oge. Site na ọsọ ịntanetị dị mma, onye ahịa ga-enweta mmelite egwuregwu kpọmkwem 33ms ọ bụla (30 kwa nkeji):

Ịmepụta Egwuregwu Weebụ ọtụtụ .io
N'ụzọ dị mwute, ọ dịghị ihe zuru oke. Foto dị adị karịa ga-abụ:
Ịmepụta Egwuregwu Weebụ ọtụtụ .io
Mmejuputa ihe na-enweghị isi bụ ihe kachasị njọ ma a bịa n'ịkwụ ụgwọ. Ọ bụrụ na enwetara mmelite egwuregwu na igbu oge nke 50ms, yabụ ụlọ ahịa ndị ahịa 50ms agbakwunyere n'ihi na ọ ka na-eme ọnọdụ egwuregwu site na mmelite gara aga. Ị nwere ike iche n'echiche ka nke a si bụrụ ihe na-adịghị ahụkebe maka onye ọkpụkpọ: breeki aka ike ga-eme ka egwuregwu ahụ dị nro na enweghị isi.

7.2 Ọnọdụ ndị ahịa emelitere

Anyị ga-eme mgbanwe ụfọdụ na mmejuputa ihe efu. Nke mbụ, anyị na-eji na-egbu oge maka 100 ms. Nke a pụtara na ọnọdụ "nke dị ugbu a" nke onye ahịa ga-adaghachi mgbe niile n'azụ ọnọdụ egwuregwu na sava site na 100ms. Dịka ọmụmaatụ, ọ bụrụ na oge na ihe nkesa bụ 150, mgbe ahụ onye ahịa ga-enye ọnọdụ nke ihe nkesa nọ n'oge ahụ 50:

Ịmepụta Egwuregwu Weebụ ọtụtụ .io
Nke a na-enye anyị ihe nchekwa 100ms iji lanarị oge mmelite egwuregwu a na-atụghị anya ya:

Ịmepụta Egwuregwu Weebụ ọtụtụ .io
Nkwụghachi ụgwọ maka nke a ga-adịgide adịgide ntinye aka maka 100 ms. Nke a bụ obere àjà maka egwuregwu dị ụtọ - ọtụtụ ndị egwuregwu (karịsịa ndị egwuregwu nkịtị) agaghị achọpụta igbu oge a. Ọ na-adịrị ndị mmadụ mfe ịhazigharị ka ọ na-adalata 100ms mgbe niile karịa ka ọ na-eji egwu egwu na-enweghị atụ.

Anyị nwekwara ike iji usoro ọzọ a na-akpọ amụma n'akụkụ ndị ahịa, nke na-arụ ọrụ dị mma nke ibelata aghọtaghị latency, ma agaghị ekpuchi ya na post a.

Nkwalite ọzọ anyị na-eji bụ interpolation linear. N'ihi nkwụsị nrụgharị, anyị na-abụkarị opekata mpe otu mmelite tupu oge dị ugbu a na onye ahịa. Mgbe akpọrọ getCurrentState(), anyị nwere ike igbu interpolation linear n'etiti mmelite egwuregwu tupu oge na mgbe oge dị ugbu a na onye ahịa:

Ịmepụta Egwuregwu Weebụ ọtụtụ .io
Nke a na-edozi okwu ọnụ ọgụgụ etiti: anyị nwere ike ugbu a wepụta okpokolo agba pụrụ iche n'ogo ọ bụla anyị chọrọ!

7.3 Na-emejuputa steeti ndị ahịa emelitere

Ihe atụ mmejuputa na src/client/state.js na-eji ma render lag na linear interpolation, ma ọ bụghị ogologo oge. Ka anyị gbajie koodu ahụ ụzọ abụọ. Nke a bụ nke mbụ:

state.js akụkụ 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;
}

Nzọụkwụ mbụ bụ ịchọpụta ihe currentServerTime(). Dịka anyị hụrụ na mbụ, mmelite egwuregwu ọ bụla na-agụnye timestamp nkesa. Anyị chọrọ iji render latency nye onyonyo 100ms n'azụ sava ahụ, mana anyị agaghị ama oge dị ugbu a na ihe nkesa, n'ihi na anyị enweghị ike ịma ogologo oge ọ na-ewe maka mmelite ọ bụla ịbịakwute anyị. Ịntanetị enweghị atụ na ọsọ ya nwere ike ịdịgasị iche!

Iji dozie nsogbu a, anyị nwere ike iji ihe ezi uche dị na ya: anyị mee ka mmelite mbụ rutere ozugbo. Ọ bụrụ na nke a bụ eziokwu, mgbe ahụ anyị ga-amata oge nkesa n'oge a! Anyị na-echekwa akara oge nke ihe nkesa ahụ firstServerTimestamp ma debe anyị mpaghara (client) timestamp n'otu oge n'ime gameStart.

Oh chere. O kwesịghị ịbụ oge nkesa = oge ndị ahịa? Gịnị kpatara anyị ji amata ọdịiche dị n'etiti "stampụ timestamp nkesa" na "stampụ oge ahịa"? Nke a bụ nnukwu ajụjụ! Ọ na-apụta na ha abụghị otu ihe. Date.now() ga-eweghachite stampụ dị iche iche na onye ahịa na ihe nkesa, ọ dabere na ihe mpaghara na igwe ndị a. Echela na akara oge ga-abụ otu na igwe niile.

Ugbu a, anyị ghọtara ihe na-eme currentServerTime(): ọ na-alọghachi ihe nkesa timestamp nke ugbu a inye oge. N'ikwu ya n'ụzọ ọzọ, nke a bụ oge nkesa nke ugbu a (firstServerTimestamp <+ (Date.now() - gameStart)) mwepu igbu oge (RENDER_DELAY).

Ugbu a, ka anyị leba anya n'otú anyị si edozi mmelite egwuregwu. Mgbe enwetara site na ihe nkesa mmelite, a na-akpọ ya processGameUpdate()ma anyị na-echekwa mmelite ọhụrụ ka ọ bụrụ n'usoro gameUpdates. Mgbe ahụ, iji lelee ojiji ebe nchekwa, anyị na-ewepụ mmelite ochie niile na mbụ isi meliten'ihi na anyị achọghị ha ọzọ.

Kedu ihe bụ "mmelite ntọala"? Nke a mmelite mbụ anyị na-ahụ site n'ịgaghachi azụ site na oge nkesa dị ugbu a. Cheta eserese a?

Ịmepụta Egwuregwu Weebụ ọtụtụ .io
Mmelite egwuregwu ahụ ozugbo n'aka ekpe nke "Oge Nrụpụta Ndị Ahịa" bụ mmelite ntọala.

Kedu ihe eji emelite ntọala? Kedu ihe kpatara anyị ga-eji tinye mmelite na ntọala? Iji chọpụta nke a, ka anyị n'ikpeazụ tụlee mmejuputa iwu getCurrentState():

state.js akụkụ 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),
    };
  }
}

Anyị na-edozi ikpe atọ:

  1. base < 0 pụtara na enweghị mmelite ruo oge inyefe ugbu a (lee n'elu mmejuputa iwu getBaseUpdate()). Nke a nwere ike ime ozugbo na mmalite nke egwuregwu n'ihi na ọ na-akwụsịlata. N'okwu a, anyị na-eji mmelite kachasị ọhụrụ enwetara.
  2. base bụ ọhụrụ update anyị nwere. Nke a nwere ike ịbụ n'ihi igbu oge netwọk ma ọ bụ njikọ ịntanetị adịghị mma. N'okwu a, anyị na-ejikwa mmelite kachasị ọhụrụ anyị nwere.
  3. Anyị nwere mmelite ma tupu ma mgbe oge nrụpụta dị ugbu a, yabụ anyị nwere ike interpolate!

Ihe niile fọdụrụ state.js bụ mmejuputa nke interpolation linear nke dị mfe (ma na-agwụ ike) mgbakọ na mwepụ. Ọ bụrụ na ịchọrọ inyocha ya n'onwe gị, wee mepee ya state.js on Github.

Nkebi 2. Ihe nkesa azụ azụ

N'akụkụ a, anyị ga-eleba anya na Node.js backend na-achịkwa anyị .io egwuregwu atụ.

1. Ebe ntinye ihe nkesa

Iji jikwaa sava weebụ, anyị ga-eji usoro webụsaịtị a ma ama maka Node.js akpọrọ Gwa. A ga-ahazi ya site na faịlụ ntinye ihe nkesa anyị src/server/server.js:

server.js akụkụ 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}`);

Cheta na n'akụkụ nke mbụ anyị tụlere Webpack? Nke a bụ ebe anyị ga-eji nhazi Webpack anyị. Anyị ga-eji ha n'ụzọ abụọ:

  • Jiri webpack-dev-middware iji wughachi ngwugwu mmepe anyị ozugbo, ma ọ bụ
  • nyefee nchekwa statically dist/, nke Webpack ga-edepụta faịlụ anyị mgbe arụpụtara ya.

Ọrụ ọzọ dị mkpa server.js bụ ịtọ ihe nkesa oghere.ionke na-ejikọ naanị na sava Express:

server.js akụkụ 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);
});

Mgbe emechara njikọ socket.io na sava ahụ nke ọma, anyị hibere ndị na-ahụ maka mmemme maka oghere ọhụrụ ahụ. Ndị na-ahụ maka mmemme na-ejikwa ozi enwetara site n'aka ndị ahịa site n'inyefe ihe otu otu otu game:

server.js akụkụ 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);
}

Anyị na-eke egwuregwu .io, yabụ na anyị chọrọ naanị otu oyiri Game ("Egwuregwu") - ndị egwuregwu niile na-egwu otu egwuregwu! Na ngalaba na-esote, anyị ga-ahụ ka klas a si arụ ọrụ. Game.

2. sava egwuregwu

Класс Game nwere ezi uche dị n'akụkụ ihe nkesa. O nwere isi ọrụ abụọ: njikwa egwuregwu и ịme anwansị egwuregwu.

Ka anyị malite na ọrụ mbụ, njikwa ọkpụkpọ.

game.js, akụkụ 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);
    }
  }

  // ...
}

N'ime egwuregwu a, anyị ga-amata ndị egwuregwu site na ubi id socket.io ha (ọ bụrụ na ị gbagwojuru anya, laghachi azụ na server.js). Socket.io n'onwe ya na-enye oghere ọ bụla pụrụ iche idyabụ anyị ekwesịghị ichegbu onwe anyị maka nke ahụ. Aga m akpọ ya NJ ọkpụkpọ.

N'iburu nke ahụ n'uche, ka anyị nyochaa mgbanwe atụ na klaasị Game:

  • sockets bụ ihe na-ejikọta ID ọkpụkpọ na oghere nke ejikọrọ na ihe ọkpụkpọ. Ọ na-enye anyị ohere ịnweta sọket site na NJ ọkpụkpọ ha na oge niile.
  • players bụ ihe na-ejikọta ID ọkpụkpọ na koodu>Ihe ọkpụkpọ

bullets bụ ọtụtụ ihe Bullet, nke na-enweghị usoro doro anya.
lastUpdateTime bụ timestamp nke ikpeazụ emelitere egwuregwu ahụ. Anyị ga-ahụ ka esi eji ya eme ihe n'oge adịghị anya.
shouldSendUpdate bụ mgbanwe inyeaka. Anyị ga-ahụkwa ojiji ya n'oge adịghị anya.
Ụzọ addPlayer(), removePlayer() и handleInput() ọ dịghị mkpa ịkọwa, ha na-eji na server.js. Ọ bụrụ na ịchọrọ iweghachite ebe nchekwa gị, laghachi azụ ntakịrị elu.

Ahịrị ikpeazụ constructor() amalite imelite okirikiri egwuregwu (nke nwere mmelite 60 / s):

game.js, akụkụ 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;
    }
  }

  // ...
}

.Zọ update() nwere eleghị anya akụkụ kachasị mkpa nke mgbagha n'akụkụ nkesa. Nke a bụ ihe ọ na-eme, n'usoro:

  1. Na-agbakọ ogologo oge dt gafere kemgbe ikpeazụ update().
  2. Na-enweta ume nke ọ bụla ma ọ bụrụ na ọ dị mkpa. Anyị ga-ahụ mmejuputa nke ọrụ a ma emechaa. Ka ọ dị ugbu a, o zuola anyị ịmata nke ahụ bullet.update() na-alaghachi trueọ bụrụ na ekwesịrị ibibi projectile ahụ (o si n'ọgbọ egwuregwu pụta).
  3. Na-emelite onye ọkpụkpọ ọ bụla wee mepụta projectile ma ọ dị mkpa. Anyị ga-ahụkwa mmejuputa a ma emechaa - player.update() nwere ike iweghachi ihe Bullet.
  4. Na-enyocha maka esemokwu n'etiti projectiles na ndị egwuregwu nwere applyCollisions(), nke na-eweghachi n'usoro nke projectiles na-akụ ndị egwuregwu. Maka projectile ọ bụla laghachiri, anyị na-abawanye isi ihe onye ọkpụkpọ gbara ya (iji player.onDealtDamage()) wee wepụ projectile ahụ n'usoro bullets.
  5. Na-ekwupụta ma na-ebibi ndị egwuregwu niile egburu.
  6. Na-eziga mmelite egwuregwu nye ndị egwuregwu niile kwa sekọnd ugboro mgbe a na-akpọ update(). Nke a na-enyere anyị aka idobe mgbanwe inyeaka a kpọtụrụ aha n'elu. shouldSendUpdate. Dị ka update() a na-akpọ 60 ugboro / s, anyị na-eziga mmelite egwuregwu ugboro 30 / s. Ya mere, ugboro elekere Ihe nkesa elekere bụ 30 clocks/s (anyị kwuru maka ọnụego elekere na akụkụ nke mbụ).

Gịnị kpatara izipu naanị mmelite egwuregwu site na oge ? Ka ịchekwaa ọwa. Mmelite egwuregwu 30 kwa sekọnd bụ ọtụtụ!

Gịnị kpatara na ọ bụghị naanị ịkpọ update() ugboro 30 kwa nkeji? Iji melite ịme anwansị egwuregwu. Nke a na-akpọkarị update(), ka simulation egwuregwu ahụ ga-abụ nke ziri ezi. Ma ekwela ka ọnụ ọgụgụ nke ihe ịma aka mebie gị. update(), n'ihi na nke a bụ ọrụ dị oke ọnụ ahịa - 60 kwa nkeji ezuru.

Klas ndị ọzọ Game nwere usoro inyeaka eji eme ihe update():

game.js, akụkụ 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() mara mma dị mfe - ọ na-ahazi ndị egwuregwu site na akara, were ise kachasị elu, wee weghachi aha njirimara na akara maka nke ọ bụla.

createUpdate() eji na update() iji mepụta mmelite egwuregwu nke ekesara ndị egwuregwu. Isi ọrụ ya bụ ịkpọ ụzọ serializeForUpdate()emejuputa atumatu maka klaasị Player и Bullet. Rịba ama na ọ na-ebufe data naanị onye ọkpụkpọ ọ bụla gbasara kacha nso ndị egwuregwu na projectiles - ọ dịghị mkpa ịnyefe ozi gbasara ihe egwuregwu dị anya na onye ọkpụkpọ!

3. Ihe egwuregwu na ihe nkesa

N'ime egwuregwu anyị, projectiles na ndị na-egwu egwuregwu yiri nnọọ: ha bụ ihe egwuregwu nkịtị, okirikiri, na-ebugharị. Iji nweta myirịta a n'etiti ndị egwuregwu na ndị na-eme ihe, ka anyị bido site na itinye klaasị isi Object:

ihe.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,
    };
  }
}

Ọ dịghị ihe mgbagwoju anya na-eme ebe a. Klas a ga-abụ ebe arịlịka dị mma maka ndọtị ahụ. Ka anyị hụ otú klas Bullet na -eji Object:

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

Mmejuputa iwu Bullet dị mkpụmkpụ! Anyị agbakwunyela na Object naanị ndọtị ndị a:

  • Iji ngwugwu shortid maka random ọgbọ id projectile.
  • Na-agbakwụnye ubi parentID, ka ị nwee ike soro onye ọkpụkpọ mepụtara projectile a.
  • Na-agbakwụnye uru nloghachi na update(), nke hà nhata truema ọ bụrụ na projectile dị n'èzí arena (cheta na anyị kwuru banyere nke a na nke ikpeazụ?).

Ka anyị gaa n'ihu Player:

onye egwu.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,
    };
  }
}

Ndị na-egwu egwuregwu dị mgbagwoju anya karịa ihe atụ, ya mere ekwesịrị ịchekwa mpaghara ole na ole na klaasị a. Usoro ya update() na-arụ ọtụtụ ọrụ, karịsịa, na-eweghachite projectile emepụtara ọhụrụ ma ọ bụrụ na ọ dịghị nke fọdụrụ fireCooldown (cheta na anyị kwuru banyere nke a na ngalaba gara aga?). Ọzọkwa ọ na-agbatị usoro serializeForUpdate(), n'ihi na anyị kwesịrị ịgụnye mpaghara ndị ọzọ maka onye ọkpụkpọ na mmelite egwuregwu.

Inwe isi klas Object - nzọụkwụ dị mkpa iji zere ịmegharị koodu. Dịka ọmụmaatụ, enweghị klas Object Ihe egwuregwu ọ bụla ga-enwerịrị otu mmejuputa ya distanceTo(), na idetuo-papawa mmemme ndị a niile n'ofe faịlụ dị iche iche ga-abụ ihe nro. Nke a na-aghọ ihe dị mkpa karịsịa maka nnukwu ọrụ.mgbe ọnụ ọgụgụ nke ịgbasa Object klaasị na-eto eto.

4. Nchọpụta nkukota

Naanị ihe fọdụrụ anyị bụ ịmata mgbe projectiles kụrụ ndị egwuregwu! Cheta mpempe koodu a sitere na usoro update() na klas Game:

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

    // ...
  }
}

Anyị kwesịrị itinye usoro ahụ applyCollisions(), nke na-eweghachite projectiles niile kụrụ ndị egwuregwu. Luckily, ọ bụghị na ike ime n'ihi na

  • Ihe niile na-agbakọta bụ okirikiri, nke a bụ ụdị kachasị mfe iji mejuputa nchọpụta nkukota.
  • Anyị enweelarị usoro distanceTo(), nke anyị mejuputa na ngalaba gara aga na klaasị Object.

Nke a bụ ihe mmejuputa nchọpụta anyị siri dị:

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

Nke a dị mfe nchọpụta nkukota dabeere na eziokwu na okirikiri abụọ na-agbakọ ma ọ bụrụ na anya dị n'etiti etiti ha erughị nchikota nke radii ha. Nke a bụ ikpe ebe ebe dị anya n'etiti etiti okirikiri abụọ hà nhata na nchikota nke radii ha:

Ịmepụta Egwuregwu Weebụ ọtụtụ .io
N'ebe a, ị kwesịrị ịṅa ntị nke ọma na akụkụ abụọ ọzọ:

  • Ihe a na-eme atụmatụ agaghị akụ onye ọkpụkpọ kere ya. Enwere ike nweta nke a site na atụnyere bullet.parentID с player.id.
  • Igwe ihe a ga-akụrịrị naanị otu ugboro na njedebe nke ọtụtụ ndị egwuregwu na-agbakọ n'otu oge. Anyị ga-edozi nsogbu a site na iji onye ọrụ break: ozugbo achọtara onye ọkpụkpọ na-adaba na projectile, anyị kwụsịrị nchọta wee gaa n'ihu na-esote projectile.

Ọgwụgwụ

Ọ gwụla! Anyị ekpuchila ihe niile ịchọrọ ịma iji mepụta egwuregwu webụ .io. Gịnị na-esote? Mee egwuregwu .io nke gị!

Koodu nlele niile bụ oghere mepere emepe wee bipute ya Github.

isi: www.habr.com

Tinye a comment