Les 10 erreurs les plus courantes commises par les développeurs Unity
Publié: 2022-03-11Unity est un outil formidable et simple à utiliser pour le développement multiplateforme. Ses principes sont faciles à comprendre et vous pouvez intuitivement commencer à créer vos produits. Cependant, si certaines choses ne sont pas prises en compte, elles ralentiront votre progression lorsque vous passerez au niveau suivant, car vous passez de la phase de prototype initial ou approchez d'une version finale. Cet article fournira des conseils sur la façon de surmonter les problèmes les plus courants et d'éviter les erreurs fondamentales dans vos projets nouveaux ou existants. Veuillez noter que la perspective de cet article est davantage axée sur le développement d'applications 3D, mais tout ce qui est mentionné s'applique également au développement 2D.
Erreur commune n° 1 : sous-estimer la phase de planification du projet
Pour chaque projet, il est crucial de déterminer plusieurs choses avant même que la partie conception et programmation de l'application ne commence. De nos jours, lorsque le marketing produit est une partie importante de l'ensemble du processus, il est également important d'avoir une idée claire de ce que sera le modèle commercial de l'application mise en œuvre. Vous devez être sûr des plates-formes pour lesquelles vous publierez le produit et des plates-formes incluses dans votre plan. Il est également nécessaire de définir les spécifications minimales des appareils pris en charge (prendrez-vous en charge les anciens appareils bas de gamme ou simplement les modèles plus récents ?) pour avoir une idée des performances et des visuels que vous pouvez vous permettre. Chaque sujet de cet article est influencé par ce fait.
D'un point de vue plus technique, il devrait être nécessaire de définir à l'avance l'ensemble du flux de travail de création d'actifs et de modèles tout en les fournissant au programmeur, en accordant une attention particulière au processus d'itération lorsque les modèles auront besoin de modifications et d'améliorations supplémentaires. Vous devriez avoir une idée claire de la fréquence d'images et du budget de vertex souhaités, afin que l'artiste 3D puisse savoir dans quelle résolution maximale les modèles doivent être et combien de variations de LOD il doit faire. Il convient également de spécifier comment unifier toutes les mesures pour avoir une échelle cohérente et un processus d'importation dans toute l'application.
La façon dont les niveaux seront conçus est cruciale pour les travaux futurs car la division du niveau influence beaucoup la performance. Les problèmes de performances doivent toujours être présents à l'esprit lors de la conception de nouveaux niveaux. N'allez pas avec des visions irréalistes. Il est toujours important de se poser la question « peut-il être raisonnablement réalisé ? Sinon, vous ne devriez pas gaspiller vos précieuses ressources sur quelque chose de difficilement réalisable (au cas où cela ne ferait pas partie de votre stratégie commerciale d'en faire votre principal avantage concurrentiel, bien sûr).
Erreur Unity commune #2 : Travailler avec des modèles non optimisés
Il est essentiel que tous vos modèles soient bien préparés pour pouvoir les utiliser dans vos scènes sans modifications supplémentaires. Il y a plusieurs choses que le bon modèle doit remplir.
Il est important de régler correctement l'échelle. Parfois, il n'est pas possible de le définir correctement à partir de votre logiciel de modélisation 3D en raison des différentes unités utilisées par ces applications. Pour que tout soit correct, définissez le facteur d'échelle dans les paramètres d'importation des modèles (laissez 0,01 pour 3dsMax et Modo, définissez 1,0 pour Maya), et notez que vous devrez parfois réimporter des objets après avoir modifié le paramètre d'échelle. Ces paramètres doivent garantir que vous pouvez utiliser uniquement l'échelle de base 1,1,1 dans vos scènes pour obtenir un comportement cohérent et aucun problème de physique. Le traitement par lots dynamique fonctionnera également plus probablement correctement. Cette règle doit également être appliquée à chaque sous-objet du modèle, pas seulement au principal. Lorsque vous devez modifier les dimensions d'un objet, faites-le en ce qui concerne d'autres objets dans l'application de modélisation 3D plutôt que dans Unity. Cependant, vous pouvez expérimenter avec l'échelle dans Unity pour trouver les valeurs appropriées, mais pour l'application finale et un flux de travail cohérent, il est bon d'avoir tout bien préparé avant d'importer dans Unity.
En ce qui concerne la fonctionnalité de l'objet et ses parties dynamiques, divisez bien vos modèles. Moins il y a de sous-objets, mieux c'est. Séparez des parties de l'objet au cas où vous en auriez besoin, par exemple, pour un déplacement ou une rotation dynamique, à des fins d'animation ou pour d'autres interactions. Chaque objet et ses sous-objets doivent avoir leur pivot correctement aligné et pivoté par rapport à leur fonction principale. L'objet principal doit avoir l'axe Z pointant vers l'avant et le pivot doit être au bas de l'objet pour un meilleur placement dans la scène. Utilisez le moins de matériaux possible sur les objets (plus d'informations à ce sujet ci-dessous).
Tous les actifs doivent avoir des noms propres qui décriront facilement leur type et leur fonctionnalité. Gardez cette cohérence dans tous vos projets.
Erreur d'unité commune n° 3 : Construire une architecture de code interdépendante
Le prototypage et la mise en œuvre des fonctionnalités dans Unity sont assez faciles. Vous pouvez facilement faire glisser et déposer toutes les références à d'autres objets, adresser chaque objet de la scène et accéder à tous ses composants. Cependant, cela peut aussi être potentiellement dangereux. En plus des problèmes de performances notables (la recherche d'un objet dans la hiérarchie et l'accès aux composants entraînent une surcharge), il existe également un grand danger à rendre des parties de votre code entièrement dépendantes les unes des autres. Ou être dépendant d'autres systèmes et scripts propres à votre application, ou même de la scène actuelle ou du scénario actuel. Essayez d'adopter une approche plus modulaire et créez des pièces réutilisables qui peuvent être utilisées dans d'autres parties de votre application, ou même partagées dans l'ensemble de votre portefeuille d'applications. Créez votre framework et vos bibliothèques sur l'API Unity de la même manière que vous construisez votre base de connaissances.
Il y a beaucoup d'approches différentes pour s'en assurer. Un bon point de départ est le système de composants Unity lui-même. Des complications peuvent apparaître lorsque des composants particuliers doivent communiquer avec d'autres systèmes de l'application. Pour cela, vous pouvez utiliser des interfaces pour rendre des parties de votre système plus abstraites et réutilisables. Vous pouvez également utiliser une approche basée sur les événements pour réagir à des événements particuliers hors de portée, soit en créant un système de messagerie, soit en vous inscrivant directement à des parties de l'autre système en tant qu'auditeurs. La bonne approche consistera à essayer de séparer les propriétés gameObject de la logique du programme (au moins quelque chose comme le principe modèle-contrôleur), car il est difficile d'identifier les objets qui modifient ses propriétés de transformation, comme la position et la rotation. Cela devrait être la responsabilité exclusive de son contrôleur.
Essayez de tout bien documenter. Traitez-le toujours comme si vous deviez revenir à votre code après un long moment et vous devez comprendre rapidement ce que fait exactement cette partie du code. Parce qu'en réalité, vous arriverez assez souvent à certaines parties de votre application après un certain temps et c'est un obstacle inutile pour sauter rapidement dans le problème. Mais n'en faites pas trop. Parfois, un nom de classe, de méthode ou de propriété approprié est tout à fait suffisant.
Erreur d'unité commune n° 4 : gaspiller vos performances
La dernière gamme de téléphones mobiles, de consoles ou d'ordinateurs de bureau ne sera jamais aussi avancée qu'il n'y aura pas besoin de se soucier des performances. Les optimisations de performances sont toujours nécessaires, et elles fournissent la base pour faire la différence dans l'apparence de votre jeu ou de votre application par rapport aux autres sur le marché. Parce que lorsque vous économisez des performances dans une partie, vous pouvez l'utiliser pour peaufiner d'autres parties de votre application.
Il existe de nombreux domaines d'optimisation. L'article entier serait nécessaire juste pour gratter la surface de ce sujet. Au moins, je vais essayer de diviser ce domaine en quelques domaines principaux.
Mettre à jour les boucles
N'utilisez pas d'éléments gourmands en performances dans les boucles de mise à jour, utilisez plutôt la mise en cache. Un exemple typique est un accès à des composants ou à d'autres objets dans une scène ou des calculs intensifs dans vos scripts. Si possible, mettez tout en cache dans les méthodes Awake()
ou changez votre architecture en une approche plus événementielle pour déclencher les choses juste quand elles sont nécessaires.
Instanciations
Pour les objets qui sont instanciés assez souvent (par exemple, les balles dans un jeu FPS), créez-en un pool pré-initialisé et choisissez-en un déjà initialisé lorsque vous en avez besoin et activez-le. Ensuite, au lieu de le détruire lorsqu'il n'est plus nécessaire, désactivez-le et remettez-le dans la piscine.
Le rendu
Utilisez l'occlusion culling ou les techniques LOD pour limiter les parties rendues de la scène. Essayez d'utiliser des modèles optimisés pour pouvoir garder sous contrôle le nombre de vertex dans la scène. Soyez conscient que le nombre de sommets n'est pas seulement le nombre de sommets sur le modèle lui-même, mais il est influencé par d'autres choses comme les normales (arêtes dures), les coordonnées UV (coutures UV) et les couleurs des sommets. De plus, un certain nombre de lumières dynamiques dans la scène influenceront considérablement les performances globales, alors essayez de tout préparer à l'avance dans la mesure du possible.
Dessiner des appels
Essayez de réduire le nombre d'appels de tirage. Dans Unity, vous pouvez obtenir une réduction des appels de dessin en utilisant le traitement par lots statique pour les objets fixes et le traitement par lots dynamique pour les objets en mouvement. Cependant, vous devez d'abord préparer vos scènes et vos modèles (les objets par lot doivent partager les mêmes matériaux), et le lot d'objets dynamiques ne fonctionne que pour les modèles basse résolution. Alternativement, vous pouvez combiner les maillages par le script en un seul ( Mesh.CombineMeshes
) au lieu d'utiliser le traitement par lots, mais vous devez faire attention à ne pas créer d'objets trop volumineux qui ne peuvent pas tirer parti de l'abattage du frustum de vue sur certaines plates-formes. En général, la clé est d'utiliser le moins de matériaux possible et de les partager à travers la scène. Vous aurez parfois besoin de créer des atlas à partir de textures pour pouvoir partager un matériau entre des objets distincts. Une bonne astuce consiste également à utiliser une résolution plus élevée des textures de lightmaps de scène (pas la résolution générée, mais la résolution de sortie de la texture) pour réduire leur nombre lorsque vous éclairez dans des environnements plus grands.
Problèmes de dépassement
N'utilisez pas de textures transparentes lorsque cela n'est pas nécessaire, car cela entraînerait des problèmes de taux de remplissage. Il est acceptable de l'utiliser pour une géométrie compliquée et plus éloignée, comme des arbres ou des buissons. Lorsque vous avez besoin de l'utiliser, préférez les shaders mélangés alpha aux shaders avec test alpha ou aux shaders découpés pour les plates-formes mobiles. Pour identifier ces problèmes en général, essayez de réduire la résolution de votre application. Si cela vous aide, il est possible que vous rencontriez ces problèmes de taux de remplissage ou que vous deviez optimiser davantage vos shaders. Sinon, il peut s'agir davantage d'un problème de mémoire.
Shaders
Optimisez vos shaders pour de meilleures performances. Réduisez le nombre de passages, utilisez des variables avec une précision moindre, remplacez les calculs mathématiques compliqués par des textures de recherche pré-générées.

