In che modo un motore come Source elabora entità?


9

Sul motore Source (ed è antecessore, goldsrc, sisma) gli oggetti di gioco sono divisi in due tipi, mondo ed entità. Il mondo è la geometria della mappa e le entità sono giocatori, particelle, suoni, punteggi, ecc. (Per il motore sorgente).

Ogni entità ha una funzione think , che fa tutta la logica per quell'entità.

Quindi, se tutto ciò che deve essere elaborato proviene da una classe base con la funzione think, il motore di gioco potrebbe archiviare tutto in un elenco e, su ogni frame, scorrere e richiamare quella funzione.

A prima vista, questa idea è ragionevole, ma può richiedere troppe risorse, se il gioco ha molte entità ..

Quindi, come fa un motore come Source a prendersi cura (processo, aggiornamento, disegno, ecc.) Degli oggetti di gioco?


2
Perché è importante come <some commercial engine>funziona?
Il comunista Duck il

8
@L'anatra comunista, penso che la vera domanda qui sia più come funziona un motore di successo in modo che io possa imparare da loro?
subb

Risposte:


5

Beh, non c'è praticamente nessun altro modo per farlo - si sta andando ad avere per scorrere e la chiamata think()per ogni entità almeno una volta ogni pochi fotogrammi.

Potresti mettere le entità sul loro thread, ma poi hai l'intero incubo di sincronizzazione dello stato, che sicuramente non ne vale la pena.

A prima vista, questa idea è ragionevole, ma può richiedere troppe risorse, se il gioco ha molte entità ..

Questo è il motivo per cui il motore Source pone un limite al numero di entità che possono esistere contemporaneamente : 4096 entità, di cui solo la metà (2048) può essere collegata in rete. Supera uno di questi limiti e il gioco andrà in crash.

Questo è anche il motivo per cui, durante la creazione di una mappa, raccomandano di non utilizzare più di circa 800 entità.


Le chiamate di funzione 2 ^ 12 non sono ancora un GRANDE numero per ciascun frame?
JulioC,

@Júlio: Beh, a 60 fps sono 246k chiamate di funzione al secondo - è molto, ma sicuramente fattibile sull'hardware di oggi. Ricorda, tuttavia, che questo è il massimo assoluto consentito prima che il motore Sorgente si arresti in modo anomalo - in genere, ci sono molte meno entità su una mappa.
BlueRaja - Danny Pflughoeft il

5
Le entità hanno un tempo successivo, la funzione think non si chiama everyframe e non per tutte le entità. Ricordo che per il terremoto 2 il tempo minimo di riflessione era di 0,1 (100 msec), solo 10 fps per l'elaborazione delle entità.
bcsanches,

"Potresti mettere le entità sul loro thread, ma poi hai l'intero incubo di sincronizzazione dello stato, che sicuramente non ne vale la pena." Dai un'occhiata a
Tara

3

Questi passaggi citati sono probabilmente eseguiti in motori separati. È solo che i motori di gioco semplici di solito li hanno in un unico passaggio. La tua sequenza

for each object
    do physics
    do game logic
    draw

diventa

call physics subsystem
call game logic subsystem
call drawing subsystem

Physics Engine si occupa di posizioni e dimensioni.

Game Logic Engine si occupa dell'interpretazione di ciò che Physics Engine ha cambiato (potrebbe ostruire alcuni waypoint ...), quali obiettivi hanno i personaggi e quale comportamento dovrebbero comportarsi , esegue script programmati (questa funzione pensa ).

Drawing Engine disegna quali oggetti sono visibili e sa quali oggetti sono visibili perché i motori di Quake in qualche modo imbrogliano qui (vedi la sezione Disegna).

Il mio consiglio è di studiare piuttosto come vengono fatte le simulazioni piuttosto che i motori di gioco. Esiste un'enorme cultura pop relativa allo sviluppo dei giochi e i motori di gioco sono realizzati in linguaggi imperativi (a causa della tradizione e della velocità); quindi è stato più illuminante per me ottenere buoni libri di testo (piuttosto teoria) e POI guardare i motori (pratica) piuttosto che guardare i motori e puzzle per ore come hanno fatto.

Fisica

L'intera nozione di iterare tutte le entità e {pensare, disegnare} probabilmente porterà a problemi. Ci saranno conflitti e così via. Credo che Valve abbia Havok e immagino che Havok si occupi di fisica abbastanza corretta.

Pensare

