Pourquoi les structures de dossiers sont-elles importantes ?

En tant que consultant au sein de l'équipe chargée de la réussite des clients, on me pose souvent la question suivante : "Avons-nous bien conçu nos ensembles d'actifs ?" ou une variante de cette question. Ma réponse est toujours la même : Cela dépend du projet. Je discute ensuite avec les clients des spécificités. Bien que cette réponse soit exacte, elle ne fournit pas d'indications pour aider les projets futurs.
Bien qu'il s'agisse d'un dilemme courant, j'ai du mal à trouver une réponse plus générale à la question (malgré nos lignes directrices et meilleures pratiques existantes pour les Addressables). Certains utilisateurs ne savent pas si les paquets sont corrects au départ, et mon temps est souvent limité à l'examen des projets pour l'optimisation de la mémoire. Cela signifie que je ne peux pas connaître l'utilisation prévue de chaque élément d'un projet. En outre, lorsqu'un projet prend de l'ampleur, il peut devenir impossible pour une seule personne de répondre à la même question pour chaque actif.
Finalement, j'ai pris conscience de la situation : La question de la constitution correcte de paquets d'actifs limite la perspective de trouver une réponse plus générale. Je m'explique.
Le chargement d'un ensemble d'actifs occupe de la mémoire. Par conséquent, si les actifs sont regroupés avec d'autres actifs qui ne sont pas chargés et déchargés en même temps, l'utilisation de la mémoire n'est pas aussi optimale qu'elle pourrait l'être. Par conséquent, la question de savoir si un actif se trouve dans le bon paquet ou si les paquets contiennent les bons actifs revient essentiellement à se demander si l'on charge les bons actifs au bon moment. La réponse à la question de savoir quand des actifs spécifiques doivent être chargés dépend de l'utilisation prévue de ces actifs, ce qui explique pourquoi la réponse est généralement : "Cela dépend du projet". Dans la pratique, j'ai constaté que le fait de connaître l'utilisation prévue de la ressource permet de savoir comment les ressources sont chargées en mémoire et comment elles doivent être regroupées.
L'expression "usage prévu" est donc essentielle : Qui sait quelle est l'utilisation prévue d'un actif ? Comment communiquer cette intention à tout le monde ? Enfin, quand cela doit-il se produire ?
À mon avis, il y a un moment où la réponse à cette question est claire comme de l'eau de roche : lors de la création et de la modification des actifs. Qu'il s'agisse d'une texture spécifique pour un personnage, d'un shader d'éclairage global ou d'un maillage d'arbre à utiliser dans plusieurs niveaux de jeu, le créateur connaît l'utilisation prévue et est donc le mieux placé pour communiquer cette intention. Les artistes peuvent communiquer cette intention en appliquant une convention de dénomination des fichiers cohérente et en regroupant dans un même dossier les fichiers destinés aux mêmes usages.
Les programmeurs et les autres membres de l'équipe peuvent alors utiliser ces informations pour décider quand et si un actif doit être regroupé avec d'autres actifs qui seront chargés simultanément. C'est pourquoi l'utilisation prévue d'un bien doit être très claire - d'un seul coup d'œil - pendant toute la durée d'un projet, et le répertoire des fichiers constitue la source de vérité pour tous les membres de l'équipe.
Dans cet article de blog, j'examinerai quelques bonnes pratiques et cas limites courants qui, je l'espère, vous aideront à mieux structurer vos futurs projets. Tout d'abord, examinons quelques-unes des structures de dossiers les plus courantes et les problèmes qu'elles posent.
D'après mon expérience, il existe quatre types de structures de dossiers : aléatoire, par type de bien, par caractéristique et par objectif. Parmi celles-ci, la dernière est de loin la meilleure, car elle traduit l'intention et convient donc le mieux à une stratégie optimale de regroupement.
L'aléatoire n'est pas un phénomène que je vois souvent. Cela se produit le plus souvent avec des développeurs solitaires qui peuvent ne pas être familiarisés avec le développement de logiciels, ce qui devient intenable, pour des raisons évidentes, lorsqu'un projet prend de l'ampleur ou devient plus complexe. L'absence de structure, ou une structure aléatoire, s'accompagne de nombreux problèmes : les actifs sont difficiles à trouver et il est pratiquement impossible de comprendre l'usage qui en est fait.
La structuration par type d'actif est assez courante, car c'est ainsi que de nombreux artistes travaillent sur les actifs avant de les importer dans le moteur. Si vous connaissez le type d'actif, il est facile de trouver son emplacement, mais tout le reste est obscur. Même avec une bonne convention de dénomination, il peut être difficile de savoir si un personnage, un environnement, une interface utilisateur ou une combinaison des trois nécessite un shader, une texture, un maillage, etc. spécifique. Un répertoire de fichiers approprié ne doit pas masquer l'information, mais la révéler.
Les structures de dossiers par caractéristiques sont rares, mais semblent judicieuses à première vue. De nombreuses entreprises se divisent en équipes spécialisées, alors pourquoi ne pas regrouper les données de la même manière ? Ce n'est pas ainsi que le jeu utilise les données. Dans le passé, j'ai vu des exemples, tels que les shaders et l'audio, qui devraient être regroupés, mais parce qu'ils sont créés par des équipes différentes, cette vérité devient obscure.
Un répertoire de fichiers avec une convention de dénomination claire basée sur l'objectif des actifs permet de contourner ces problèmes. Pour illustrer cela, j'utiliserai un exemple de jeu fictif appelé "Dinosaur Brawl".
Pour les besoins de cet exemple, Dinosaur Brawl est un jeu d'action-aventure en 3D à la troisième personne dans lequel le joueur choisit un dinosaure qu'il contrôle dans un vaste monde ouvert avec de multiples biomes, en combattant d'autres dinosaures et créatures préhistoriques pour tenter de devenir plus fort et de transmettre ses gènes à la génération suivante - le tout dans une lutte géante pour survivre à l'ère glaciaire qui s'annonce. Le jeu est conçu pour la téléphonie mobile et certaines données seront distribuées dans le cadre de l'application originale. Le reste sera téléchargé à partir d'un CDN selon les besoins.
Nous pouvons concevoir une structure de dossier générale pour l'ensemble du projet à partir du synopsis ci-dessus. Puisque le joueur peut sélectionner et combattre d'autres dinosaures, il est logique de créer un dossier par dinosaure qui contiendra tous les actifs spécifiques à ce dinosaure : maillages, effets sonores, textures, animations, effets de particules, etc. Je les classerai dans la catégorie des atouts uniques.
Comme il s'agit d'un jeu d'action, les environnements seront des biomes distincts. Il convient donc de créer un dossier unique pour chaque biome, ou niveau, du projet : plaines, déserts, toundra, marécages, volcans, etc.
Bien sûr, il y aura aussi des atouts dont la présence sera nécessaire pour des parties entières du jeu. Les éléments de l'interface utilisateur en font partie. Vous pouvez considérer ces actifs comme des actifs globaux. Tout comme nous avons créé un dossier pour tous les actifs uniques, il doit y avoir un dossier global au sommet de la hiérarchie des dossiers. Par exemple, un dossier Global UI, un dossier Global Dinosaur, un dossier Global Environment, etc. Ainsi, tous les éléments partagés par ces sections du jeu sont stockés en un seul endroit.
Cette catégorie d'actifs est définie comme étant partagée par certains actifs uniques mais pas tous. À ce titre, ils n'entrent ni dans la catégorie des actifs globaux ni dans celle des actifs uniques. Pour Dinosaur Brawl, un exemple de ce type d'actifs partagés pourrait être ceux qui sont présents dans tous les dinosaures volants, tels que les particules, les ombres et les effets sonores nécessaires pour donner la sensation de s'élever dans les airs.
Ce qui se passe souvent, c'est que ces actifs sont placés dans le dossier du premier dinosaure qui en a besoin. Malheureusement, cela ne décrit pas exactement la manière dont ils sont censés être utilisés et brouille donc leur intention. Dans le pire des cas, les actifs sont dupliqués dans chaque paquet de dinosaures volants, ce qui est inefficace pour la mémoire, le débogage et la taille de l'application.
La meilleure solution consiste à créer un nouveau dossier portant un nom qui indique l'usage auquel il est destiné, par exemple Dinosaures volants. Le choix du lieu est plus délicat ; il n'y a pas de norme. Je préfère les placer dans un sous-dossier au même niveau que les dossiers dinosaures globaux et uniques, mais il est tout aussi possible de les placer avec d'autres dossiers uniques.
Un cas limite typique de cette convention est lorsque les exigences du projet changent et qu'un bien qui était initialement prévu pour être unique devient partagé. Dans notre exemple Dinosaur Brawl, pour gagner du temps de développement, la décision est prise d'utiliser le préfabriqué Velociraptor comme base pour tous les autres Raptors (tels que Utahraaptor, Dokataraptor, etc.).
Ce que les développeurs ne réalisent pas, cependant, c'est que lorsque le préfabriqué Velociraptor est ajouté à un pack, tous les actifs Velociraptor seront téléchargés lorsque tous les autres raptors seront chargés, augmentant ainsi les temps de téléchargement bien que seul le préfabriqué soit utilisé.
Cela s'est produit parce que l'intention de la ressource a été modifiée et que la structure du dossier ne reflète plus cette intention. En cas de changement d'intention, l'emplacement et le nom du ou des biens doivent être mis à jour pour refléter ce changement, afin de maintenir la cohérence et l'exactitude du système. Cela permet de communiquer à l'équipe qui crée les lots les actifs qui doivent être dans un lot "Raptor partagé" et ceux qui doivent rester dans le modèle unique Velociraptor.
L'un des cas les plus courants et les plus difficiles à résoudre est celui où un bien est utilisé involontairement d'une manière qui n'était pas prévue. Lorsque cela se produit, il s'agit généralement d'un accident. Par exemple, quelqu'un a un délai à respecter et utilise un actif déjà existant dans le projet pour terminer le travail rapidement.
Prenons l'exemple suivant : Un artiste ajoute un tutoriel pour une prochaine extension de Dinosaur Brawl et trouve un shader "gold glow" pour accentuer le moment où les joueurs peuvent effectuer une contre-attaque sur les ennemis d'élite. Ce que l'artiste ne sait pas, c'est que ce shader est un contenu de fin de partie contre un énorme T-Rex - c'est un boss unique qui a beaucoup d'atouts regroupés. Toutes ces ressources seront téléchargées pendant le tutoriel, à un endroit où la plupart d'entre elles ne sont pas utilisées. Ce pack étant énorme, le système qui télécharge habituellement des éléments mineurs comme celui-ci au milieu d'une partie est mis à rude épreuve, ce qui peut entraîner des pics de performance ou des plantages parce que l'élément ne peut pas être téléchargé assez rapidement par les joueurs disposant d'une connexion de mauvaise qualité.
Il s'agit d'un exemple extrême, mais tout à fait réaliste, que j'ai vu se produire dans plus d'un projet. C'est pourquoi, en plus de la structure des dossiers, tous les actifs doivent avoir un nom qui communique leur intention. Si le shader s'appelait gold_glow_trex_endgame, par exemple, l'utilisation prévue serait évidente. Ensuite, lors du débogage, il serait évident que cet actif ne devrait pas être chargé pendant le tutoriel.
Si vous êtes familier avec Addressables, vous savez peut-être que les groupes et les étiquettes sont utilisés pour regrouper et étiqueter les ressources de la même manière que je l'ai suggéré dans l'exemple du jeu ci-dessus - en utilisant des dossiers et des conventions de dénomination judicieuses. Vous vous demandez peut-être : "Pourquoi s'embêter avec tout cela si vous pouvez le faire avec les groupes et les étiquettes ?"
Ma réponse est que vous devriez faire les deux. Comme je l'ai expliqué au début, au fur et à mesure que le nombre d'actifs d'un projet augmente, il devient plus difficile, voire impossible, pour une seule personne de savoir comment tous les actifs sont censés être utilisés. Le fait de savoir que les groupes d'Addressables doivent correspondre à la structure des dossiers peut être utilisé comme un moyen de confirmer qu'ils sont configurés correctement.
J'ai vu beaucoup de nos clients qui utilisent des ensembles d'actifs sans Addressables coder des systèmes complexes pour résoudre ce problème. Par exemple, ils créeront et maintiendront une liste maîtresse utilisée pour créer les liasses, ou vérifieront les commits de contrôle de version pour comparer les changements dans les liasses, etc. D'après mon expérience, ces solutions ne sont pas rentables à long terme. Il s'agit encore d'un autre système à développer et à maintenir, ce qui crée des points de défaillance supplémentaires. Au fur et à mesure que le projet prend de l'ampleur, ils cèdent à une myriade d'exceptions et de cas limites que les projets de longue durée accumulent naturellement. Pire encore, à un niveau fondamental, ils échouent parce qu'ils n'ont pas de solution pour les erreurs des utilisateurs.
Un système de dossiers bien structuré et une convention de dénomination des fichiers devraient permettre d'obtenir une correspondance de 1 à 1 pour les regroupements d'actifs et les groupes d'Addressables. La catégorisation des fichiers en groupes logiques et en sous-dossiers garantit que tous les membres de l'équipe interprètent et localisent les fichiers de manière uniforme, ce qui réduit les risques de malentendus et de divergences au fur et à mesure que le personnel change et que les exigences du projet évoluent. Les créateurs d'actifs peuvent faciliter l'accès et la navigation, épargnant ainsi aux autres membres de l'équipe la tâche fastidieuse de rechercher des actifs spécifiques. Une approche systémique permet de gagner un temps précieux et de minimiser la probabilité d'erreurs et d'oublis. Devenir un point de référence durable, une source de vérité, faciliter le processus d'intégration des nouveaux membres de l'équipe et assurer la viabilité du projet dans le temps.
Vous avez besoin d'aide ou de conseils sur la structure des dossiers ? Discutez avec nous sur les forums. Découvrez d'autres blogs techniques de développeurs Unity dans le cadre de la série permanente Tech from the Trenches.
