Come gestire un gran numero di pickup in un gioco MMO


26

Come possono gestirli con giochi come Minecraft o qualsiasi altro gioco MMO con pickup?

Di 'terreno genera 3 gocce di raccolta di "sporcizia" ogni volta che si scava detto terreno. Supponiamo che ogni elemento abbia un'animazione di rotazione calcolata su ogni fotogramma. Se il numero di pickup nel mondo aumenta molto, sarebbe un inutile sovraccarico nel calcolo del frame per un client in un determinato server, poiché è probabile che molti di questi elementi di pickup siano lontani anni luce da te.

Quindi quello che ho pensato è che devi "fare cose" solo con i pickup vicini al giocatore locale, ma ciò implicherebbe comunque che ogni fotogramma che devo controllare se qualsiasi altro oggetto pickup sia abbastanza vicino da dover iniziare ad animare.

La mia vera domanda è: in che modo altri MMO hanno risolto questo problema?


9
Inoltre, nel contesto di Minecraft, dopo che un certo numero di elementi sono abbastanza vicini tra loro (3+ dello stesso oggetto nello stesso spazio blocchi), il server sostituisce le 3 istanze con un'istanza raggruppata che contiene il tipo di blocco ( minecraft:dirt) e un conteggio (30), in modo che quando il giocatore è abbastanza vicino da raccoglierlo, aggiunge semplicemente il maggior numero possibile di conteggio all'inventario del giocatore. Se il giocatore ha solo spazio per 6 oggetti e una pila di 30 è a terra, il giocatore raccoglierà i 6 e la pila sul conteggio del terreno è ridotta a 24.
Zymus

6
@Zymus Vale la pena notare che in realtà ha ridotto le prestazioni di tick per un numero moderato di oggetti rilasciati perché sono tutti costantemente alla ricerca di quelli vicini.
user253751

Risposte:


48

Semplicemente caricando solo quelle parti del mondo nella memoria che sono vicine al giocatore. Qualsiasi altra cosa è sospesa sul disco rigido. Quando c'è un piccolo oggetto che si trova a circa due chilometri di distanza, il giocatore non può vederlo e non può interagire con esso. Quindi non c'è motivo di aggiornarlo o inviarlo alla GPU per il rendering. Più piccolo è l'oggetto e il suo raggio di interazione, più basso è il raggio intorno al giocatore dove è necessario caricarlo.

Per quanto riguarda lo scoprire cosa c'è vicino al giocatore: ciò si riduce principalmente alla memorizzazione del mondo in una struttura di dati ottimizzata per la ricerca spaziale. I buoni candidati per questi sono hashing spaziale e alberi multidimensionali .


Grazie per la risposta rapida. Stavo pensando di usare Unity poiché immagino che utilizzi una sorta di partizionamento spaziale per controllare i collider di trigger, quindi creerei un grande collider circolare attorno al mio personaggio e ogni oggetto al suo interno sarebbe "animato". È un modo per implementare la tua risposta? Correggimi se sbaglio, evviva!
Alakanu,

2
@Alakanu Può essere usato se vuoi che gli oggetti siano visibili a lunghe distanze ma esegui determinati comportamenti ad alta intensità di calcolo quando sei vicino al giocatore (e ruotare semplicemente qualcosa attorno al suo asse y non dovrebbe essere molto costoso). Ma la vera sfida quando si implementa un gioco open world in Unity è l'istanza e la distruzione intelligente degli oggetti di gioco mentre il giocatore si muove attraverso il mondo (o ancora meglio: usa il pooling di oggetti invece di istanziare e distruggere).
Philipp,

Sì, il pooling di oggetti è obbligatorio in questa situazione :) Ok, grazie mille!
Alakanu,

3
@Alakanu Puoi controllare il concetto di "Loaded Chunks" di Minecraft per maggiori informazioni su come questa risposta si applica a quel gioco.
T. Sar - Ripristina Monica il

1
Questo non è vero solo per i pickup. QUALSIASI oggetto troppo lontano dal giocatore può essere trattato in questo modo. A volte anche oggetti vicini al giocatore. Immagina una casa con un interno completo ma non è necessario renderla finché non entri effettivamente nella casa.
Zibelas,

22