Utilisez toujours un profileur pour déterminer les goulots d'étranglement. C'est un excellent outil. Pour le rendu, vous pouvez également utiliser l'impressionnant Frame Debugger, qui vous aidera à en apprendre beaucoup sur la façon dont les choses fonctionnent en général lors de la décomposition des processus de rendu avec lui.
Erreur Unity commune #5 : Ignorer les problèmes de Garbage Collection
Il est nécessaire de réaliser que malgré le fait que Garbage Collector (GC) lui-même nous aide à être vraiment efficaces et concentrés sur des choses importantes dans la programmation, il y a quelques choses dont nous devrions être explicitement conscients. L'utilisation de GC n'est pas gratuite. En règle générale, nous devons éviter les allocations de mémoire inutiles pour empêcher GC de se déclencher trop souvent et ainsi de gâcher les performances par des pics de fréquence d'images. Idéalement, il ne devrait pas y avoir de nouvelles allocations de mémoire se produisant régulièrement à chaque image. Cependant, comment pouvons-nous atteindre cet objectif ? C'est vraiment déterminé par l'architecture de l'application, mais il y a quelques règles que vous pouvez suivre pour vous aider :
- Évitez les allocations inutiles dans les boucles de mise à jour.
- Utilisez des structures pour les conteneurs de propriétés simples, car elles ne sont pas allouées sur le tas.
- Essayez de préallouer des tableaux ou des listes ou d'autres collections d'objets, au lieu de les créer dans des boucles de mise à jour.
- Évitez d'utiliser des éléments mono problématiques (comme les expressions LINQ ou les boucles foreach, par exemple) car Unity utilise une version plus ancienne et pas idéalement optimisée de Mono (au moment de la rédaction, il s'agit de la version 2.6 modifiée, avec une mise à niveau sur la feuille de route).
- Chaînes de cache dans les méthodes
Awake()
ou dans les événements. - Si la mise à jour de la propriété de chaîne dans la boucle de mise à jour est nécessaire, utilisez l'objet StringBuilder au lieu de la chaîne.
- Utilisez le profileur pour identifier les problèmes potentiels.
Erreur commune d'Unity #6 : optimiser l'utilisation de la mémoire et de l'espace en dernier
Il est nécessaire de garder l'attention sur la plus faible consommation de mémoire et d'espace de l'application dès le début du projet, car il est plus compliqué de le faire lorsque vous quittez l'optimisation pour la phase de pré-version. Sur les appareils mobiles, c'est encore plus important, car nous manquons de ressources là-bas. De plus, en dépassant la taille de l'installation de 100 Mo, nous pouvons perdre une quantité importante de nos clients. Cela est dû à la limite de 100 Mo pour les téléchargements sur le réseau cellulaire, ainsi qu'à des raisons psychologiques. Il est toujours préférable que votre application ne gaspille pas les précieuses ressources téléphoniques des clients, et ils seront plus susceptibles de télécharger ou d'acheter votre application lorsque sa taille est plus petite.
Pour trouver des draineurs de ressources, vous pouvez utiliser le journal de l'éditeur où vous pouvez voir (après chaque nouvelle construction) la taille des ressources divisées en catégories distinctes, comme l'audio, les textures et les DLL. Pour une meilleure orientation, il existe des extensions d'éditeur sur Unity Asset Store, qui vous fourniront un résumé détaillé des ressources et fichiers référencés dans votre système de fichiers. La consommation réelle de mémoire peut également être vue dans le profileur, mais il est recommandé de le tester lorsqu'il est connecté pour construire sur votre plate-forme cible car il y a beaucoup d'incohérences lors des tests dans un éditeur ou sur autre chose que votre plate-forme cible.
Les plus gros consommateurs de mémoire sont souvent les textures. De préférence, utilisez des textures compressées car elles prennent beaucoup moins d'espace et de mémoire. Mettez toutes les textures au carré, idéalement, faites la longueur des deux côtés puissance de deux (POT), mais gardez à l'esprit que Unity peut également mettre à l'échelle automatiquement les textures NPOT en POT. Les textures peuvent être compressées lorsqu'elles sont sous la forme POT. Atlas textures ensemble pour remplir toute la texture. Parfois, vous pouvez même utiliser le canal alpha de texture pour obtenir des informations supplémentaires pour vos shaders afin d'économiser de l'espace et des performances supplémentaires. Et bien sûr, essayez de réutiliser autant que possible les textures de vos scènes et utilisez des textures répétitives lorsqu'il est possible de conserver une bonne apparence visuelle. Pour les appareils bas de gamme, vous pouvez réduire la résolution des textures dans les paramètres de qualité. Utilisez le format audio compressé pour les clips audio plus longs, comme la musique de fond.
Lorsque vous traitez avec différentes plates-formes, résolutions ou localisations, vous pouvez utiliser des ensembles d'actifs pour utiliser différents ensembles de textures pour différents appareils ou utilisateurs. Ces ensembles d'actifs peuvent être chargés dynamiquement à partir d'Internet après l'installation de l'application. De cette façon, vous pouvez dépasser la limite de 100 Mo en téléchargeant des ressources pendant le jeu.
Erreur d'unité commune n° 7 : Erreurs de physique courantes
Parfois, lorsque nous déplaçons des objets dans la scène, nous ne réalisons pas que l'objet a un collisionneur dessus et que changer sa position forcera le moteur à recalculer tout le monde physique à nouveau. Dans ce cas, vous devez lui ajouter le composant Rigidbody
(vous pouvez le définir sur non cinématique si vous ne souhaitez pas que des forces externes soient impliquées).
Pour modifier la position de l'objet avec Rigidbody
dessus, définissez toujours Rigidbody.position
lorsqu'une nouvelle position ne suit pas la précédente, ou Rigidbody.MovePosition
lorsqu'il s'agit d'un mouvement continu, qui prend également en compte l'interpolation. Lors de sa modification, appliquez toujours les opérations dans FixedUpdate
, pas dans les fonctions de mise à Update
. Il assurera des comportements physiques cohérents.
Si possible, utilisez des collisionneurs primitifs sur gameObjects, comme une sphère, une boîte ou un cylindre, et non des collisionneurs de maillage. Vous pouvez composer votre collisionneur final à partir de plusieurs de ces collisionneurs. La physique peut être un goulot d'étranglement des performances de votre application en raison de sa surcharge CPU et les collisions entre collisionneurs primitifs sont beaucoup plus rapides à calculer. Vous pouvez également ajuster le paramètre de pas de temps fixe dans le gestionnaire de temps pour réduire la fréquence des mises à jour fixes de la physique lorsque la précision de l'interaction physique n'est pas si nécessaire.
Erreur d'unité commune n° 8 : tester manuellement toutes les fonctionnalités
Parfois, il peut y avoir une tendance à tester manuellement les fonctionnalités en expérimentant le mode de jeu car c'est assez amusant et vous avez tout sous votre contrôle direct. Mais ce facteur cool peut diminuer assez rapidement. Plus l'application devient complexe, plus le programmeur doit répéter et réfléchir à des tâches fastidieuses pour s'assurer que l'application se comporte comme prévu à l'origine. Cela peut facilement devenir la pire partie de tout le processus de développement, en raison de son caractère répétitif et passif. De plus, parce que la répétition manuelle des scénarios de test n'est pas si amusante, il y a donc plus de chances que certains bogues survivent à l'ensemble du processus de test.
Unity dispose d'excellents outils de test pour automatiser cela. Avec une architecture et une conception de code appropriées, vous pouvez utiliser des tests unitaires pour tester des fonctionnalités isolées, ou même des tests d'intégration pour tester des scénarios plus complexes. Vous pouvez réduire considérablement l'approche d' essai et de vérification dans laquelle vous enregistrez des données réelles et les comparez à l'état souhaité.
Les tests manuels sont sans aucun doute une partie essentielle du développement. Mais sa quantité peut être réduite et l'ensemble du processus peut être plus robuste et plus rapide. Lorsqu'il n'y a aucun moyen possible de l'automatiser, préparez vos scènes de test pour pouvoir entrer dans le problème que vous essayez de résoudre le plus rapidement possible. Idéalement, quelques images après avoir appuyé sur le bouton de lecture. Implémentez des raccourcis ou des astuces pour définir l'état souhaité pour les tests. En outre, faites en sorte que la situation de test soit isolée pour être sûr de la cause du problème. Chaque seconde inutile en mode lecture lorsque les tests sont accumulés, et plus le biais initial de test du problème est important, plus il est probable que vous ne testerez pas le problème du tout, et vous espérerez que tout fonctionnera parfaitement. Mais ce ne sera probablement pas le cas.
Erreur commune Unity #9 : Penser que les plugins Unity Asset Store résoudront tous vos problèmes
Croyez-moi; ils ne le feront pas. Lorsque je travaillais avec certains clients, j'étais parfois confronté à la tendance ou aux reliques du passé d'utiliser des plugins de magasin d'actifs pour chaque petite chose. Je ne veux pas dire qu'il n'y a pas d'extensions Unity utiles sur Unity Asset Store. Il y en a beaucoup, et parfois il est même difficile de décider lequel choisir. Mais pour chaque projet, il est important de conserver une cohérence, qui peut être détruite par l'utilisation imprudente de pièces différentes qui ne s'emboîtent pas bien.
En revanche, pour les fonctionnalités qui vous demanderaient beaucoup de temps à mettre en place, il est toujours utile d'utiliser des produits bien testés de Unity Asset Store, qui peuvent vous faire gagner énormément de temps de développement. Cependant, choisissez avec soin, utilisez ceux qui ont fait leurs preuves et qui n'apporteront pas beaucoup de bogues incontrôlables et étranges à votre produit final. Les avis cinq étoiles sont une bonne mesure pour commencer.
Si la fonctionnalité que vous souhaitez n'est pas difficile à mettre en œuvre, ajoutez-la simplement à vos bibliothèques personnelles (ou d'entreprise) en croissance constante, qui pourront être utilisées ultérieurement dans tous vos projets. De cette façon, vous améliorez vos connaissances et votre ensemble d'outils en même temps.
Erreur Unity commune n° 10 : ne pas avoir besoin d'étendre les fonctionnalités de base d'Unity
Parfois, il peut sembler que l'environnement Unity Editor est tout à fait suffisant pour les tests de jeu de base et la conception de niveau, et l'étendre est une perte de temps. Mais croyez-moi, ce n'est pas le cas. Le grand potentiel d'extension de Unity vient de sa capacité à l'adapter à des problèmes spécifiques qui doivent être résolus dans divers projets. Cela peut soit améliorer l'expérience utilisateur lorsqu'il travaille dans Unity, soit accélérer considérablement l'ensemble du workflow de développement et de conception de niveau. Il serait regrettable de ne pas utiliser les fonctionnalités intégrées, telles que les tiroirs de propriétés intégrés ou personnalisés, les tiroirs de décorateurs, les paramètres d'inspecteur de composants personnalisés, ou même de ne pas créer de plugins entiers avec ses propres fenêtres d'éditeur.
Conclusion
J'espère que ces rubriques vous seront utiles à mesure que vous avancerez dans vos projets Unity. Il y a beaucoup de choses qui sont spécifiques à un projet, donc elles ne peuvent pas être appliquées, mais il est toujours utile d'avoir quelques règles de base à l'esprit lorsque l'on essaie de résoudre des problèmes plus difficiles et spécifiques. Vous pourriez avoir des opinions ou des procédures différentes sur la façon de résoudre ces problèmes dans vos projets. Le plus important est de garder vos idiomes cohérents tout au long de votre projet afin que tous les membres de votre équipe puissent clairement comprendre comment le domaine particulier aurait dû être résolu correctement.
Lectures complémentaires sur le blog Toptal Engineering :
- Développement Unity AI : un didacticiel sur les machines à états finis