2012-01-27 14 views
13

Mam pytanie, na które nie mogę znaleźć odpowiedzi.Multiplayerowa gra JavaScript zbudowana za pomocą Node.JS - Rozdzielenie graczy

Eksperymentuję z budowaniem gry dla wielu graczy za pomocą Node.JS i Socket.IO. Założyłem pokój do czatowania jako mój pierwszy eksperyment, więc pracuję nad transmisjami itd. Teraz jestem w miejscu, w którym chcę pracować z Canvas.

Problem, jaki mam, polega na tym, że obawiam się wielu niezależnych graczy. Wiem, że każdy gracz wyśle ​​swoje kable x, y do serwera, a serwer je roześle, ale skąd klient wie, ilu graczy chce wyświetlić, domyślam się, że muszą być przechowywane gdzieś w tablicy.

Odpowiedz

39

Mojego realizacji będzie bardzo naiwne i uproszczone, bez odszkodowania lag, ekstrapolacja i takie, ale powinien on zwrócić uwagę na ogólną koncepcję „multiplayering” z węzła.

Myślę, że najprostszym podejściem jest posiadanie asocjacyjnej tablicy zawierającej graczy (encje) na kliencie i serwerze. Następnie od strony klienta wysyłamy komendy takie jak {action: "move", target:[32, 100]} i przetwarzamy to polecenie za pomocą logiki serwera (gdzie działa prawdziwa gra). Do każdego gniazda on connection należy przypisać obiekt odtwarzacza lub identyfikator, dzięki czemu można uzyskać dostęp to lubią:

var lastPlayerID = 0; 
var players = {}; 

server.on("connection", function(socket) { 

    var newcommer = new Player({id: lastPlayerID});  
    players[lastPlayerID] = newcommer; 
    socket.player = newcommer; // or lastPlayerID 
    lastPlayerID++;  

    socket.onMessage = function(message) { 
    this.player.doSomething(); 
    } 

}); 

Następnie każdy powiedzmy 100ms można wysłać zrzuty do wszystkich podłączonych graczy:

{ 
    timestamp: game.delta, 
    players: { 
    1: {x: 32, y: 100}, 
    2: {x: 14, y: 11} 
    } 
} 

a następnie w strona klienta odbiera dane i interpoluje ze starych do nowych wartości.

// duration in this simplified example is snapshot sending interval in [ms] 
Player.prototype.interpolateTo = function(data, duration) { 
    if(typeof data.x != "undefined") { 
    // step needed to get `destination x` within `duration` miliseconds 
    this.stepValues.x = Math.abs(data.x - this.x)/duration; 
    this.target.x = data.x; 
    } 
    // ... 
} 

// step you call for each game loop iteration 
Player.prototype.step = function(delta) { 
    if(this.x < this.target.x) { 
    this.x += delta * this.stepValues.x 
    } 
} 

Jest to wystarczający algorytm dla gry zręcznościowej z maksymalnie 20 obiektami. Zmniejszanie interwału migawki sprawia, że ​​prawie nadaje się do gry strategicznej z większą liczbą obiektów. Twoim głównym wrogiem jest wykorzystanie przepustowości, które możesz zmniejszyć, minimalizując rozmiar pakietu. Na przykład przeczytaj o BiSON, LZW i nie wysyłaj danych, które nie zmieniły się od ostatniej migawki.

Moja reputacja nie pozwala mi pisać wszystkie linki, więc załączam je tutaj: http://pastebin.com/Kh3wvF1D

Ogólne wprowadzenie do koncepcji multiplayer Glenn Fiedler:

http://gafferongames.com/networking-for-game-programmers/what-every-programmer-needs-to-know-about-game-networking/

Niektóre techniki dla wielu graczy z Quake: To da ci pojęcie o nterpolation i ekstrapolacja (przewidywanie)

http://fabiensanglard.net/quakeSource/quakeSourcePrediction.php

artykuł Valve o opóźnienia kompensacji i ogólnych optymalizacji:

https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization

techniki wielu graczy w wieku od Imperiami:

http://zoo.cs.yale.edu/classes/cs538/readings/papers/terrano_1500arch.pdf#search=%22Real%20time%20strategy%20networking%20lockstep%22

Można również przeczytać mój artykuł na temat optymalizacji wykorzystania pasma

http://rezoner.net/minimizing-bandwidth-usage-in-html5-games-using-websocket,299

+1 Ivo za Wetzel Mapple.js to wielka kupa wiedzy.

https://github.com/BonsaiDen/Maple.js

+0

Witamy w Stackoverflow! Bardzo dobra odpowiedź, trzymaj się tak, a twój brak przedstawiciela nie powinien być problemem bardzo długo. :) – RedRiderX

+0

Dziękuję za tak szczegółowe wyjaśnienie :) – Henryz

10

Gracze nie wysyłają swoich współrzędnych x, y na serwer, co pozwoliłoby na oszustwo poprzez ręczne wysyłanie współrzędnych.

Każdy gracz wysyła na serwer zdarzenia "ruch w lewo/prawo/w górę/w dół". Następnie serwer aktualizuje pozycje i okresowo nadaje pozycję (lub deltom na miejscu) wszystkich graczy.

Każdy klient pobiera wszystkie te delt gracza i renderuje je. Pod względem implementacji po stronie klienta miałbym jakiś obiekt Board/Map i miałby on listę RenderableEntities. Następnie aktualizuję RenderableEntities o nowe pozycje i okresowo przerysowuję wszystkie elementy.

Polecam przyjrzeć Maple.js

+0

Ah oczywiście. Dziękuję za wyjaśnienie. Tak więc logika będzie siedzieć na serwerze i rozgłaszać nowe pozycje dla graczy. Czy miałbym transmitować tablicę lub obiekt, a następnie zapętlać go po stronie klienta, aby wyświetlić? Rzucę okiem na Maple.js dzięki :) – Henryz

+0

@Henryz dla celów wydajnościowych nadajesz tylko obiekty, które zmieniły pozycję, a emitujesz tylko rzeczywistą różnicę pozycji zamiast całej pozycji. Struktury danych zależą od ciebie, obiekt krotek jest całkiem niezły '{id: [x, y], otherid: [x, y]}' itp. – Raynos

+0

Obawiam się, że próbuję uruchomić demo Maple.js i to w ogóle nie działa. Brak aktualizacji repo w ciągu ostatnich 3 lat. Jakieś inne sugestie, które mogłyby implementować tego rodzaju synchronizowane aktualizacje między klientem a serwerem? –

0

Innym sposobem, aby zsynchronizować X & Y współrzędne każdego gracza jest użycie Lance. Jest to biblioteka JavaScript o otwartym kodzie źródłowym, która obsługuje korektę pozycji dla wielu graczy za pomocą wiarygodnego serwera.

Przydaje się, gdy trzeba synchronizować inne rzeczy oprócz współrzędnych, takich jak nazwa obiektu lub właściwości awatara. Lub jeśli twoi gracze mają prędkości.

Powiązane problemy