Hai due cose molto diverse da gestire:

  1. Il server deve gestire tutto il mondo, in modo autorevole. Per questo, è necessaria la comunicazione con N clienti (dove N è "massiccio").

  2. Il cliente potrebbe , in linea di principio, conoscere tutto il mondo, ma non è necessario . Per il cliente, è sufficiente sapere cosa c'è nelle vicinanze del giocatore. Supponendo ad esempio un partizionamento simile a una griglia piuttosto grossolana, dovrebbe conoscere solo la cella del giocatore e le 26 celle attorno al giocatore (o 8 celle nel caso tu abbia una griglia 2D). Una griglia un po 'più fine è migliore, ma hai l'idea.

Ora, molti pickup, cos'è "molto"? Puoi scavare forse 5 cose al secondo, ovvero due dozzine di numeri che devono essere aggiornati sul server e il server potrebbe doverli trasmettere a qualche altro giocatore la cui area di interesse si sovrappone al tuo cellulare. Per un computer, questa è una quantità di dati piuttosto ridicola e una quantità trascurabile di calcolo. Può diventare una sfida quando ci sono centinaia / migliaia di giocatori nella stessa cella (quindi il tuo partizionamento è troppo approssimativo).

Il server non ha bisogno di sapere, né di preoccuparsi della rotazione dei pickup o di tali dettagli. Perché dovrebbe?

Al cliente non importa nemmeno, dal momento che questo è solo un piacere per gli occhi che il cliente può recuperare al volo.

Ciò che è necessario dal punto di vista del server è sapere che stavi scavando in (30, 40, 50) nel nodo in cui ti trovi e decide che questo genera ad esempio tre oggetti di tipo 5 o un oggetto di tipo 7 con un conteggio di 3. Questo è tutto ciò che interessa, ed è tutto ciò che ti dice. Comprenderà inoltre che le informazioni nei dati inviati a qualcuno spostino la sua area di interesse sulla cella della griglia in seguito (supponendo che siano ancora lì per allora).

Al cliente vengono comunicati tre oggetti generati lì, blah blah. Ora, se il client visualizza una mappa di arte ASCII in cui ora c'è una 'D' o se mostra un mucchio di terra rotante, è lo stesso. Anche se le pile hanno rotazioni diverse o se solo quelle vicine al tuo giocatore ruotano è lo stesso. È solo roba che viene visualizzata sul monitor, non influisce su nessun altro.

Quindi, nel caso concreto in cui si desidera ruotare solo pile di sporcizia vicine, è possibile effettuare un controllo della portata su tutti gli oggetti che si conoscono. Poiché il set di dati non è grande, anche la forza bruta su tutto funzionerà.

Puoi (e dovresti) a seconda delle dimensioni del tuo partizionamento, eliminare banalmente le celle della griglia che sono troppo lontane.

Puoi, ovviamente, suddividere ulteriormente il tuo cellulare in sottospartizioni e usare qualcosa di super intelligente. Usa un kd-Tree se vuoi, ma non aspettarti enormi guadagni. Puoi eliminare le cose con Manhattan distace oppure puoi ordinare le tue cose in una piccola griglia di tua scelta ... ma perché?

Un controllo di distanza (distanza veramente quadrata, ma è la stessa per te) è solo due moltiplicazioni e un'aggiunta (ottimizzata per MUL, MADD, quindi in realtà solo due operazioni), seguita da una diramazione o da una mossa condizionale. È abbastanza veloce come qualsiasi altra operazione che non pota intere celle della griglia alla volta. In realtà, questo è qualcosa che si potrebbe anche fare sulla GPU ...

Vedendo come avrai qualche centinaio o al massimo qualche migliaio di controlli di distanza rispetto alla stessa posizione (la distanza al quadrato funziona bene), non hai davvero molti problemi a fare quel calcolo, anche di più in quanto è piuttosto un cache- iterazione amichevole su memoria contigua e con mosse condizionate, è sporco a buon mercato. Qualcosa di simile (pseudocodice) rot = r[i] + 1; r[i] = ((dx*dx+dy*dy) < DIST_SQ) ? rot : r[i];. Questa è un'iterazione su una matrice di poche centinaia di valori per frame. Al computer non potrebbe fregare di meno di farlo, sono carichi e archivi contigui, ALU semplice, senza rami e solo poche migliaia di iterazioni.

Questo (molti-a-uno) non è la stessa classe di problemi (molti-a-molti) del server. Davvero, il problema non è il client.


Mi dispiace, ho pensato che fosse chiaro che stavo parlando di un cliente quando ho iniziato a parlare di framerate.
Alakanu,

