Voici notre nouveau livre électronique : La pile technologique orientée données (DOTS) d'Unity pour les développeurs avancés

THOMAS KROGH-JACOBSEN / UNITY TECHNOLOGIESSenior Technical Content Marketing Manager
May 30, 2024|9 Min
Voici notre nouveau livre électronique : La pile technologique orientée données (DOTS) d'Unity pour les développeurs avancés
Cette page a été traduite automatiquement pour faciliter votre expérience. Nous ne pouvons pas garantir l'exactitude ou la fiabilité du contenu traduit. Si vous avez des doutes quant à la qualité de cette traduction, reportez-vous à la version anglaise de la page web.

La pile technologique orientée données (DOTS) d'Unity vous permet de créer des jeux complexes à grande échelle en fournissant une série d'outils d'amélioration des performances qui vous aident à tirer le meilleur parti de votre matériel cible.

Ce livre électronique de plus de 50 pages, Introduction à la pile technologique orientée données pour les développeurs Unity avancésest maintenant disponible en téléchargement gratuit. Utilisez-le comme une introduction pour mieux comprendre la programmation orientée données et évaluer si DOTS est le bon choix pour votre prochain projet. Que vous cherchiez à démarrer un nouveau projet basé sur les DOTS, ou à implémenter les DOTS pour les parties critiques de votre jeu basé sur le Monobehaviour, ce guide couvre tout le terrain nécessaire d'une manière structurée et claire.

Avec Unity 6 en avant-première et DOTS 1.0 prêt pour la production, c'est le moment idéal pour explorer les possibilités offertes par DOTS. L'e-book, écrit par Brian Will, ingénieur logiciel senior chez Unity, rejoint les échantillons mis à jour de Unity Learn, le récent bootcamp DOTS, et les échantillons GitHub dans la collection de ressources disponibles pour les développeurs qui veulent apprendre à travailler avec DOTS.

Un guide pour vous aider à décider si les DOTS sont le bon choix pour votre jeu
Dans le système de composants d'entités d'Unity, toutes les entités ayant le même ensemble de types de composants sont stockées ensemble dans le même "archétype".

L'objectif de ce livre électronique est de vous aider à prendre une décision éclairée sur la question de savoir si la mise en œuvre d'une partie ou de la totalité des paquets et des technologies DOTS est la bonne décision pour votre projet Unity existant ou à venir. Chaque partie de la pile joue un rôle dans l'amélioration de la vitesse d'exécution et de l'efficacité d'un jeu. Ce guide a pour but d'expliquer chacune de ces parties, la manière dont elles peuvent être utilisées ensemble et leur base commune, le système de composants d'entités Unity (ECS).

L'une des principales raisons d'utiliser DOTS est d'obtenir les meilleures performances de votre matériel cible, ce qui nécessite de comprendre le multithreading et l'allocation de mémoire. En outre, pour tirer parti de DOTS, vous devrez architecturer votre code et vos projets orientés données différemment de vos projets Monobehaviour basés sur C#, avec leur niveau d'abstraction plus élevé.

Regardons de plus près ce que vous trouverez dans l'e-book.

CTA : Télécharger Introduction à la pile technologique orientée données pour les développeurs Unity avancés.

Que contient l'e-book DOTS ?
 Une scène de l'exemple Firefighters, disponible sur EntityComponentSystemSamples Github

La première section du guide, que nous avons incluse ci-dessous, présente certains des facteurs qui peuvent contribuer à une mauvaise performance du processeur dans un jeu, comme la surcharge de la collecte des déchets, les données et le code qui ne sont pas compatibles avec le cache, le code machine généré par le compilateur qui n'est pas optimal, et bien d'autres choses encore.

La section suivante explique comment chacun des paquets et fonctionnalités DOTS facilite l'écriture de codes qui évitent les pièges liés aux performances du processeur. Vous trouverez des explications utiles sur les points suivants

  • Système d'emploi C#
  • Compilateur de rafales
  • Collections
  • Mathématiques
  • Entités
  • Entités Graphiques
  • Unité physique
  • Netcode pour les entités

Après un aperçu de chaque partie de la pile, vous aurez une introduction au repo GitHub EntityComponentSystemSamples, qui comprend de nombreux échantillons qui introduisent à la fois les fonctionnalités de base et avancées de DOTS. Certains des exemples du repo Github sont reproduits dans un nouveau cours Unity Learn sur DOTS, Get acquainted with DOTS.

L'autre section clé du guide DOTS est l'annexe. C'est ici que Brian Will fournit des explications détaillées sur les concepts liés à Unity ECS, notamment l'allocation de la mémoire et le ramassage des ordures, la mémoire et le cache du CPU, la programmation multithread, les limites de la programmation orientée objet et la programmation orientée données.