Pensa che la funzione venga eseguita quando un tempo in un gioco è uguale al tempo nel prossimo pensiero . Funziona in questo modo nel motore Quake e il motore Quake è la base per i motori Half Life. NON viene eseguito ogni volta.

Internamente dovrebbe essere una semplice iterazione attraverso un elenco di entità e verificare se è passato il tempo per chiamare la funzione think. La complessità temporale sarà O (N), dove N è il numero di entità.

Se c'è un numero molto grande di entità Dovresti misurare quanto migliorerà il fps. Si noti che a causa della legge di Amdahl si tratta di uno speedup potenzialmente invisibile. Voglio dire, devi solo scorrere tutti gli elementi e diminuire e controllare un numero.

Vorrei accelerare ordinando le entità in base al prossimo pensiero (creare un elenco di puntatori alle entità e ordinarlo ogni volta; non array di entità, perché le entità potrebbero cambiare il loro pensiero successivo in qualsiasi momento, quindi riordinarle in array richiede O (N) anziché O ( 1) in elenco).

Dovresti anche guardare lo scheduler O (1) in Linux .

Disegnare

Il motore disegna ciò che è approssimativamente visibile dall'area in cui si trova la telecamera. Il livello di gioco è la partizione in un albero e un'area è la foglia di quell'albero. Non ti darò fastidio con i dettagli a riguardo ... Quindi se un'entità è visibile viene inserita in un insieme di entità visibili e vengono disegnate.

Memorizzano quali aree sono aree potenzialmente visibili. Si chiama "potentialy visible set", abbreviato PVS . C'è la visualizzazione del PVS , la capsula verde è il giocatore e intorno a lui viene visualizzato ciò che contiene il suo PVS.


2

Quindi, se tutto ciò che deve essere elaborato proviene da una classe base con la funzione think, il motore di gioco potrebbe archiviare tutto in un elenco e, su ogni frame, scorrere e richiamare quella funzione.

A prima vista, questa idea è ragionevole, ma può richiedere troppe risorse, se il gioco ha molte entità ..

Mettere effettivamente tutto in una grande lista è di solito meno desiderabile; se dovessi raggruppare le entità in elenchi basati, ad esempio, sul loro tipo, potresti distribuire meglio l'elaborazione su più thread. Ad esempio, se si conosce che tutte le entità di tipo Foo non interagiscono mai con altre entità durante la fase di simulazione, è possibile scaricarle completamente. Se fossero sparsi volenti o nolenti in una grande lista singolare, questo sarebbe molto più difficile da fare.

A quel punto non è nemmeno necessario derivare tutto da una classe base comune; La fonte è abbastanza esagerata con l'abuso ereditario per ciò che altrimenti potrebbe essere implementato come dati a tale riguardo.

Ovviamente avrai sempre un limite massimo al numero di entità che puoi elaborare per frame, anche se inizi a scaricare il lavoro su altri core. Non c'è modo di aggirare questo, devi solo avere un'idea di ciò che quel limite è nella tua implementazione e prendere provvedimenti per alleviarlo (abbattimento corretto delle fasi di elaborazione su oggetti che non ne avranno bisogno, evitando l'eccessiva granularità negli oggetti, ecc. cetera).


1

Quello che devi prendere in considerazione e questo seguendo il filo del pensiero delle risposte precedenti è che la tua performance sarà anche su quando e come chiamerai queste funzioni di pensiero.

Guardando il link che hai pubblicato sul motore di origine puoi anche leggere che puoi impostare i tempi di pensiero e contesti di pensiero diversi per ciascuna delle tue entità, oltre all'ovvio limite rigido che qualcuno ha già sottolineato, questa sarà la chiave per ottenere prestazioni migliori con un numero più elevato di entità, sia creando aggiornamenti graduali che diffondono l'elaborazione affamata delle prestazioni attraverso più frame di esecuzione, sia eliminando l'elaborazione non necessaria a seconda del contesto corrente (ovvero entità che sono troppo lontane o al di là della percezione del giocatore non hanno bisogno) lo stesso livello di "dettaglio del pensiero" dei personaggi vicini a un giocatore semplicemente non vedrà un personaggio a 2 miglia di distanza raccogliersi il naso).

E ci sono altri livelli più specifici di ottimizzazione a seconda della logica e della situazione di gioco specifiche.


"un giocatore semplicemente non vedrà un personaggio a 2 miglia di distanza raccogliersi il naso" Haha! Ma come mai nessuno sta sottolineando che l'utilizzo delle funzioni virtuali è molto lento?
Tara,
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.