Quali sono le insidie ​​tipiche quando si scrivono giochi con una lingua gestita come C #? [chiuso]


66

Quali insidie ​​hai riscontrato durante la scrittura di giochi per PC con un linguaggio gestito come C # e come li hai risolti?


È meglio porre questa domanda su Stack Overflow, in quanto c'è ben poco specifico per i giochi.
Chris Garrett,

31
@ Chris: Fortemente in disaccordo: la domanda menziona specificamente i giochi! I problemi che si verificano quando si deve inviare un aggiornamento ogni 16 ms sono molto diversi da quelli che si otterrebbero nella maggior parte delle applicazioni desktop.
Andrew Russell,

La domanda non è chiara. Java e C # differiscono abbastanza perché solo un consiglio molto generale sia applicabile ad entrambi. Tutte le risposte finora sono state C #. Anche la piattaforma di destinazione non menzionata - un buon consiglio può differire a seconda del dispositivo (ad es. Programmazione per un telefono cellulare, zune, xbox, diverso dalla programmazione per un PC). È stata anche una domanda abbastanza ampia a cui qualcuno ha risposto che le lingue gestite sono la "trappola".
paulecoyote,

@paulecoyote: sono passato alla domanda per chiedere solo di C #. Inoltre, poiché non è menzionata alcuna piattaforma specifica, riguarda il PC.
Michael Klement,

@Michael supponendo che la piattaforma sia un presupposto pericoloso in quanto differiscono così tanto nell'implementazione, sarebbe bene menzionare Windows in modo specifico e rilasciare "mi piace" e "Java" del tutto.
paulecoyote,

Risposte:


69

Non so molto su Java, quindi questo è dal punto di vista di uno sviluppatore .net.

Il più grande è di gran lunga la spazzatura. Il garbage collector .NET su Windows fa un lavoro fantastico e puoi scappare senza fare da baby-sitter per la maggior parte. Su Xbox / Windows Phone 7 è una questione diversa. Se si verificano bancarelle ogni pochi frame, la garbage collection potrebbe causare problemi. Al momento si attiva dopo ogni allocazione da 1 MB.

Ecco alcuni suggerimenti per gestire la spazzatura. Non dovresti preoccuparti della maggior parte di questi in realtà, ma potrebbero tornare utili un giorno.

  • Disegna il contenuto dello GC.GetTotalMemory()schermo. Questo ti dà un'approssimazione della quantità di byte allocati utilizzati dal tuo gioco. Se non si muove quasi, stai andando bene. Se sta salendo veloce, hai problemi.
  • Prova ad allocare tutti gli oggetti heap in primo piano. Se non assegni tutto prima dell'inizio del gioco, ogni volta che colpisci un mega di allocazioni, ti fermerai. Nessuna allocazione, nessuna raccolta. Così semplice.
  • Dopo il caricamento, chiama GC.Collect(). Se sai che la maggior parte delle tue grandi allocazioni è fuori strada, è bello solo far sapere al sistema.
  • NON CHIAMARE GC.Collect()tutti i frame. Potrebbe sembrare una buona idea, tenere d'occhio la tua spazzatura e tutto il resto, ma ricorda che l'unico con peggio di una raccolta di rifiuti è la raccolta di rifiuti.
  • Cerca da dove viene la tua spazzatura. Esistono alcune cause comuni come la concatenazione di stringhe anziché l'utilizzo StringBuilder(attenzione, StringBuildernon è un proiettile magico e può comunque causare allocazioni!. Ciò significa che semplici operazioni come l'aggiunta di un numero alla fine di una stringa possono creare quantità sorprendenti di immondizia) o l'uso di foreachloop su raccolte che utilizzano l' IEnumerableinterfaccia può anche creare immondizia senza che tu lo sappia (ad esempio, foreach (EffectPass pass in effect.CurrentTechnique.Passes)è comune)
  • Utilizzare strumenti come il profiler della memoria CLR per capire dove viene allocata la memoria. Ci sono un sacco di tutorial là fuori su come utilizzare questo strumento.
  • Quando sai dove stai allocando durante il gioco, vedi se puoi usare trucchi come raggruppare oggetti per ridurre il conteggio di allocazione.
  • Se tutto il resto fallisce, rendi le tue raccolte più veloci! Il GC sul framework compatto segue ogni riferimento nel codice per capire quali oggetti non sono più in uso. Rifattorizza il tuo codice usando meno riferimenti!
  • Ricordarsi di utilizzare IDisposablesu classi che contengono risorse non gestite. È possibile utilizzarli per ripulire la memoria che il GC non può liberare.