Extrait : À propos de la performance
Profil du Unity Profiler montrant des tâches compilées en rafale utilisant le potentiel de l'unité centrale et s'exécutant sur de nombreux threads de travail.

Si vous êtes un développeur de jeux expérimenté, vous savez que l'optimisation des performances sur les plates-formes cibles est une tâche qui s'étend sur l' ensemble du cycle de développement. Votre jeu fonctionne peut-être bien sur un PC haut de gamme, mais qu'en est-il des plates-formes mobiles bas de gamme que vous visez également ? Certains cadres prennent-ils beaucoup plus de temps que d'autres, ce qui crée des problèmes perceptibles ? Les temps de chargement sont-ils excessivement longs et le jeu se fige-t-il pendant de longues secondes chaque fois que le joueur franchit une porte ? Dans ce cas, non seulement l'expérience actuelle est médiocre, mais vous ne pouvez pas ajouter de nouvelles fonctionnalités : Plus de détails sur l'environnement et l'échelle, les mécanismes, les personnages et les comportements, la physique et les plateformes.

Quel est le coupable ? Dans de nombreux projets, il s'agit d'un rendu : Les textures sont trop grandes, les maillages trop complexes, les shaders trop coûteux ou l'utilisation du batching, du culling et du LOD est inefficace.

Un autre écueil courant est l'utilisation excessive de collisionneurs à mailles complexes, qui augmentent le coût de la simulation physique. Ou bien la simulation du jeu elle-même est lente. Le code C# que vous avez écrit et qui définit ce qui rend votre jeu unique prend peut-être trop de millisecondes de temps CPU par image.

Alors, comment écrire un code de jeu qui soit rapide, ou du moins pas lent ?

Au cours des décennies précédentes, les développeurs de jeux pour PC pouvaient souvent résoudre ce problème en attendant. Depuis les années 1970 et jusqu'au XXIe siècle, les performances des processeurs en mode "single-thread" ont généralement doublé toutes les quelques années (phénomène connu sous le nom de " loi de Moore"), de sorte qu'un jeu sur PC devenait "magiquement" plus rapide tout au long de son cycle de vie. Toutefois, au cours des deux dernières décennies, les gains de performance des processeurs à un seul fil ont été relativement modestes. Au contraire, le nombre de cœurs dans le processeur a augmenté et même les petits appareils portables comme les smartphones disposent aujourd'hui de plusieurs cœurs. En outre, l'écart entre les appareils de jeu haut de gamme et bas de gamme s'est creusé, une grande partie des joueurs utilisant du matériel vieux de plusieurs années. Attendre un matériel plus rapide ne semble plus être une stratégie viable.

La question à se poser est donc la suivante : "Pourquoi mon code CPU est-il lent ?". Il existe plusieurs pièges courants :

  • Le ramassage des ordures induit des surcharges et des pauses notables : Cela est dû au fait que le ramasse-miettes sert de gestionnaire de mémoire automatique qui gère l'allocation et la libération de la mémoire pour une application. Non seulement le ramassage des ordures entraîne une surcharge de l'unité centrale et de la mémoire, mais il interrompt parfois l'exécution de votre code pendant plusieurs millisecondes. Les utilisateurs peuvent ressentir ces pauses comme de petits accrocs ou des bégaiements plus gênants.
  • Le code machine généré par le compilateur est sous-optimal : Certains compilateurs génèrent un code beaucoup moins optimisé que d'autres, les résultats variant d'une plate-forme à l'autre.
  • Les cœurs de l'unité centrale ne sont pas suffisamment utilisés : Bien que les appareils les plus bas de gamme d'aujourd'hui soient équipés de processeurs multicœurs, de nombreux jeux se contentent de conserver la majeure partie de leur logique sur le fil principal, car l'écriture d'un code multithread est souvent difficile et sujette à des erreurs.
  • Les données ne sont pas compatibles avec la mémoire cache : L'accès aux données de la mémoire cache est beaucoup plus rapide que l'accès aux données de la mémoire principale. Cependant, l'accès à la mémoire du système peut nécessiter des centaines de cycles d'attente de la part de l'unité centrale ; il est préférable que l'unité centrale lise et écrive des données à partir de sa mémoire cache autant que possible. La façon la plus simple de procéder est de lire et d'écrire la mémoire de façon séquentielle, et la façon la plus conviviale de stocker les données est donc de les répartir dans des tableaux contigus étroitement empilés. À l'inverse, si vos données sont dispersées de manière non contiguë dans la mémoire, leur accès déclenchera généralement de nombreux et coûteux manques de mémoire cache ; l'unité centrale demande des données qui ne sont pas présentes dans la mémoire cache et doit les chercher dans la mémoire principale, plus lente.
  • Le code n'est pas adapté au cache : Lorsque le code est exécuté, il doit être chargé à partir de la mémoire du système s'il ne se trouve pas déjà dans le cache. Une stratégie consiste à privilégier l'appel d'une fonction dans le moins d'endroits possible afin de réduire le nombre de fois où elle doit être chargée à partir de la mémoire du système. Par exemple, plutôt que d'appeler une fonction particulière à différents endroits disséminés dans votre image, il est préférable de l'appeler dans une seule boucle afin que le code ne doive être chargé qu'une seule fois par image.
  • Le code est excessivement abstrait : Entre autres, l'abstraction tend à créer de la complexité à la fois dans les données et dans le code, ce qui exacerbe les problèmes susmentionnés : la gestion des allocations sans ramassage des ordures devient plus difficile ; le compilateur peut ne pas être en mesure d'optimiser aussi efficacement ; le multithreading sûr et efficace devient plus difficile, et vos données et votre code tendent à devenir moins conviviaux pour la mémoire cache. En outre, les abstractions ont tendance à répartir les coûts de performance, de sorte que l'ensemble du code est plus lent, ce qui ne permet pas d'optimiser les goulets d'étranglement.

