Come funzionano i proiettili nei videogiochi?


64

Mi sono imbattuto in questa domanda quando stavo progettando un videogioco in C #.

Se consideriamo giochi come Battlefield o Call of Duty , centinaia o addirittura migliaia di proiettili volano contemporaneamente. Gli eventi vengono costantemente attivati ​​e, per quanto ne so, ciò risucchia molta potenza di elaborazione ... o lo fa? Voglio sapere come i vari sviluppatori di giochi gestiscono i proiettili (2D e 3D) e qual è il metodo più efficiente per ognuno.

Ho letto la domanda Come vengono simulati i proiettili nei videogiochi? ma non tocca come funzionano i proiettili dal punto di vista della progettazione del programma.

Ho avuto un paio di idee, ma ognuna ha i suoi svantaggi:


Metodo più efficiente che mi viene in mente (per i giochi 2D):

Supponiamo che dovessi creare una classe chiamata Bullet e per quanto tempo l'utente tiene premuto un pulsante, ogni 0,01 secondi verrebbe creato un oggetto Bullet. Questo proiettile ha:

  • 1 velocità

  • 2 Posizione iniziale della posizione da cui viene sparato

  • 3 trama Sprite

  • 4 Un effetto al colpo

Dal momento che il proiettile sarebbe la sua classe, poteva gestire da solo gli ascoltatori di disegno, movimento e azione.

Non sarebbe difficile per il processore elaborare migliaia di questi oggetti che vengono istanziati, quindi distrutti (quando viene attivato l'effetto al colpo)? Spazio RAM?


Metodo efficiente per i giochi 3D - Un altro pensiero che avevo era:

Diciamo che creo una classe di armi. Questa arma ha varie caratteristiche, alcune delle quali:

  • 1 Rileva dove sta puntando l'arma e determina se sta guardando un bersaglio

  • 2 Attiva un'animazione della sparatoria

  • 3 Ha un metodo doDamage () che indica qualcosa per sottrarre la salute da qualunque cosa sia puntata la pistola

  • 4 Notifica una classe di animazione proiettile quando viene premuto il pulsante

Potrei quindi creare una classe statica, ad esempio BulletAnimation, che potrebbe ottenere una notifica da dove si trova la pistola che l'ha attivata, dove è puntata quella pistola (per la destinazione del proiettile) e informazioni su uno sprite e velocità appropriati da usare per il proiettile . Questa classe quindi disegna sprite (su un nuovo thread forse, idk) basato su entrambe le posizioni e lo sprite desiderato, per simulare un proiettile sparato da una pistola.


Quest'ultimo sembra molto più difficile da codificare e non ci vorrebbe molta potenza di elaborazione per chiamare costantemente l'elettricità statica per farlo per migliaia di proiettili alla volta? Anche ottenere aggiornamenti costanti su entrambe le posizioni iniziale e finale sarebbe difficile.

La mia domanda è: qual è il modo più efficiente in cui i creatori di giochi lo fanno? Questo metodo cambia da giochi 2D a giochi 3D?


16
Nota che anche oggi la maggior parte dei giochi non simula il volo dei proiettili. Per qualsiasi cosa considerata "abbastanza veloce", viene invece eseguito un semplice hitcan - in pratica, si presume che l'impatto si verifichi contemporaneamente alla pressione del grilletto. In ogni caso "centinaia o migliaia di proiettili" non è davvero una grande quantità - è qualcosa che i giochi avevano fin dalle prime console (vari giochi infernali), migliaia di volte meno potenti delle macchine di oggi. Devi solo assicurarti di fare solo il minor lavoro possibile per proiettile :)
Luaan

42
I proiettili di solito funzionano tramite la pew-pew-pewtecnologia :)
MonkeyZeus,

5
Non ci sono mai centinaia o migliaia di proiettili che volano contemporaneamente. Non c'è una pistola che li spari così in fretta. Perfino la potente falange supera 75 proiettili al secondo. Sulla base del "Campo di tiro effettivo" elencato su Wikipedia, i proiettili volano al massimo per circa 3 secondi, quindi una falange può mettere in aria 225 proiettili contemporaneamente. Un M16 arriva a circa 12 round / sec e non è in grado di sostenere quella velocità (il massimo per il fuoco sostenuto è 0,25round / sec). Solo che non ci sono così tante pistole che sparano alla volta!
Cort Ammon,