L'altra cosa a cui pensare è la prestazione in virgola mobile. Sebbene .NET JITer esegua una discreta quantità di ottimizzazioni specifiche del processore, non può utilizzare SSE o altri set di istruzioni SIMD per accelerare la matematica in virgola mobile. Ciò può causare una notevole differenza di velocità tra C ++ e C # per i giochi. Se usi mono, hanno alcune speciali librerie matematiche SIMD che puoi sfruttare.


Sono completamente d'accordo. Le implementazioni di Garbage Collector sulle piattaforme "minori" sembrano essere spazzatura completa.
Krisc,

Buon post, tuttavia per quanto riguarda la tua affermazione sull'assegnazione anticipata di oggetti heap, ti consiglio di leggere La verità sui tipi di valore
Giustino

Ottimo punto qui, quando ottimizzi il codice vale davvero la pena capire la piattaforma per cui stai cercando di ottimizzare. Questo non era in realtà un commento sui tipi di valore / tipi di riferimento, è probabile che qualsiasi oggetto di lunga durata non si trovi nello stack. Si tratta davvero di assicurarsi di ottenere il maggior numero possibile di allocazioni al momento del caricamento e di non colpire quella barriera magica da 1 MB durante il gioco. Tutte le implementazioni .net che xna prende di mira hanno anche una chiara garanzia, gli oggetti allocati vicini nel tempo saranno vicini nello spazio, il che può essere bello per perf.
Cubed2D

Sembra anche che abbia dimenticato di menzionare che l'attuale framework compatto su xbox è allergico alle chiamate al metodo inline. Conservalo per i tuoi peggiori scenari perf, tuttavia, usare le versioni ref dei metodi matematici sembra abbastanza brutto com'è!
Cubed2D

10

Una trappola per prestazioni tipiche non sta prendendo in considerazione il garbage collector nella progettazione / sviluppo del gioco. Produrre troppa spazzatura può portare a "singhiozzi" nel gioco, che si verificano quando il GC funziona per un tempo considerevole.

Per C #, l'utilizzo di oggetti valore e l'istruzione "using" possono alleviare la pressione dal GC.


3
Inoltre, puoi dire a Garbage Collector di essere eseguito esplicitamente se hai appena finito un ciclo pesante allocato / libero o se trovi che hai dei cicli di riserva.
BarrettJ,

16
La usingdichiarazione non ha nulla a che fare con la raccolta dei rifiuti! È per gli IDisposableoggetti, che servono per rilasciare risorse non gestite (ovvero: quelle che non sono gestite dal Garbage Collector ).
Andrew Russell,

9

Direi che i maggiori problemi che ho riscontrato scrivendo giochi in C # è stata la mancanza di librerie decenti. La maggior parte che ho trovato sono porte dirette, ma incomplete, o wrapper su una libreria C ++ che comportano una pesante penalizzazione delle prestazioni per il marshalling. (Sto parlando specificamente di MOgre e Axiom per la libreria OGRE e BulletSharp per la libreria di fisica Bullet)

