Quels sont les pièges typiques lors de l'écriture de jeux avec un langage géré tel que C #? [fermé]


66

Quelles difficultés avez-vous rencontrées lors de la création de jeux pour PC avec un langage géré tel que C # et comment les avez-vous résolues?


Il est préférable de poser cette question sur Stack Overflow, car il n’ya que peu de choses spécifiques aux jeux.
Chris Garrett

31
@Chris: Pas du tout d'accord: la question mentionne spécifiquement les jeux! Les problèmes que vous rencontrez lorsque vous devez publier une mise à jour toutes les 16 ms sont très différents de ceux que vous rencontriez dans la plupart des applications de bureau.
Andrew Russell

La question n'est pas claire. Java et C # diffèrent suffisamment pour que seuls des conseils très généraux soient applicables aux deux. Toutes les réponses à ce jour ont été C #. La plate-forme cible n'est pas non plus mentionnée - les bons conseils peuvent varier en fonction de l'appareil (par exemple, programmation pour un téléphone portable, zune, xbox, différente de la programmation pour un PC). Il est même devenu une question suffisamment large pour que quelqu'un ait répondu que les langues gérées sont elles-mêmes le "piège".
paulecoyote

@paulecoyote: J'ai changé de question pour ne poser que des questions sur C #. De plus, comme aucune plateforme spécifique n’est mentionnée, il s’agit du PC.
Michael Klement le

@Michael en supposant que la plate-forme est une hypothèse dangereuse car ils diffèrent tellement par leur mise en œuvre, il serait bon de mentionner spécifiquement Windows et de supprimer "like" et "Java".
paulecoyote

Réponses:


69

Je ne connais pas grand chose à Java, c'est donc du point de vue d'un développeur .net.

Le plus gros de loin est la poubelle. Le ramasse-miettes .NET de Windows fait un travail fantastique, et vous pouvez vous en sortir sans laisser le bébé s'asseoir pour la plupart. Sur la Xbox / Windows Phone 7, le problème est différent. Si vous obtenez des décrochages toutes les quelques images, la récupération de place peut vous causer des problèmes. Pour le moment, il se déclenche après chaque allocation de 1 Mo.

