• Nenhum resultado encontrado

Modul multiplayer și comunicarea în timp real dintre client și server

36

37

La crearea conexiunii websocket în lobby, fiecare client va trimite token-ul sau cheia de acces al user-ului pentru a demonstra că acea conexiune a fost făcută de un user autentificat.

Logica jocului pornește când toți jucătorii din lobby sunt pregătiți să înceapă și proprietarul lobby-ului apasă pe butonul PLAY care va emite un eveniment de începere. După încărcarea jocului, fiecare jucător va emite un eveniment gameLoaded, adică jocul a fost încărcat și sunt pregătiți să înceapă; după ce toți jucătorii vor trimite acest eveniment, ei vor asculta evenimentul startGame în care se vor primi toate pozițiile pe hartă a tancurilor și vor putea începe jocul.

În timpul jocului, clientul va emite următoarele evenimente prin websocket:

respawn – după ce tancul este distrus, la apăsarea tastei SPACE se va emite acest eveniment în care clientul va cere să aducă la viață tancul distrus și să îl repoziționeze pe hartă, iar server-ul va trimite această informație tuturor clienților din camera jocului;

fire – acest eveniment se va emite tot la apăsarea tastei SPACE, dar când tancul este în viață; evenimentul de tragere, care trimite la server poziția, direcția, accelerația și cât din viață are tancul, va trimite mai departe la restul clienților această informație;

movement – acest eveniment se va emite de fiecare dată când se va apăsa sau se va elibera una din tastele de navigare5, și va trimite de fiecare dată aceleași informații, ca și în cazul evenimentului fire, adică poziția, direcția, accelerația și cât din viață are tancul.

După ce jocul a fost început, clientul va asculta numai evenimentul updatePlayer, unde vor veni actualizările de la ceilalți jucători.

Când vine vorba de un joc multiplayer în timp real, logica în sine a jocului trebuie rulată atât pe server, cât și pe client, deoarece serverul trebuie să fie autoritatea cu privire la starea de joc în orice moment.

În cazul de față, logica jocului este rulată doar pe client și server-ul primește, verifică și trimite informațiile celorlalți jucători.

5 Sunt tastele care au desenate pe ele săgeți.

38

Deoarece sunt trimise și primite informații despre tanc doar când se schimbă direcția și accelerația, trebuie să rulăm animația tancului în care își schimbă poziția pe partea de client, acest lucru fiind un sistem de prezicere a clientului, iar la următoarea actualizare trebuie reparate foarte ușor greșelile de predicție, pentru a se păstra pozițiile tancurilor sincronizate, astfel rezolvându-se problema timpului mare de răspuns în care se pot trimite informațiile.

Ce se poate întămpla dacă nu sunt reparate greșelile de predicție? De exemplu:

 Clientul apasă tasta de navigare spre stânga, anunță serverul și în același timp începe să mute tancul pe hartă;

 După 100 de milisecunde informația ajunge pe server, unde este procesată și puțin mai târziu o trimite celuilalt client;

 La celălalt client informația ajunge după 150 de milisecunde, timp în care va începe să mute tancul jucătorului inamic pe hartă.

Deja există o diferență de 250 de milisecunde care este insesizabilă, dar după câteva minute de joc, tancurile nu vor mai fi sincronizate.

39

3 Dezvoltarea aplicației server

Aplicația server este formată din două fișiere localizate în folderul server, un fișier în care se află datele de conectare la baza de date, url-ul aplicației client și url-ul aplicației server numit config.js și main.js în care se află tot codul specific aplicației server.

Aplicația server se poate porni prin rularea comenzii node main.js în directorul server al aplicației, dar am preferat să folosesc biblioteca pm2, care este un manager de procese pentru aplicațiile Node.js. Astfel îmi permite să țin aplicația server tot timpul deschisă, iar în caz de eroare, îmi salvează în log-uri ce s-a întâmplat și restartează aplicația automat. De asemenea, îmi oferă o modalitate simplă de monitorizare a resurselor consumate de aplicație la cererea mea.

La pornirea aplicației server, în primele linii de cod, sunt instanțiate toate modulele necesare explicate în subcapitolul 1.3 Arhitectura aplicației.

Următoarele linii de cod sunt doar câteva necesare pentru pornirea serverului folosind modulul Express și Socket.IO care este atașat la Express, pentru ca amândouă să asculte pe același port.

// Create a new Express application var app = require('express')();

// Create an http server with Node's HTTP module and pass it the Express application var server = require('http').createServer(app);

// Instantiate Socket.IO hand have it listen on the Express/HTTP server var io = require('socket.io')(server);

// Start server and listen to port 8081 server.listen(8081, function () { console.log(‘SERVER STARTED’);

});

Secțiune de cod 12: Codul pentru pornirea server-ului pentru cererile HTTP și WebSocket

După cum am explicat și în capitolul 1.3 Arhitectura aplicației, în această configurație Express este utilizat pentru a trata cererile HTTP care vin în aplicația Node.js. Modulul Socket.IO se atașează de Express și ascultă pe același port pentru conexiunele WebSocket de intrare.

Express are în componența lui diferite tehnici pe care le putem folosi în momentul în care o cerere către o anumită pagină web sau o anumită informație este dorită spre vizualizare în browser. Una dintre aceste tehnici se numește "routing" și are ca principal scop traseul cererii ce

40

vine de la client și care mai apoi este gestionată cu ajutorul diferitelor funcții sau metode, cu scopul de a-i oferi un răspuns cu un anume conținut browser client.(12)