Le lingue gestite (distinte da quelle interpretate - né Java né C # sono in realtà più interpretate) possono essere altrettanto veloci delle lingue native se si ha una buona comprensione di ciò che le rende effettivamente lente (marshalling, garbage collection). Il vero problema, penso, è che gli sviluppatori di librerie non l'hanno ancora capito.


Questo è un aspetto positivo della gestione di C # e Java anziché dell'interpretazione ... modificato la mia domanda per renderlo più accurato :)
Michael Klement

2
Il marshalling in generale è un collo di bottiglia delle prestazioni, ma aiuta anche a essere consapevoli dei tipi disponibili, tipi che possono essere associati direttamente alla memoria non gestita senza un impatto significativo sulle prestazioni. msdn.microsoft.com/en-us/library/75dwhxf7.aspx
Sean Edwards

8

Come altri hanno già detto, le pause della raccolta GC sono il problema maggiore. L'uso di pool di oggetti è una soluzione tipica.


4

C # e Java non vengono interpretati. Sono compilati in un bytecode intermedio che, dopo JIT , diventa altrettanto veloce del codice nativo (o abbastanza vicino da essere insignificante)

La più grande trappola che ho riscontrato è nel liberare risorse che influenzano direttamente l'esperienza dell'utente. Questi linguaggi non supportano automaticamente la finalizzazione deterministica come fa C ++, che se non te lo aspetti può portare a cose come mesh che fluttuano sulla scena dopo aver pensato che fossero state distrutte. (C # realizza la finalizzazione deterministica tramite IDisposable , non sono sicuro di cosa faccia Java.)

A parte questo, le lingue gestite sono davvero molto più in grado di gestire il tipo di prestazioni richieste dai giochi di quanto non meritino credito. Il codice gestito ben scritto è molto più veloce del codice nativo mal scritto.


Sì, grazie per la nota, ho già corretto la cosa interpretata / gestita;) Inoltre, buon punto con le maglie che fluttuano intorno alla scena. Non ci ho pensato quando pensavo ai problemi di GC ...
Michael Klement,

1
IDisposableconsente la pulizia deterministica di risorse time-critical e non gestite, ma non influisce direttamente sulla finalizzazione o sul garbage collector.
Sam Harwell,

4

Né Java né C # vengono interpretati. Entrambi vengono compilati in codice macchina nativo.

Il problema più grande sia per loro che per i giochi è di dover programmare in modo tale che non si raccolgano mai durante la partita. Il numero di cerchi che devi saltare per raggiungere questo risultato supera di gran lunga i vantaggi di usarli in primo luogo. La maggior parte delle funzionalità che rendono divertente l'uso di quel linguaggio per la programmazione dell'applicazione o del server devono essere evitate per la programmazione del gioco, altrimenti durante il gioco si fanno lunghe pause durante il gioco e la raccolta dei rifiuti.


La raccolta dei rifiuti può essere gestita, almeno in C #, abbastanza bene, quindi non direi che è un affare. Con il threading adeguato e la consapevolezza dello stato del programma, è possibile evitare problemi di prestazioni. È ancora un'altra cosa a cui devi pensare e rende la lingua gestita un po 'meno gestita.
Karantza,

4
Vale la pena notare che in .NET 4, il Garbage Collector supporta la raccolta in background per tutte e tre le generazioni di oggetti. Ciò dovrebbe minimizzare efficacemente l'impatto sulle prestazioni della garbage collection nei giochi. Link rilevante: geekswithblogs.net/sdorman/archive/2008/11/07/…
Mike Strobel

I raccoglitori di rifiuti si stanno evolvendo e, come notato da Mike Strobel, alcuni sono già in produzione che quasi eliminano questa trappola.
Sam Harwell,

2
Né C # né Java sono compilati in codice macchina nativo. C # viene compilato in MSIL e Java in bytecode. La garbage collection non farà pause "lunghe", ma potrebbe dare "singhiozzo".
Cloudanger,

2

Una grande trappola che vedo nel creare giochi con linguaggi come questi (o usando strumenti come XNA, motore TorqueX, ecc.) È che sarà difficile trovare un team di brave persone con l'esperienza necessaria per creare un gioco equivalente a quello che sarebbe abbastanza facile trovare persone per C ++ e OpenGL / DirectX.

L'industria degli sviluppatori di giochi è ancora fortemente impregnata di C ++ poiché la maggior parte degli strumenti e delle pipeline che vengono utilizzati per estrarre piccoli giochi grandi o semplicemente ben rifiniti sono stati scritti in C ++, e per quanto ne so TUTTI i kit di sviluppo ufficiali che puoi ottenere per XBox, PS3 e Wii sono rilasciati solo con compatibilità per C ++ (il set di strumenti XBox può essere più gestito al giorno d'oggi, qualcuno ne sa di più?)

Se vuoi sviluppare giochi per console in questo momento ottieni praticamente XNA e C # su XBox e solo in una parte laterale della libreria di giochi chiamata XBox Live Indie Games. Alcuni che vincono concorsi, ecc. Vengono scelti per portare il loro gioco sul vero XBox Live Arcade. A parte quel piano sulla realizzazione di un gioco per PC.

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.