1
Ma il client non è mai il problema. Il client è molto non massiccio e molto locale, deve sapere molto meno del server. Idealmente, il client conosce il nodo di partizionamento spaziale (qualunque cosa sia, diciamo, griglia) in cui si trova il giocatore, e quelli immediatamente circostanti, e basta. Gli aggiornamenti sono quindi molto modesti a meno che un migliaio di giocatori non siano vicini. Normalmente, hai solo bisogno di delta per uno o due oggetti e il contenuto di un nuovo nodo della griglia dopo esserti spostato verso una direzione per più della metà della larghezza di un nodo. Tutto il resto: non è un tuo problema.
Damon,

1
Il punto è che essere troppo intelligenti può essere un'idea incredibilmente stupida. Il tuo mondo è necessariamente già diviso spazialmente, con un numero gestibile di oggetti in ciascun nodo. Le CPU moderne (e le GPU ancora di più) sono brave nell'elaborazione sequenziale di massa di dati SoA. A loro non piace la ramificazione incoerente e gli piace l'accesso alla memoria incoerente ancora meno, che è comunque esattamente ciò che fa "solo il processo nelle vicinanze". Per i numeri gestibili (alcune centinaia, alcune migliaia), "elaborare tutto" all'interno di una cella è perfettamente adeguato e probabilmente la cosa migliore che puoi fare.
Damon,

1
@Alakanu Questa mi sembra una risposta dettagliata e completa alla tua domanda. Se pensi che non sia una risposta, o l'hai fraintesa o la tua domanda è così poco chiara che è stata fraintesa da Damon, da me e da tutte le persone che hanno votato questa risposta.
David Richerby,

2
@Alakanu Passi davvero molto tempo a lamentarti delle persone che stanno cercando di aiutarti. Buona fortuna.
David Richerby,

2

@ T.Sar scrive in un commento che dovresti esaminare il concetto di "pezzo caricato" di Minecraft per ulteriori informazioni. Se lo fai, tieni presente che questo è piuttosto complicato in Minecraft a causa delle persone che costruiscono macchine nel gioco.

Segue una versione molto semplificata:

Il mondo è diviso in regioni quadrate (blocchi). In Minecraft c'è anche una divisione in altezza ma la maggior parte dei mmos non ne ha bisogno.

Il client di gioco si preoccupa solo delle regioni vicine al giocatore. È molto più semplice che disegnare un cerchio attorno al giocatore, ma perfettamente abbastanza buono.

In Minecraft, le regioni sono 16x16 blocchi e il client conosce circa 9x9 regioni, 4 regioni in ogni direzione. (4 regioni est + regione giocatore è in + 4 regioni ovest = 9 regioni totali. Stesso nord / sud)

Non c'è nulla di magico in questi numeri, usa tutto ciò che ha senso nel tuo gioco.

Il client anima solo le cose all'interno di quest'area. Il server calcola solo cose come mostri erranti in regioni vicine ad alcuni giocatori.

Quando un giocatore cammina all'interno di una regione, non accade nulla di speciale, quando attraversa un confine di regione il "bordo dell'animazione" viene spinto sopra una regione. Il client deve quindi chiedere al server le aree che vede ora.

Non c'è nulla di sbagliato nell'avere diversi limiti di animazione nidificati. Ad esempio, gli oggetti animati cadono in un'area 3x3, i mostri erranti in un'area 5x5 e mostrano semplicemente il paesaggio in un'area 9x9.

Il server mantiene una "versione bloccata" delle regioni che nessun giocatore vede. Se ciò richiede molta memoria, è possibile scaricarli dopo un po '. Quando arriva un giocatore successivo, la regione viene ricaricata senza che l'oggetto cada. La prossima volta devi essere più veloce, Giocatore 1.


La distanza di disegno è regolabile, ma in questo caso 8 blocchi sono 9x9 ed è una decisione sul lato client, tuttavia può informare il server per velocizzare le cose (quindi il server non invia dati che il client non renderà). Inoltre ... Doom e Quake non hanno risolto quel problema nel rendere solo ciò che ha senso?
SparK,

Informazioni sulla scomparsa degli oggetti rilasciati ... in Minecraft l'oggetto "invecchia" solo quando c'è un giocatore nelle vicinanze. Quindi puoi "salvare" un oggetto lasciato cadere in un pezzo scaricato e farlo in un secondo momento.
SparK,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.