Voici quelques conseils pour faire face aux ordures. Vous ne devriez pas avoir à vous soucier de la plupart de ces problèmes dans la réalité, mais ils pourraient vous être utiles un jour.

  • Dessinez le contenu de GC.GetTotalMemory()à l'écran. Cela vous donne une approximation du nombre d'octets alloués que votre jeu utilise. Si ça bouge à peine, tu vas bien. Si ça monte vite, vous avez des problèmes.
  • Essayez d'allouer tous vos objets de tas à l'avant. Si vous n'allouez pas tout avant le début du jeu, chaque fois que vous frappez un mégo d'allocations, vous perdez votre temps. Pas d'allocation, pas de collection. Aussi simple que cela.
  • Après le chargement, appelez GC.Collect(). Si vous savez que la plupart de vos grosses allocations sont épuisées, il est bon que le système le sache.
  • NE PAS APPELER GC.Collect()chaque image. Cela peut sembler une bonne idée, de garder le dessus de vos ordures et tout le reste, mais souvenez-vous que le seul qui soit pire qu’une collecte des ordures est la récupération des ordures.
  • Cherchez d'où viennent vos ordures. Il existe des causes courantes telles que la concaténation de chaînes au lieu de les utiliser StringBuilder(attention, StringBuildern’est pas une solution miracle, mais peut toujours provoquer des allocations!. Cela signifie que de simples opérations telles que l’ajout d’un nombre à la fin d’une chaîne peuvent créer des quantités surprenantes de déchets) ou utiliser des foreachboucles sur des collections qui utilisent l' IEnumerableinterface peut également créer des déchets sans que vous le sachiez (par exemple, foreach (EffectPass pass in effect.CurrentTechnique.Passes)c'est un problème commun)
  • Utilisez des outils tels que le profileur de mémoire CLR pour déterminer où la mémoire est allouée. Il existe de nombreux tutoriels sur l'utilisation de cet outil.
  • Lorsque vous savez où vous allouez pendant le jeu, voyez si vous pouvez utiliser des astuces telles que la mise en pool d'objets pour réduire le nombre d'allocations.
  • Si tout échoue, accélérez vos collections! Le GC sur le cadre compact suit chaque référence dans votre code pour déterminer quels objets ne sont plus utilisés. Refactor votre code utilise moins de références!
  • N'oubliez pas d'utiliser des IDisposableclasses contenant des ressources non gérées. Vous pouvez les utiliser pour nettoyer la mémoire que le CPG ne peut pas se libérer.

L'autre chose à laquelle il faut penser est la performance en virgule flottante. Bien que .NET JITer effectue un nombre suffisant d’optimisations spécifiques au processeur, il ne peut pas utiliser SSE ni aucun autre jeu d’instructions SIMD pour accélérer vos calculs en virgule flottante. Cela peut entraîner une différence de vitesse assez importante entre C ++ et C # pour les jeux. Si vous utilisez mono, ils disposent de bibliothèques de mathématiques SIMD spéciales dont vous pouvez tirer parti.


Complètement d'accord. Les implémentations du ramasse-miettes sur les plates-formes "mineures" semblent être un déchet complet.
Krisc

Bon post, cependant, en ce qui concerne votre déclaration sur "l'allocation des objets du tas à l'avance", je vous recommande de lire La vérité sur les types de valeur
Justin

Le point positif est que, lorsque vous optimisez du code, il est vraiment utile de comprendre la plate-forme pour laquelle vous essayez d’optimiser. Ce n'était pas vraiment un commentaire sur les types de valeur / types de référence, aucun objet de longue durée n'est susceptible d'être sur la pile. Il s’agit vraiment de vous assurer d’obtenir le plus grand nombre possible d’allocations au moment du chargement. Ne heurtez pas cette barrière magique de 1 Mo pendant les parties. Toutes les implémentations .net que les cibles xna ont également une garantie, les objets alloués proches les uns des autres dans le temps seront proches dans l’espace, ce qui peut être agréable pour perf.
Cubed2D

Il semble également que j’ai oublié de mentionner que le cadre compact actuel de la xbox est allergique aux appels de méthode en ligne. Conservez celui-ci pour vos scénarios de performances les plus défavorables, utiliser les versions ref des méthodes mathématiques a l'air assez laid alors qu'il est!
Cubed2D

10

Un piège de performance typique ne tient pas compte du ramasse-miettes dans la conception / le développement du jeu. Produire trop de déchets peut conduire à des "hoquets" dans le jeu, ce qui se produit lorsque le GC tourne longtemps.

Pour C #, l'utilisation d'objets de valeur et de l'instruction "using" peut réduire la pression exercée par le CPG.


3
De plus, vous pouvez indiquer au collecteur de déchets de s’exécuter explicitement si vous venez de terminer une boucle lourde d’allocation / libre ou si vous constatez que vous avez des cycles inutilisés.
BarrettJ

16
La usingdéclaration n'a rien à voir avec le ramassage des ordures! C'est pour les IDisposableobjets - qui servent à libérer des ressources non gérées (c'est-à-dire: celles qui ne sont pas gérées par le ramasse-miettes ).
Andrew Russell

9

Je dirais que le plus gros problème que j'ai rencontré en écrivant des jeux en C # a été le manque de bibliothèques décentes. La plupart des solutions que j'ai trouvées sont soit des ports directs, mais incomplets, soit des enveloppes recouvrant une bibliothèque C ++ qui entraînent de lourdes pertes de performances pour le marshaling. (Je parle spécifiquement de MOgre et Axiom pour la bibliothèque OGRE et de BulletSharp pour la bibliothèque de physique Bullet)

Les langues gérées (par opposition à Interprété - ni Java ni C # ne sont en réalité plus interprétées) peuvent être aussi rapides que les langues natives si vous comprenez bien ce qui les ralentit (marshaling, nettoyage de la mémoire). Je pense que le vrai problème, c'est que les développeurs de bibliothèques ne l'ont pas encore compris.


Voilà un bon point sur la gestion de C # et de Java au lieu d'interpréter ... modifie ma question pour la rendre plus précise :)
Michael Klement

2
Le Marshalling en général est un goulot d'étranglement en termes de performances, mais il est également utile de connaître les types compatibles, des types pouvant être mappés directement vers une mémoire non gérée sans impact significatif sur les performances. msdn.microsoft.com/en-us/library/75dwhxf7.aspx
Sean Edwards

8

Comme d’autres l’ont dit, les pauses de recouvrement du GC constituent le principal problème. L'utilisation de pools d'objets est une solution typique.


4

C # et Java ne sont pas interprétés. Ils sont compilés en un bytecode intermédiaire qui, après JIT , devient aussi rapide que le code natif (ou assez proche pour être insignifiant)

Le plus gros écueil que j'ai trouvé est de libérer des ressources qui affectent directement l'expérience utilisateur. Ces langages ne prennent pas automatiquement en charge la finalisation déterministe comme le fait le C ++, ce qui, si vous ne vous attendez pas à cela, peut donner lieu à des éléments tels que des maillages flottant dans la scène après que vous pensiez avoir été détruits. (C # accomplit la finalisation déterministe via IDisposable , je ne suis pas sûr de ce que fait Java.)

En dehors de cela, les langages gérés sont en réalité beaucoup plus capables de gérer le type de performances requises par les jeux que d'obtenir un crédit. Un code géré bien écrit est beaucoup plus rapide qu'un code natif mal écrit.


Oui, merci pour la note, déjà corrigé la chose interprétée / gérée;) En outre, bon point avec les mailles flottant autour de la scène. Je ne pensais pas à ça quand on pensait aux problèmes du GC ...
Michael Klement

1
IDisposablepermet un nettoyage déterministe des ressources urgentes et non gérées, mais n'affecte pas directement la finalisation ni le garbage collector.
Sam Harwell

4

Ni Java ni C # ne sont interprétés. Les deux sont compilés en code machine natif.

Le plus gros problème avec les deux et les jeux est de devoir coder de manière à ne jamais ramasser les ordures pendant le jeu. Le nombre d'objectifs à franchir pour accomplir cette tâche est presque supérieur aux avantages de les utiliser. La plupart des fonctionnalités qui rendent ces langages amusants à utiliser pour la programmation d'applications ou de serveurs doivent être évitées pour la programmation de jeux, sinon vous obtiendrez de longues pauses pendant le jeu, au fur et à mesure de leur disparition et de leur ramassage des ordures.


La collecte des ordures ménagères peut être traitée assez bien, du moins en C #, donc je ne dirais pas que c'est une rupture de marché. Avec un thread approprié et une connaissance de l'état du programme, vous pouvez éviter les problèmes de performances. C'est encore une autre chose à laquelle vous devez penser, et cela rend le langage géré un peu moins géré.
Karantza

4
Il convient de noter que, dans .NET 4, le ramasse-miettes prend en charge la collecte en arrière-plan pour les trois générations d'objets. Cela devrait effectivement minimiser l'impact sur la performance du ramassage des ordures dans les jeux. Lien pertinent: geekswithblogs.net/sdorman/archive/2008/11/07/…
Mike Strobel

Les éboueurs évoluent et, comme l'a noté Mike Strobel, certains d'entre eux sont déjà en production et ont presque éliminé ce piège.
Sam Harwell

2
Ni C # ni Java ne sont compilés en code machine natif. C # est compilé en MSIL et Java en bytecode. Le ramassage des ordures ne donnera pas de "longues" pauses, mais peut donner le "hoquet".
Cloudanger

2

Un grand piège que je vois en faisant des jeux avec des langages comme ceux-ci (ou en utilisant des outils comme XNA, le moteur TorqueX, etc.) est que vous aurez du mal à trouver une équipe de bonnes personnes possédant l'expertise nécessaire pour créer un jeu équivalent à ce Il serait relativement facile de trouver des personnes pour C ++ et OpenGL / DirectX.

L’industrie du développement de jeux est encore très fortement ancrée dans le C ++, car la plupart des outils et des pipelines utilisés pour lancer de petits jeux bien ou très bien conçus ont été écrits en C ++ et, autant que je sache, vous pouvez utiliser TOUS les kits de développement officiels. obtenir pour XBox, PS3 et Wii sont publiés uniquement avec une compatibilité pour C ++ (l'ensemble d'outils XBox peut être plus géré de nos jours, quelqu'un en sait plus?)

Si vous souhaitez développer des jeux pour consoles dès maintenant, vous obtenez quasiment XNA et C # sur la XBox, puis uniquement dans une partie de la bibliothèque de jeux appelée XBox Live Indie Games. Certains qui gagnent des concours, etc. sont sélectionnés pour transférer leur jeu sur le véritable XBox Live Arcade. Autre que ce plan sur la création d'un jeu pour PC.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.