3
Solo per sottolineare questo, non è mai bello creare oggetti singole classi quando sono così semplici. È molto meglio avere un'istanza bulletField per ogni tipo di proiettile. Il leggero sovraccarico di lunghezza del codice e quant'altro ti farà risparmiare una parola in più di 4 byte per punto elenco (se type è un numero intero). Inoltre, un oggetto può facilmente scansionare un elenco.
The Great Duck

4
@Cort - è vero supponendo che ci sia solo un'arma da fuoco nello spazio di gioco. L'OP ha menzionato giochi come Battlefield e CoD, in cui dozzine di giocatori potevano sparare pistole automatiche contemporaneamente. Non è irragionevole che ci sia un numero ridicolo se ogni round fosse effettivamente rappresentato fisicamente nello spazio.
Jesse Williams,

Risposte:


78

Posso certamente capire perché penseresti che sarebbe difficile simularli, ma ci sono abbastanza vincoli sui proiettili (tutti i proiettili, davvero) per renderli più facili.

  1. Sono generalmente simulati come un singolo punto, anziché come qualcosa con il volume. Questo rende il rilevamento delle collisioni molto più semplice, poiché ora ho solo bisogno di fare collisioni su superfici molto semplici, come una linea contro un cerchio.

  2. Sappiamo come si sposteranno, quindi non ci sono molte informazioni che dobbiamo archiviare o calcolare per loro. Il tuo elenco era ragionevolmente accurato, generalmente avremo alcune altre cose associate, come chi ha sparato il proiettile e di che tipo è.

  3. Poiché tutti i proiettili saranno molto simili, possiamo pre-allocarli, per evitare tutto il sovraccarico di crearli dinamicamente. Posso allocare un array di 1000 proiettili e ora è possibile accedervi con un solo indice e sono tutti sequenziali in memoria, quindi elaborarli sarà veloce.

  4. Hanno una durata / intervallo fissi, quindi posso far scadere i vecchi proiettili e riciclare la memoria in nuovi proiettili molto rapidamente.

  5. Una volta che colpiscono qualcosa, posso anche farli scadere, quindi hanno una vita finita.

  6. Dato che sappiamo quando sono stati creati, se ne abbiamo bisogno di nuovi e non ne abbiamo uno libero nella nostra lista pre-allocata, posso semplicemente prendere quelli più vecchi e riciclarli, e le persone non noteranno se i proiettili scadono leggermente in anticipo .

  7. Sono resi come sprite (di solito) o come modelli poli bassi e occupano pochissimo spazio sullo schermo, quindi sono veloci da renderizzare.

Tenendo conto di tutte queste cose, i proiettili tendono ad essere relativamente economici. Se il nostro budget venisse mai consumato dai proiettili e rendendoli, generalmente lo ridisegneremmo per limitare il numero di colpi che puoi sparare alla volta (lo vedrai in molti vecchi giochi arcade), usa armi a raggi che si muovono all'istante o rallenta la frequenza di fuoco per assicurarci di rispettare il budget.


12
Non sono d'accordo con 5), che in realtà rende tutto complicato nei giochi moderni. Nei tiratori precedenti questo era accettabile, al giorno d'oggi anche il COD permette ai giocatori di sparare attraverso le pareti di legno. 6) sarebbe inaccettabile per qualsiasi sistema competitivo, sebbene sarebbe un problema raro.
SBoss

17
@SBoss quindi riformulare: "Una volta che colpiscono qualcosa che non riescono a penetrare, posso anche farli scadere, quindi hanno una vita finita.". E per 6 puoi ottenere il caso peggiore limitando la massima velocità di fuoco per personaggio e quindi mantenendo una serie di lunghezzenum_characters * max_bullets_per_character
maniaco del cricchetto

14
@SBoss Penso che # 6 sia più adatto ad es. giochi spaziali dall'alto verso il basso, in cui un proiettile che si muove lentamente potrebbe percorrere una grande distanza fuori dallo schermo prima di colpire qualcosa / scomparire. Ovviamente non è un problema nei giochi di tipo CoD, in cui i proiettili si muovono rapidamente e raggiungono rapidamente i confini del mondo.
BlueRaja - Danny Pflughoeft,

