Cette page décrit les problèmes de performance courants et les meilleures pratiques pour les atténuer.
Calcul de script
Les opérations coûteuses dans le code Luau prennent plus de temps à traiter et peuvent donc affecter le taux de rafraîchissement. À moins qu'il ne soit exécuté en parallèle, le code Luau s'exécute de manière synchrone et bloque le fil principal jusqu'à ce qu'il rencontre une fonction qui cède le fil.
Problèmes courants
Opérations intensives sur les structures de table - Les opérations complexes telles que la sérialisation, la désérialisation et le clonage profond entraînent un coût de performance élevé, en particulier sur de grandes structures de table. Cela est particulièrement vrai si ces opérations sont récursives ou impliquent l'itération sur de très grandes structures de données.
Événements à haute fréquence - Lier des opérations coûteuses à des événements basés sur les images de RunService sans limiter la fréquence signifie que ces opérations sont répétées à chaque image, ce qui entraîne souvent une augmentation inutile du temps de calcul. Ces événements incluent :
Atténuation
- Invoquez le code sur les événements de RunService avec parcimonie, en limitant l'utilisation aux cas où l'invocation à haute fréquence est essentielle (par exemple, la mise à jour de la caméra). Vous pouvez exécuter la plupart des autres codes dans d'autres événements ou moins fréquemment dans une boucle.
- Divisez les tâches importantes ou coûteuses en utilisant task.wait() pour répartir le travail sur plusieurs images.
- Identifiez et optimisez les opérations inutilement coûteuses et utilisez le multithreading pour les tâches computationnelles coûteuses qui n'ont pas besoin d'accéder au modèle de données.
- Certains scripts côté serveur peuvent bénéficier de la génération de code natif, un simple drapeau qui compile un script en code machine plutôt qu'en bytecode.
- Si vos serveurs manquent toujours de CPU après optimisation, vous pouvez en réserver davantage avec Extended Services for Compute.
Portées de MicroProfiler
| Portée | Calcul associé |
| RunService.PreRender | Code s'exécutant sur l'événement PreRender |
| RunService.PreSimulation | Code s'exécutant sur l'événement Stepped |
| RunService.PostSimulation | Code s'exécutant sur l'événement Heartbeat |
| RunService.Heartbeat | Code s'exécutant sur l'événement Heartbeat |
Pour plus d'informations sur le débogage des scripts à l'aide de MicroProfiler, consultez la bibliothèque debug, qui comprend des fonctions pour marquer un code spécifique et augmenter la spécificité, telles que debug.profilebegin et debug.profileend. De nombreuses méthodes de l'API Roblox appelées par des scripts ont également leurs propres balises MicroProfiler associées qui peuvent fournir des signaux utiles.
Utilisation de la mémoire des scripts
Des fuites de mémoire peuvent se produire lorsque vous écrivez des scripts qui consomment de la mémoire que le ramasse-miettes ne peut pas libérer correctement lorsqu'elle n'est plus utilisée. Les fuites sont particulièrement répandues sur le serveur, car elles peuvent rester en ligne pendant de nombreux jours, tandis qu'une session client est beaucoup plus courte.
Les valeurs de mémoire suivantes dans la Console Développeur peuvent indiquer un problème nécessitant une enquête plus approfondie :
- LuaHeap - Une consommation élevée ou croissante suggère une fuite de mémoire.
- InstanceCount - Des nombres d'instances en constante augmentation suggèrent que des références à certaines instances dans votre code ne sont pas collectées par le ramasse-miettes.
- PlaceScriptMemory - Fournit une répartition de l'utilisation de la mémoire par script.
Problèmes courants
Laisser des connexions connectées - Le moteur ne collecte jamais les événements connectés à une instance et toutes les valeurs référencées à l'intérieur du rappel connecté. Par conséquent, les connexions actives d'événements et le code à l'intérieur des instances connectées, des fonctions connectées et des valeurs référencées, sont hors de portée pour le ramasse-miettes, même après que les événements aient été déclenchés.
Bien que les événements soient déconnectés lorsque l'instance à laquelle ils appartiennent est détruite, une erreur courante est de supposer que cela s'applique aux objets Player. Après qu'un utilisateur quitte un jeu, le moteur ne détruit pas automatiquement son objet Player représentatif et son modèle de personnage, donc les connexions à l'objet Player et aux instances sous le modèle de personnage, telles que CharacterAdded, continuent de consommer de la mémoire si vous ne les déconnectez pas dans vos scripts. Cela peut entraîner des fuites de mémoire très significatives au fil du temps sur le serveur à mesure que des centaines d'utilisateurs rejoignent et quittent le jeu.
Tables - Insérer des objets dans des tables mais ne pas les supprimer lorsqu'ils ne sont plus nécessaires entraîne une consommation de mémoire inutile, en particulier pour les tables qui suivent les données des utilisateurs lorsqu'ils rejoignent. Par exemple, le code d'exemple suivant crée une table ajoutant des informations sur l'utilisateur chaque fois qu'un utilisateur rejoint :
Exemplelocal playerInfo = {}Players.PlayerAdded:Connect(function(player)playerInfo[player] = {} -- quelques infosend)Si vous ne supprimez pas ces entrées lorsqu'elles ne sont plus nécessaires, la table continue de croître en taille et consomme plus de mémoire à mesure que plus d'utilisateurs rejoignent la session. Tout code qui itère sur cette table devient également plus coûteux en termes de calcul à mesure que la table augmente en taille.
Atténuation
Pour nettoyer toutes les valeurs utilisées afin de prévenir les fuites de mémoire :
Déconnectez toutes les connexions - Parcourez votre code et assurez-vous que chaque connexion est nettoyée via l'un des chemins suivants :
- Déconnexion manuelle en utilisant la fonction Disconnect().
- Détruire l'instance à laquelle l'événement appartient avec la fonction Destroy().
- Détruire l'objet script auquel la connexion remonte.
Supprimez les objets et personnages des joueurs après leur départ - Activez Workspace.PlayerCharacterDestroyBehavior pour détruire automatiquement les objets des joueurs et les modèles de personnages après qu'un utilisateur quitte. Si vous préférez, vous pouvez les nettoyer manuellement :
Exemple de nettoyage des joueurs et des personnageslocal Players = game:GetService("Players")Players.PlayerAdded:Connect(function(player)player.CharacterRemoving:Connect(function(character)task.defer(character.Destroy, character)end)end)Players.PlayerRemoving:Connect(function(player)task.defer(player.Destroy, player)end)
Calcul physique
Une simulation physique excessive peut être une cause clé d'augmentation du temps de calcul par image sur le serveur et le client.
Problèmes courants
Fréquence de pas de physique excessive - Par défaut, le comportement de pas est en mode adaptatif, où la physique se déroule à 60 Hz, 120 Hz ou 240 Hz, selon la complexité du mécanisme physique.
Un mode fixe avec une précision améliorée de la physique est également disponible, ce qui force tous les assemblages physiques à se dérouler à 240 Hz (quatre fois par image). Cela entraîne un calcul significativement plus important à chaque image.
Nombre excessif d'objets simulés complexes - Plus il y a d'assemblages 3D simulés, plus les calculs physiques prennent de temps à chaque image. Souvent, les jeux auront des objets simulés qui n'ont pas besoin de l'être ou auront des mécanismes qui ont plus de contraintes et de joints que nécessaire.
Détection de collision trop précise - Les parties de maillage ont une propriété CollisionFidelity pour détecter les collisions qui offre une variété de modes avec différents niveaux d'impact sur la performance. Le mode de détection de collision précise pour les parties de maillage a le coût de performance le plus élevé et prend plus de temps au moteur pour le calcul.
Atténuation
Ancrez les parties qui ne nécessitent pas de simulation - Ancrez toutes les parties qui n'ont pas besoin d'être entraînées par la physique, comme pour les NPC statiques.
Utilisez un pas de physique adaptatif - Le pas adaptatif ajuste dynamiquement le taux de calculs physiques pour les mécanismes physiques, permettant des mises à jour physiques moins fréquentes dans certains cas.
Réduisez la complexité des mécanismes
- Lorsque cela est possible, minimisez le nombre de contraintes ou de joints physiques dans un assemblage.
- Réduisez la quantité d'auto-collision au sein d'un mécanisme, par exemple en appliquant des limites ou des contraintes sans collision aux membres de ragdoll pour éviter qu'ils ne se heurtent les uns aux autres.
Réduisez l'utilisation de la fidélité de collision précise pour les maillages
Pour les objets petits ou non interactifs où les utilisateurs remarqueraient rarement la différence, utilisez la fidélité de boîte.
Pour les objets de taille petite à moyenne, utilisez des fidélités de boîte ou de coque, selon la forme.
Pour les objets grands et très complexes, construisez des collisions personnalisées en utilisant des parties invisibles lorsque cela est possible.
Pour les objets qui ne nécessitent pas de collisions, désactivez les collisions et utilisez la fidélité de boîte ou de coque, car la géométrie de collision est toujours stockée en mémoire.
Vous pouvez rendre la géométrie de collision à des fins de débogage dans Studio en activant Fidélité de collision dans le widget Options de visualisation dans le coin supérieur droit de la vue 3D.
Alternativement, vous pouvez appliquer le filtre CollisionFidelity=PreciseConvexDecomposition à l'Explorateur qui montre un compte de toutes les parties de maillage avec la fidélité précise et vous permet de les sélectionner facilement.
Pour un guide détaillé sur la façon de choisir une option de fidélité de collision qui équilibre vos exigences de précision et de performance, consultez Définir les paramètres de physique et de rendu.
Portées de MicroProfiler
| Portée | Calcul associé |
| physicsStepped | Calcul physique global |
| worldStep | Pas de physique discrets pris à chaque image |
Utilisation de la mémoire physique
Le mouvement physique et la détection de collision consomment de la mémoire. Les parties de maillage ont une propriété CollisionFidelity qui détermine l'approche utilisée pour évaluer les limites de collision du maillage.
Problème courant
Les modes de détection de collision par défaut et précis consomment significativement plus de mémoire que les deux autres modes avec des formes de collision de fidélité inférieure.
Si vous constatez des niveaux élevés de consommation de mémoire sous PhysicsParts, vous devrez peut-être explorer la réduction de la fidélité de collision des objets dans votre jeu.
Comment atténuer
Pour réduire la mémoire utilisée pour la fidélité de collision :
- Pour les parties qui n'ont pas besoin de collisions, désactivez leurs collisions en définissant BasePart.CanCollide, BasePart.CanTouch et BasePart.CanQuery sur false.
- Réduisez la fidélité des collisions en utilisant le paramètre CollisionFidelity. Box a le plus faible coût en mémoire, et Default et Precise sont généralement plus coûteux.
- Il est généralement sûr de définir la fidélité de collision de toute petite partie ancrée sur Box.
- Pour des maillages très complexes et grands, vous voudrez peut-être construire votre propre maillage de collision à partir d'objets plus petits avec une fidélité de collision de boîte.
Humanoïdes
Humanoid est une classe qui fournit une large gamme de fonctionnalités aux personnages joueurs et non joueurs (NPC). Bien que puissante, une Humanoid entraîne un coût de calcul significatif.
Problèmes courants
- Laisser tous les HumanoidStateTypes activés sur les NPC - Il y a un coût de performance à laisser certains HumanoidStateTypes activés. Désactivez ceux qui ne sont pas nécessaires pour vos NPC. Par exemple, à moins que votre NPC ne grimpe des échelles, il est sûr de désactiver l'état Climbing.
- Instancier, modifier et faire réapparaître des modèles avec Humanoids ou des MeshParts skinnés fréquemment
- Cela peut être intensif pour le moteur à traiter, en particulier si ces modèles utilisent des vêtements superposés. Cela peut également être particulièrement problématique dans les jeux où les avatars réapparaissent souvent.
- Dans le MicroProfiler, les balises longues updateInvalidatedFastClusters (plus de 4 ms) sont souvent un signal que l'instanciation/modification d'avatar déclenche des invalidations excessives.
- Utiliser des Humanoïdes dans des cas où ils ne sont pas nécessaires - Les NPC statiques qui ne bougent généralement n'ont pas besoin de la classe Humanoid.
- Jouer des animations sur un grand nombre de NPC depuis le serveur - Les animations de NPC qui s'exécutent sur le serveur doivent être simulées sur le serveur et répliquées au client. Cela peut être une surcharge inutile.
- Effectuer des changements de taille et d'échelle inutiles - Les changements de taille/échelle entraînent la reconstruction de FastCluster. Essayez de réduire cela pendant le gameplay si vous constatez des problèmes de performance liés à FastCluster. De même, d'autres changements de propriétés peuvent également entraîner la reconstruction de FastCluster, donc en général, réduisez ces changements autant que possible.
Atténuation
- Jouez les animations des NPC sur le client - Dans les jeux avec un grand nombre de NPC, envisagez de créer le Animator sur le client et d'exécuter les animations localement. Cela réduit la charge sur le serveur et la nécessité de répliques inutiles. Cela permet également d'autres optimisations possibles (comme ne jouer des animations que pour les NPC qui sont proches du personnage).
- Utilisez des alternatives favorables aux performances aux Humanoïdes - Les modèles de NPC n'ont pas nécessairement besoin de contenir un objet humanoïde.
- Pour les NPC statiques, utilisez un simple AnimationController, car ils n'ont pas besoin de se déplacer mais juste de jouer des animations.
- Pour les NPC mobiles, envisagez de mettre en œuvre votre propre contrôleur de mouvement et d'utiliser un AnimationController pour les animations, selon la complexité de vos NPC.
- Désactivez les états humanoïdes inutilisés - Utilisez Humanoid:SetStateEnabled() pour n'activer que les états nécessaires pour chaque humanoïde.
- Pool des modèles de NPC avec réapparition fréquente - Au lieu de détruire complètement un NPC, envoyez le NPC dans une piscine de NPC inactifs. De cette façon, lorsque qu'un nouveau NPC doit réapparaître, vous pouvez simplement réactiver l'un des NPC de la piscine. Ce processus s'appelle le pooling, ce qui minimise le nombre de fois que les personnages doivent être instanciés.
- Ne faites apparaître des NPC que lorsque les utilisateurs sont à proximité - Ne faites pas apparaître de NPC lorsque les utilisateurs ne sont pas à portée, et éliminez-les lorsque les utilisateurs quittent leur portée.
- Évitez de modifier la hiérarchie de l'avatar après son instanciation - Certaines modifications de la hiérarchie d'un avatar ont des implications significatives sur la performance. Certaines optimisations sont disponibles :
- Pour les animations procédurales personnalisées, ne mettez pas à jour les propriétés JointInstance.C0 et JointInstance.C1. Au lieu de cela, mettez à jour la propriété Motor6D.Transform.
Portées de MicroProfiler
| Portée | Calcul associé |
| stepHumanoid | Contrôle et physique humanoïdes |
| stepAnimation | Animation humanoïde et animateur |
| updateInvalidatedFastClusters | Associé à l'instanciation ou à la modification d'un avatar |
Rendu
Une partie significative du temps que le client passe à chaque image est consacrée au rendu de la scène dans l'image actuelle. Le serveur ne fait aucun rendu, donc cette section est exclusive au client.
Appels de dessin
Un appel de dessin est un ensemble d'instructions du moteur au GPU pour rendre quelque chose. Les appels de dessin ont une surcharge significative. En général, moins il y a d'appels de dessin par image, moins de temps de calcul est consacré au rendu d'une image.
Vous pouvez voir combien d'appels de dessin se produisent actuellement avec l'élément Statistiques de rendu ⟩ Timing dans Studio. Vous pouvez afficher les Statistiques de rendu dans le client en appuyant sur ShiftF2.
Plus d'objets doivent être dessinés dans votre scène à une image donnée, plus d'appels de dessin sont effectués au GPU. Cependant, le moteur Roblox utilise un processus appelé instanciation pour regrouper des maillages identiques avec les mêmes caractéristiques de texture en un seul appel de dessin. Plus précisément, plusieurs maillages avec le même MeshContent sont traités dans un seul appel de dessin lorsque :
- SurfaceAppearances sont identiques si présents, sinon lorsque TextureContents sont identiques.
- Les matériaux sont identiques lorsque ni SurfaceAppearance ni MeshPart.TextureID n'existent.
Autres problèmes courants
Densité d'objets excessive - Si un grand nombre d'objets sont concentrés avec une haute densité, alors le rendu de cette zone de la scène nécessite plus d'appels de dessin. Si vous constatez que votre taux de rafraîchissement diminue lorsque vous regardez une certaine partie de la carte, cela peut être un bon signal que la densité d'objets dans cette zone est trop élevée.
Des objets comme des décalcomanies, des textures et des particules ne se regroupent pas bien et introduisent des appels de dessin supplémentaires. Faites particulièrement attention à ces types d'objets dans une scène. En particulier, les changements de propriétés sur ParticleEmitters peuvent avoir un impact dramatique sur les performances.
Opportunités d'instanciation manquées - Souvent, une scène inclura le même maillage dupliqué plusieurs fois, mais chaque copie du maillage a des ID d'actif de maillage ou de texture différents. Cela empêche l'instanciation et peut entraîner des appels de dessin inutiles.
Une cause courante de ce problème est lorsque toute une scène est importée d'un coup, plutôt que des actifs individuels étant importés dans Roblox puis dupliqués après importation pour assembler la scène.
Même un script simple comme celui-ci peut vous aider à identifier les parties de maillage avec le même nom qui utilisent des ID de maillage différents :
for _,descendant in workspace:GetDescendants() doif descendant:IsA("MeshPart") thenprint(descendant.Name .. ", " .. descendant.MeshId)endendLa sortie (avec Stack Lines activé) pourrait ressembler à ceci. Les lignes répétées indiquent la réutilisation du même maillage, ce qui est bon. Les lignes uniques ne sont pas nécessairement mauvaises, mais selon votre schéma de nommage, pourraient indiquer des maillages en double dans votre jeu :
LargeRock, rbxassetid://106420009602747 (x144) -- bonLargeRock, rbxassetid://120109824668127LargeRock, rbxassetid://134460273008628LargeRock, rbxassetid://139288987285823LargeRock, rbxassetid://71302144984955LargeRock, rbxassetid://90621205713698LargeRock, rbxassetid://113160939160788LargeRock, rbxassetid://135944592365226 -- tous des doublons possiblesComplexité excessive des objets - Bien que moins important que le nombre d'appels de dessin, le nombre de triangles dans une scène influence également le temps qu'il faut pour rendre une image. Les scènes avec un très grand nombre de maillages très complexes sont un problème courant, tout comme les scènes avec la propriété MeshPart.RenderFidelity définie sur Precise sur trop de maillages.
Projection d'ombres excessive - Gérer les ombres est un processus coûteux, et les cartes contenant un grand nombre et une forte densité d'objets lumineux qui projettent des ombres (ou un grand nombre et une forte densité de petites parties influencées par des ombres) peuvent avoir des problèmes de performance.
Surcouche de transparence élevée - Placer des objets avec une transparence partielle près les uns des autres oblige le moteur à rendre les pixels qui se chevauchent plusieurs fois, ce qui peut nuire aux performances. Pour plus d'informations sur l'identification et la résolution de ce problème, consultez Supprimer les transparences superposées.
Mouvement inutile de MeshPart skinnés - Les MeshParts skinnés qui font partie d'un modèle sans un Humanoid sont regroupés à l'aide de FastClusters organisés spatialement. Lorsque ces MeshParts se déplacent, ils doivent être continuellement ajoutés et retirés de ces clusters spatiaux, forçant les clusters à être reconstruits et impactant les performances.
- Une solution très efficace consiste à intégrer un Humanoid dans le modèle. La présence d'un Humanoid remplace le comportement de regroupement spatial par défaut, imposant l'utilisation d'un seul FastCluster unifié pour l'ensemble du modèle. Par conséquent, les mises à jour de position ne nécessitent plus de reconstructions de clusters, atténuant ainsi le goulet d'étranglement de performance. Cette technique doit être réservée exclusivement aux MeshParts avec un mouvement prévu, car elle peut introduire une surcharge mémoire et annuler les avantages de l'optimisation spatiale. Nous recommandons toujours de profiler votre jeu après avoir apporté ces types de modifications. Consultez Conseils de performance Humanoid pour plus d'informations.
Trop de parties dans un Model - Trop de parties dans un modèle pourraient entraîner des reconstructions plus fréquentes en raison du potentiel de changement de propriété d'une partie nécessitant une reconstruction complète. Trouvez le bon équilibre de parties dans un modèle lorsqu'il utilise FastCluster.
Atténuation
Instanciation de maillages identiques et réduction du nombre de maillages uniques - Si vous vous assurez que tous les maillages identiques ont les mêmes ID d'actif sous-jacents, le moteur peut les reconnaître et les rendre dans un seul appel de dessin. Assurez-vous de ne télécharger chaque maillage dans une carte qu'une seule fois, puis de les dupliquer dans Studio pour réutilisation plutôt que d'importer de grandes cartes dans leur ensemble, ce qui pourrait entraîner des maillages identiques ayant des ID de contenu séparés et être reconnus comme des actifs uniques par le moteur. Les Packages sont un mécanisme utile pour la réutilisation d'objets.
Culling - Le culling décrit le processus d'élimination des appels de dessin pour les objets qui ne font pas partie de l'image finale rendue. Par défaut, le moteur ignore les appels de dessin pour les objets en dehors du champ de vision de la caméra (culling de frustum) et les parties, maillages et terrains occlus de la vue par d'autres objets (culling d'occlusion). Dans certains scénarios, comme les environnements intérieurs, vous pourriez être en mesure de mettre en œuvre un système de pièces ou de portails et de faire du culling manuel des objets pour réduire encore les appels de dessin ou la charge computationnelle globale.
Réduction du niveau de détail pour les modèles - Activez le streaming d'instance et définissez la propriété LevelOfDetail de vos modèles mondiaux sur SLIM pour rendre des maillages SLIM légers optimisés à mesure que la distance par rapport à la caméra augmente.
Réduction du niveau de détail pour les avatars - Activez le streaming d'instance et définissez Workspace.EnableSLIMAvatars pour rendre les avatars de plateforme sous forme de représentations SLIM légères optimisées avec un support d'animation complet à mesure que la distance par rapport à la caméra augmente.
Réduction de la fidélité de rendu - Définissez MeshPart.RenderFidelity sur Automatic ou Performance. Cela permet aux maillages de revenir à des alternatives moins complexes, ce qui peut réduire le nombre de polygones à dessiner.
Désactivation de la projection d'ombres sur les parties et objets lumineux appropriés - Le moteur Roblox dégrade automatiquement la qualité des ombres à mesure que le niveau de qualité graphique du client diminue, désactivant finalement complètement les ombres à des niveaux de qualité inférieurs à 4. Cependant, vous pouvez désactiver sélectivement les propriétés de projection d'ombres sur les objets lumineux et les parties pour améliorer les performances tout en maintenant les ombres activées et augmenter la probabilité que les ombres restent activées. Voici quelques exemples d'optimisations que vous pouvez effectuer soit au moment de l'édition, soit dynamiquement à l'exécution :
Utilisez la propriété BasePart.CastShadow pour désactiver la projection d'ombres sur de petites parties où les ombres sont peu susceptibles d'être visibles. Cette stratégie est particulièrement efficace lorsqu'elle est appliquée à des parties éloignées de la caméra de l'utilisateur.
Désactivez les ombres sur les objets en mouvement lorsque cela est possible.
Désactivez Light.Shadows sur les instances lumineuses où l'objet n'a pas besoin de projeter des ombres.
Limitez la portée et l'angle des instances lumineuses.
Utilisez moins d'instances lumineuses.
Envisagez de désactiver les lumières qui sont en dehors d'une portée spécifique ou sur une base pièce par pièce pour les environnements intérieurs.
Portées de MicroProfiler
| Portée | Calcul associé |
| Prepare and Perform | Rendu global |
| Perform/Scene/computeLightingPerform | Mises à jour de la grille lumineuse et des ombres |
| LightGridCPU | Mises à jour de la grille lumineuse voxel |
| ShadowMapSystem | Cartographie des ombres |
| Perform/Scene/UpdateView | Préparation pour le rendu et mises à jour des particules |
| Perform/Scene/RenderView | Rendu et post-traitement |
Réseautage et réplication
Le réseautage et la réplication décrivent le processus par lequel les données sont envoyées entre le serveur et les clients connectés. Les informations sont envoyées entre le client et le serveur à chaque image, mais de plus grandes quantités d'informations nécessitent plus de temps de calcul.
Problèmes courants
Trafic distant excessif - Envoyer une grande quantité de données via des objets RemoteEvent ou RemoteFunction ou les invoquer très fréquemment peut entraîner une grande quantité de temps CPU dépensé à traiter les paquets entrants à chaque image. Les erreurs courantes incluent :
- Répliquer des données à chaque image qui n'ont pas besoin d'être répliquées.
- Répliquer des données sur l'entrée de l'utilisateur sans aucun mécanisme pour le limiter.
- Envoyer plus de données que nécessaire. Par exemple, envoyer l'inventaire entier du joueur lorsqu'il achète un objet plutôt que juste les détails de l'objet acheté.
Création ou suppression d'arbres d'instances complexes - Lorsqu'un changement est apporté au modèle de données sur le serveur, il est répliqué aux clients connectés. Cela signifie que créer et détruire de grandes hiérarchies d'instances comme des cartes à l'exécution peut être très intensif en réseau.
Un coupable courant ici est les données d'animation complexes enregistrées par des plugins Animation Editor dans des rigs. Si celles-ci ne sont pas supprimées avant que le jeu ne soit publié et que le modèle animé soit cloné régulièrement, une grande quantité de données sera répliquée inutilement.
TweenService côté serveur - Si TweenService est utilisé pour tweener un objet côté serveur, la propriété tweener est répliquée à chaque client à chaque image. Cela entraîne non seulement un tweener saccadé à mesure que la latence des clients fluctue, mais cela génère également beaucoup de trafic réseau inutile.
Atténuation
Vous pouvez employer les tactiques suivantes pour réduire la réplication inutile :
- Évitez d'envoyer de grandes quantités de données à la fois via des événements distants. Au lieu de cela, envoyez uniquement les données nécessaires à une fréquence plus faible. Par exemple, pour l'état d'un personnage, répliquez-le lorsqu'il change plutôt qu'à chaque image.
- Divisez les arbres d'instances complexes comme des cartes et chargez-les par morceaux pour répartir le travail de réplication sur plusieurs images.
- Nettoyez les métadonnées d'animation, en particulier le répertoire d'animation des rigs, après importation.
- Limitez la réplication d'instances inutiles, en particulier dans les cas où le serveur n'a pas besoin d'avoir connaissance des instances créées. Cela inclut :
- Les effets visuels tels qu'une explosion ou un sort magique. Le serveur n'a besoin de connaître que l'emplacement pour déterminer le résultat, tandis que les clients peuvent créer des visuels localement.
- Modèles d'objets de vue en première personne.
- Tween des objets sur le client plutôt que sur le serveur.
Portées de MicroProfiler
| Portée | Calcul associé |
| ProcessPackets | Traitement des paquets réseau entrants, tels que les invocations d'événements et les changements de propriétés |
| Allocate Bandwidth and Run Senders | Événements sortants pertinents sur les serveurs |
Utilisation de la mémoire des actifs
Le mécanisme ayant le plus d'impact à la disposition des créateurs pour améliorer l'utilisation de la mémoire du client est d'activer le streaming d'instance.
Streaming d'instance
Le streaming d'instance charge sélectivement des parties du modèle de données qui ne sont pas requises, ce qui peut entraîner des temps de chargement considérablement réduits et augmenter la capacité du client à prévenir les plantages lorsqu'il est soumis à une pression mémoire.
Si vous rencontrez des problèmes de mémoire et que le streaming d'instance est désactivé, envisagez de mettre à jour votre jeu pour le prendre en charge, en particulier si votre monde 3D est grand. Le streaming d'instance est basé sur la distance dans l'espace 3D, donc les mondes plus grands en bénéficient naturellement davantage.
Si le streaming d'instance est activé, vous pouvez augmenter son agressivité. Par exemple, envisagez :
- De réduire l'utilisation de Enum.ModelStreamingMode.Persistent lorsque cela est possible. Vous devrez peut-être mettre à jour vos scripts si vous l'utilisez comme mesure de compatibilité.
- De réduire le Workspace.StreamingMinRadius et le Workspace.StreamingTargetRadius.
Pour plus d'informations sur les options de streaming et leurs avantages, consultez propriétés de streaming.
Autres problèmes courants
Duplication d'actifs - Une erreur courante consiste à télécharger le même actif plusieurs fois, ce qui entraîne des ID d'actif différents. Cela peut entraîner le chargement du même contenu en mémoire plusieurs fois.
Volume d'actifs excessif - Même lorsque les actifs ne sont pas identiques, il existe des cas où des opportunités de réutiliser le même actif et d'économiser de la mémoire sont manquées.
Fichiers audio - Les fichiers audio peuvent être un contributeur surprenant à l'utilisation de la mémoire, en particulier si vous les chargez tous dans le client en même temps plutôt que de ne charger que ce dont vous avez besoin pour une partie du jeu. Pour des stratégies, voir Temps de chargement.
Textures haute résolution - La consommation de mémoire graphique pour une texture n'est pas liée à la taille de la texture sur le disque ; le nombre de pixels dans la texture détermine l'utilisation de la mémoire. Par exemple, une texture de 1024x1024 pixels consomme quatre fois la mémoire graphique d'une texture de 512x512 pixels.
Les images téléchargées sur Roblox sont transcodées dans un format fixe, donc il n'y a aucun avantage mémoire à télécharger des images dans un modèle de couleur associé à moins de bytes par pixel. De même, compresser des images avant le téléchargement ou supprimer le canal alpha des images qui n'en ont pas besoin peut réduire la taille de l'image sur le disque, mais n'améliore pas l'utilisation de la mémoire.
Au fur et à mesure qu'un jeu se charge, le moteur commence automatiquement avec des textures de qualité inférieure, puis augmente la qualité en fonction de la mémoire disponible sur l'appareil, de la distance par rapport à la caméra, de la quantité d'espace écran que la texture occupe et d'autres facteurs. Même ainsi, dimensionner stratégiquement vos textures peut améliorer l'utilisation de la mémoire dans votre jeu.
Atténuation
Téléchargez des actifs une seule fois - Réutilisez le même ID d'actif à travers les objets et assurez-vous que les mêmes actifs, en particulier les maillages et les images, ne sont pas téléchargés séparément plusieurs fois.
Trouvez et corrigez les actifs en double - Recherchez des parties de maillage et des textures identiques qui sont téléchargées plusieurs fois avec des ID différents.
- Bien qu'il n'existe pas d'API pour détecter automatiquement la similarité des actifs, vous pouvez collecter tous les ID d'actifs d'image dans votre lieu (soit manuellement, soit avec un script), les télécharger et les comparer à l'aide d'outils de comparaison externes.
- Pour les parties de maillage, la meilleure stratégie consiste à prendre des ID de maillage uniques et à les organiser par taille pour identifier manuellement les doublons.
- Au lieu d'utiliser des textures séparées pour différentes couleurs, téléchargez une seule texture et utilisez la propriété SurfaceAppearance.Color pour appliquer diverses teintes.
Importez des actifs dans la carte séparément - Au lieu d'importer une carte entière d'un coup, importez et reconstruisez les actifs dans la carte individuellement et reconstruisez-les. L'importateur ne fait aucune dé-duplication des maillages, donc si vous importez une grande carte avec beaucoup de carreaux de sol séparés, chacun de ces carreaux serait importé comme un actif séparé (même s'ils sont des doublons). Cela peut entraîner des problèmes de performance et de mémoire à long terme, car chaque maillage est traité individuellement et occupe de la mémoire et des appels de dessin.
Limitez les pixels des images à pas plus que le nécessaire. À moins qu'une image n'occupe une grande quantité d'espace physique à l'écran, elle a généralement besoin au maximum de 512x512 pixels. La plupart des images mineures devraient être plus petites que 256x256 pixels.
Utilisez des feuilles de découpe pour garantir une réutilisation maximale des textures dans les cartes 3D. Pour des étapes et des exemples sur la façon de créer des feuilles de découpe, consultez Créer des feuilles de découpe.
Vous pourriez également envisager d'utiliser des feuilles de sprites pour charger de nombreuses petites images UI en une seule image. Vous pouvez ensuite utiliser ImageLabel.ImageRectOffset et ImageLabel.ImageRectSize pour afficher des portions de la feuille.
Temps de chargement
De nombreux jeux mettent en œuvre des écrans de chargement personnalisés et utilisent la méthode ContentProvider:PreloadAsync() pour demander des actifs afin que les images, les sons et les maillages soient téléchargés en arrière-plan.
L'avantage de cette approche est qu'elle vous permet de vous assurer que les parties importantes de votre jeu sont entièrement chargées sans apparition soudaine. Cependant, une erreur courante consiste à surutiliser cette méthode pour précharger plus d'actifs que nécessaire.
Un exemple de mauvaise pratique est de charger l'ensemble de Workspace. Bien que cela puisse empêcher l'apparition soudaine des textures, cela augmente considérablement les temps de chargement.
Une autre pratique similaire consiste à utiliser ContentProvider.RequestQueueSize pour s'assurer que tous les actifs demandés ont fini de se charger. Cependant, cela présente le même problème d'augmentation significative des temps de chargement, tout en étant également une méthode peu fiable en raison de sa nature fluctuante.
Au lieu de cela, utilisez ContentProvider:PreloadAsync() uniquement dans des situations nécessaires, qui incluent :
- Images dans l'écran de chargement.
- Images importantes dans votre menu de jeu, telles que les arrière-plans et les icônes de boutons.
- Actifs importants dans la zone de départ ou de réapparition.
Si vous devez charger un grand nombre d'actifs, nous vous recommandons de fournir un bouton Passer le chargement.