Tous ces problèmes sont fréquemment rencontrés dans les projets Unity. Examinons-les plus précisément :

  • Bien que le langage C# permette de créer des objets alloués manuellement (c'est-à-dire des objets qui ne sont pas ramassés), la norme par défaut en C# et dans la plupart des projets Unity est d'utiliser des instances de classes C#, qui sont ramassées. Dans la pratique, les utilisateurs d'Unity ont depuis longtemps atténué ce problème grâce à une technique appelée pooling (même si le pooling va à l'encontre de l'objectif d'utilisation d'un langage de collecte de déchets). Le principal avantage de la mise en commun d'objets est la réutilisation efficace d'objets provenant d'une réserve pré-affectée, ce qui élimine la nécessité de créer et de désaffecter fréquemment des objets.
  • Dans l'éditeur Unity, le code C# est normalement compilé en code machine avec le compilateur Mono de . Pour les constructions autonomes, vous pouvez obtenir de meilleurs résultats en utilisant IL2CPP (C# Intermediate Language cross-compiled to C++), mais cela présente des inconvénients, comme des temps de construction plus longs et une prise en charge des mods plus difficile.
  • Il est courant que les projets Unity exécutent tout leur code sur le thread principal, en partie parce que c'est ce qu'Unity rend facile :
  • Les fonctions événementielles de Unity, telles que la méthode Update() de MonoBehaviours, sont toutes exécutées sur le thread principal.
  • La plupart des API Unity ne peuvent être appelées en toute sécurité qu'à partir du fil d'exécution principal.
  • Les données d'un projet Unity typique ont tendance à être structurées comme un ensemble d'objets aléatoires dispersés dans la mémoire, ce qui entraîne une mauvaise utilisation du cache. Encore une fois, c'est en partie parce que c'est ce qu'Unity rend facile :
  • Un GameObject et ses composants sont tous alloués séparément et se retrouvent donc souvent dans des parties différentes de la mémoire.
  • Le code d'un projet Unity typique a tendance à ne pas être compatible avec le cache:
  • Le langage C# conventionnel et les API de Unity encouragent un style de code orienté objet, qui tend vers de nombreuses petites méthodes et des chaînes d'appels complexes. Contrairement à une approche axée sur les données, elle n'est pas très adaptée au matériel.
  • Les fonctions d'événement de chaque MonoComportement sont invoquées individuellement et les appels ne sont pas nécessairement regroupés par type de MonoComportement. Par exemple, si vous avez 1000 Monstres MonoBehaviours, chaque Monstre est mis à jour séparément et pas nécessairement en même temps que les autres Monstres.

Le style orienté objet du langage C# conventionnel et de nombreuses API Unity conduisent généralement à des solutions à forte abstraction. Le code qui en résulte tend alors à présenter des inefficacités qui sont difficiles à démêler et à isoler.

À qui s'adresse le livre électronique DOTS ?
Un aperçu du nouveau livre électronique Introduction to the Data-Oriented Technology Stack for advanced Unity developers (Introduction à la pile technologique orientée données pour les développeurs Unity avancés).

Cet e-book est disponible gratuitement pour tout le monde, mais il est conçu pour les développeurs Unity qui ont de l'expérience dans le développement de jeux basés sur le Monobehaviour et orientés objet, mais qui ne connaissent pas Unity DOTS et le développement de design orienté données.

Nous espérons que ce guide vous aidera à comprendre DOTS et comment ces fonctionnalités peuvent bénéficier à votre prochain projet Unity, et qu'il vous sera plus facile d'obtenir la pleine valeur des échantillons disponibles sur notre repo GitHub.