1
La stragrande maggioranza dei giochi NON modella affatto proiettili (balistica esterna). La maggior parte dei giochi utilizza una tecnica chiamata "hit-scanning".
Aron,

44

Probabilmente uno dei modi più efficienti per implementare i proiettili è usare quello che è noto come hitscan . È piuttosto semplice nella sua implementazione: quando spari, controlli per vedere a cosa punta la pistola (possibilmente usando un raggio per trovare l'entità / oggetto / mesh più vicini), e poi lo "colpisci", facendo danni. Se vuoi far sembrare che sia stato sparato un proiettile invisibile reale e in rapido movimento, puoi falsificarlo aggiungendo un leggero ritardo che dipende dalla distanza prima di fare danni.

Questo approccio presuppone essenzialmente che il proiettile sparato abbia una velocità infinita, ed è tipicamente usato per tipi di armi come laser e fasci di particelle / cannoni e forse alcune forme di fucili di precisione .

L'approccio successivo sarebbe quello di modellare il proiettile sparato come un proiettile, che è modellato come la propria entità / oggetto soggetto a collisione, e possibilmente la gravità e / o la resistenza dell'aria che ne altera la direzione e la velocità. È più complesso dell'approccio hitcan a causa delle equazioni di fisica extra e più intenso in termini di risorse a causa della presenza di un vero oggetto proiettile, ma può fornire proiettili più realistici.

Per quanto riguarda la gestione delle collisioni tra proiettili a base di proiettili e altri oggetti nel gioco, il rilevamento delle collisioni può essere notevolmente semplificato ordinando i tuoi oggetti in quad o ocre . Gli octrees sono usati principalmente nei giochi 3d, mentre i quadtrees possono essere usati nei giochi 2d o 3d. I vantaggi dell'utilizzo di uno di questi alberi è che è possibile ridurre notevolmente il numero di possibili controlli di collisione. Ad esempio, se hai 20 oggetti attivi nel livello, senza usare uno di questi alberi, dovrai controllare tutti i 20 per una collisione con il proiettile. Dividendo i 20 oggetti tra le foglie (nodi finali) dell'albero, puoi ridurre il numero di controlli fino a quando molte entità sono presenti nella stessa foglia del proiettile.

Per quanto riguarda questi approcci - hitcan e proiettile, entrambi possono essere usati liberamente nei giochi 2D o 3D. Dipende più da cosa sia l'arma e da come il creatore ha deciso che l'arma funzionerà.


Le informazioni sul modello di progettazione, Hitscan e quad / octrees aiutano davvero. Inoltre, grazie per le informazioni!
Eric

8
Se non fai causa a un hitcan ma simuli i proiettili, possono spostarsi attraverso oggetti sottili perché si muovono così velocemente. In tal caso, ricorda che tutto nei giochi è falso. Anche se un proiettile è lungo solo pochi centimetri, è possibile eseguire il rilevamento delle collisioni come se fosse lungo un metro. In questo modo puoi comunque eseguire piacevoli cadute di proiettili e simulazioni temporali di volo senza doversi preoccupare troppo dei proiettili che si deformano attraverso gli oggetti senza colpirli :).
Roy T.

2
Ci sono giochi in cui la fisica dei proiettili (al contrario, diciamo, dei proiettili di cannone) rispetta cose come la gravità (proiettile), la resistenza dell'aria? (Cioè, giochi oltre a giochi speciali in cui il focus è il tiro al bersaglio di precisione o qualcosa del genere: FPS, ecc.) Non sono un giocatore, ma sono sorpreso che quel livello di fedeltà sia (anche a volte) necessario.
davidbak,

3
@davidbak: dipende fortemente dal tipico incontro di gioco e dal realismo atteso dal genere di gioco. Se stai combattendo principalmente (solo?) Combattimenti ravvicinati, allora davvero quel livello di fedeltà non è necessario. Ma se esiste l'opzione per il combattimento a lungo raggio (ad es. Cecchini o arcieri in un ambiente più simile a un gioco di ruolo), oggigiorno la gravità che colpisce i missili è un po 'attesa. Se punti il ​​lanciarazzi verso l'alto, ti aspetteresti comunque che il razzo atterri ed esploda da qualche parte, no? Tuttavia, le traiettorie non sono sempre calcolate dalla fisica reale, solo un'approssimazione (per motivi di performance)
hoffmale

