ProHoster > Blog > Pulega > 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.
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.
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:
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:
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.
Atonu e foliga faigata lenei mea, ae o le mea moni e le tele se mea e tupu iinei:
Auina mai nisi faila JS.
Fa'aulufale mai CSS (ina ia iloa e le Webpack e fa'aofi i totonu o la matou pusa CSS).
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.
A mae'a le laasaga 3 o lo'o fa'aalia le lisi autu (playMenu).
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:
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:
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:
Talaaga
Vaa tagata taalo
O isi tagata taaalo i le taaloga
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:
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):
Ae paga lea, e leai se mea e atoatoa. O se ata sili atu ona moni o le a:
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:
E maua mai ai ia i matou se 100ms buffer e ola ai i le taimi le mautonu o faʻafouga taʻaloga:
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:
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?
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:
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.
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.
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.
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:
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:
Fa'atatau le taimi dt talu mai le taimi mulimuli update().
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).
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.
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.
Fa'ailoa ma fa'aumatia tagata ta'aalo uma.
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():
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:
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:
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.