1
@davidbak Battlefield da quando Bad Company 2 ha avuto un proiettile. Sia per fucili, pistola, proiettili, razzi, tutto. Battlefield 3 è gratuito su Origin, puoi controllare (IIRC). Battlefield 4 ovviamente ha anche questa "caratteristica". Un altro gioco in cui puoi vedere questo è "Sniper Elite". 2 o 3 sono i titoli più recenti. La fisica gioca un ruolo importante in quel gioco.
Apache,

7

Non sono affatto un esperto, ma per rispondere alla tua domanda, sì, avresti bisogno di molte delle cose che menzioni.

Per il tuo esempio 2D, potresti avere una posizione e una velocità per un proiettile. (Potresti anche aver bisogno di una vita o di una distanza massima, a seconda di come implementi i tuoi proiettili.) Di solito ciò implicherebbe 2 (x, y) valori. Se fossero float, erano 16 byte. Se hai 100 proiettili, sono solo 1600byte o circa 1,5k. Non c'è niente su una macchina oggi.

Successivamente, menzioni gli sprite. Avresti bisogno di un solo sprite per rappresentare ogni proiettile. Le sue dimensioni dipendono dalla profondità di bit che stai disegnando e da quanto grande dovrebbe apparire sullo schermo. Anche non compresso, per esempio, 256x256 in virgola mobile a 32 bit per canale, questo è 1 MB per lo sprite. (E sarebbe molto grande!) Disegneresti lo stesso sprite in ogni posizione del proiettile, ma non ci vorrà memoria aggiuntiva per ogni copia dello sprite. Sarebbe simile per un effetto al colpo.

Accenni di sparare ogni 0,01 secondi. Sarebbero 100 proiettili al secondo dalla tua arma. Anche per un'arma futuristica è abbastanza! Secondo questo articolo di Wikipedia :

Quando si preme il grilletto, la velocità con cui vengono sparati i colpi è la frequenza ciclica. Le tipiche velocità di fuoco cicliche sono 600-900 giri / min per fucili d'assalto, 1.000-1.100 giri / min in alcuni casi, 900-1.200 giri / min per mitra e mitragliatrici e 600-1.200 giri / min per mitragliatrici. I minifucili M134 montati su elicotteri d'attacco e altri veicoli da combattimento possono raggiungere velocità di fuoco di oltre 100 colpi al secondo (6.000 giri / min).

Quindi questo sarebbe il tasso di un elicottero d'attacco!

Per un grande mondo come menzionato in Battlefield / Call of Duty / ecc., Possono calcolare tutte quelle posizioni di proiettile, ma non trarne tutte se l'azione è lontana. Oppure potrebbero non simularli finché non ti avvicini. (Devo ammettere che sto indovinando un po 'su questa parte perché non ho lavorato su qualcosa di così grande.)


6

Non sarebbe difficile per il processore elaborare migliaia di questi oggetti che vengono istanziati, quindi distrutti (quando viene attivato l'effetto al colpo)? Spazio RAM?

Penso che tu stia sottovalutando la velocità dei computer. Questo a volte era un problema sui sistemi degli anni '80 e '90. In parte è il motivo per cui gli Space Invaders originali non ti permetteranno di sparare un altro proiettile fino a quando quello attuale non ha colpito. Alcuni giochi hanno sofferto di "rallentamento" se c'erano troppi sprite sullo schermo.

Oggi, però? Hai una potenza di elaborazione sufficiente per migliaia di operazioni per pixel necessarie per eseguire trame e illuminazione. Non ci sono problemi con migliaia di oggetti in movimento; questo ti permette di fare terreno distruttibile (ad es. Red Faction) in cui ogni frammento esegue l'elaborazione delle collisioni con altri frammenti e segue una curva balistica.

Devi essere un po 'attento in modo algoritmico - non puoi fare l'approccio ingenuo di controllare ogni oggetto contro ogni altro oggetto quando hai migliaia di oggetti. I proiettili generalmente non controllano le collisioni con altri proiettili.

Un piccolo aneddoto laterale: la prima versione di Doom in rete (l'originale degli anni '90) ha inviato un pacchetto sulla rete per ogni proiettile sparato. Quando uno o più giocatori hanno ottenuto la mitragliatrice, questo potrebbe facilmente sopraffare la rete. Gli anni '90 erano pieni di persone che giocavano illegalmente a Doom nelle università o nelle reti di lavoro e si mettevano nei guai con i loro amministratori di rete quando la rete divenne inutilizzabile.


Mi chiedo come abbia funzionato la motosega in questo contesto
riassunto il

1
IIRC, il vero problema con il primo destino della rete è che ha evitato la necessità di inviare ciascun pacchetto separatamente a ogni giocatore avversario utilizzando invece i pacchetti di trasmissione. Ciò ha ridotto il numero di pacchetti inviati, ma purtroppo ha comportato un notevole carico della CPU su ogni macchina della rete, inclusi quelli che non stavano giocando.
supercat

1

Sono tutt'altro che un esperto, ma ho lavorato su un gioco sparatutto 2D multiplayer nel mio tempo libero.

Il mio metodo

Esistono diverse classi di proiettili tra il client e il server (anche quando si gioca offline, un'istanza del server viene avviata su un processo separato e collegata dal gioco "principale").

Ogni segno di spunta (60 al secondo) il client determina un rilevamento tra il puntatore del mouse del giocatore e il centro dello schermo (dove si trova il suo personaggio) e fa parte delle informazioni inviate al server. Se anche il giocatore spara in quel momento (supponendo che l'arma sia caricata e pronta), viene creata un'istanza di proiettile sul lato server, con semplicemente alcune coordinate e un danno base (che deriva dalle statistiche dell'arma che ha sparato esso). L'istanza bullet utilizza quindi alcune funzioni matematiche per calcolare una velocità X e Y dal rilevamento che abbiamo raccolto dal client.

Per ogni tick successivo, il proiettile si sposta da quelle coordinate e riduce il danno base di un valore predefinito. Se questo valore scende al di sotto di 1 o se colpisce un oggetto solido nel mondo, l'istanza del proiettile viene eliminata e poiché le collisioni dei punti di prova sono incredibilmente economiche in 2D, anche le armi a fuoco rapido hanno un impatto trascurabile sulle prestazioni.

Per quanto riguarda il client, le informazioni sul proiettile non vengono effettivamente ricevute sulla rete (si sono rivelate dispendiose nei test), invece come parte dell'aggiornamento per tick ogni personaggio ha un booleano "sparato", che se vero il client crea un locale oggetto bullet che funziona quasi esattamente come quelli del server, l'unica differenza è che ha uno sprite.

Ciò significa che sebbene il proiettile che vedi non sia una rappresentazione del tutto accurata sul server, qualsiasi differenza sarebbe appena percettibile se non per un giocatore e i vantaggi della rete superano qualsiasi incoerenza.

Nota su diversi metodi

Alcuni giochi, incluso il mio, muovono i proiettili ogni segno di spunta come se fossero oggetti fisici, mentre altri semplicemente creano un vettore nella direzione del tiro, o calcolano l'intero percorso del proiettile nel segno di spunta che viene creato, ad esempio in Counter- Giochi di sciopero. Ci sono alcuni trucchi sul lato client per mascherarlo, come un'animazione del lancio del proiettile, ma a tutti gli effetti ogni proiettile è solo un laser .

Con i modelli 3D che possono avere hitbox complesse, è standard testare PRIMA le collisioni con un semplice riquadro di delimitazione e, se ciò riesce, passare a un rilevamento più "dettagliato" delle collisioni.


0

Si chiama rilevamento delle collisioni. I computer a 8 bit lo hanno fatto usando la grafica dei missili del giocatore nell'hardware. I motori di gioco moderni utilizzano motori fisici e algebra lineare. La direzione corrente di un'arma è rappresentata come un vettore 3D. Ciò fornisce una linea infinita nella direzione del fuoco. Ogni oggetto in movimento ha una o più sfere di delimitazione in quanto è l'oggetto più semplice per rilevare una collisione con una linea. Se i due si intersecano, è un successo, in caso contrario, non c'è successo. Ma lo scenario potrebbe essere in mezzo, quindi anche questo deve essere verificato (usando i volumi gerarchici di delimitazione). L'oggetto più vicino che ha un'intersezione è quello che è stato colpito.

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.