Améliorer les performances

*Ce contenu est traduit en utilisant l'IA (Beta) et peut contenir des erreurs. Pour consulter cette page en anglais, clique ici.

Cette page décrit les problèmes de performances 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 trame. Sauf si elles sont exécutées 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 suspend le fil.

Problèmes courants

  • Opérations intensives sur les structures de tableau - 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 tableau. 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 - Attacher des opérations coûteuses à des événements basés sur des 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 lors des événements de RunService avec parcimonie, en limitant l'utilisation aux cas où l'invocation à haute fréquence est essentielle (par exemple, mettre à jour 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 volumineuses 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.

Portées de MicroProfiler

PorteCalcul associé
RunService.PreRenderCode s'exécutant sur l'événement PreRender
RunService.PreSimulationCode s'exécutant sur l'événement Stepped
RunService.PostSimulationCode s'exécutant sur l'événement Heartbeat
RunService.HeartbeatCode 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 accroître encore la spécificité, telles que debug.profilebegin et debug.profileend. De nombreuses méthodes API Roblox appelées par des scripts ont également leurs propres balises MicroProfiler associées qui peuvent fournir un signal utile.

Utilisation de la mémoire du script

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 correctement libérer lorsqu'elle n'est plus utilisée. Les fuites sont en particulier répandues sur le serveur, car elles peuvent être activées 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 - Un nombre d'instances qui augmente de façon constante suggère 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 script 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é. Ainsi, les connexions actives des événements et le code à l'intérieur des instances connectées, des fonctions connectées et des valeurs référencées échappent à la portée du ramasse-miettes, même après que les événements ont é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 leur objet Player et le 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 - L'insertion d'objets dans des tables mais ne pas les supprimer lorsqu'ils ne sont plus nécessaires provoque une consommation inutile de mémoire, en particulier pour les tables qui suivent les données des utilisateurs lorsqu'ils rejoignent. Par exemple, l'exemple de code suivant crée une table ajoutant des informations sur les utilisateurs chaque fois qu'un utilisateur rejoint :

    Exemple
    local playerInfo = {}
    Players.PlayerAdded:Connect(function(player)
    playerInfo[player] = {} -- certaines informations
    end)

    Si vous ne supprimez pas ces entrées lorsqu'elles ne sont plus nécessaires, la table continue de croître et consomme plus de mémoire à mesure que plus d'utilisateurs rejoignent la session. Tout code qui itère sur cette table devient également de plus en plus coûteux en calcul à mesure que la table grandit.

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 codebase et assurez-vous que chaque connexion est nettoyée via l'un des chemins suivants :

    • Déconnexion manuelle à l'aide de la fonction Disconnect().
    • Destruction de l'instance à laquelle l'événement appartient avec la fonction Destroy().
    • Destruction de l'objet script auquel la connexion se rapporte.
  • 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 soit parti. Si vous préférez, vous pouvez les nettoyer manuellement :

    Exemple de nettoyage des joueurs et des personnages
    local 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 de physique

Une simulation physique excessive peut être une cause clé d'augmentation du temps de calcul par image, tant sur le serveur que sur 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éplace à 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 de physique à se déplacer à 240 Hz (quatre fois par image). Cela entraîne un coût de calcul beaucoup plus élevé à 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 offrent une variété de modes avec différents niveaux d'impact sur la performance. Le mode de détection des collisions précis pour les parties de maillage a le coût de performance le plus élevé et prend plus de temps à calculer par le moteur.

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 NPCs statiques.

  • Utilisez le pas de physique adaptatif - Le pas adaptatif ajuste dynamiquement le taux des calculs de physique pour les mécanismes de physique, permettant aux mises à jour de physique d'être effectuées moins souvent dans certains cas.

  • Réduisez la complexité des mécanismes

    • Lorsque cela est possible, minimisez le nombre de contraintes ou de joints de physique dans un assemblage.
    • Réduisez la quantité de collisions internes au sein d'un mécanisme, par exemple en appliquant des limites ou des contraintes de non-collision aux membres d'un 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 les fidélités de boîte ou de coque, selon la forme.

    • Pour les objets larges et très complexes, construisez des collisions personnalisées à l'aide de parties invisibles lorsque cela est possible.

    • Pour les objets qui n'ont pas besoin de collisions, désactivez les collisions et utilisez la fidélité de boîte ou de coque, étant donné que 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 des Options de visualisation dans le coin supérieur droit de la fenêtre 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

PorteCalcul associé
physicsSteppedCalcul global de la physique
worldStepPas de physique discrets effectués à 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 beaucoup 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 envisager de réduire 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 la plus faible surcharge 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 les maillages très complexes et grands, vous voudrez peut-être créer 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 qu'elle soit puissante, un Humanoid entraîne un coût de calcul important.

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, sauf si votre NPC va grimper des échelles, il est sûr de désactiver l'état Climbing.
  • Instancier, modifier et réapparaître des modèles avec Humanoids ou des MeshParts skinned fréquemment
    • Cela peut être intensif à traiter pour le moteur, en particulier si ces modèles utilisent des vêtements en couches. Cela peut également être particulièrement problématique dans les jeux où les avatars réapparaissent souvent.
    • Dans le MicroProfiler, les balises updateInvalidatedFastClusters longues (plus de 4 ms) sont souvent un signal que l'instanciation ou la modification d'avatar déclenche des invalidations excessives.
  • Utiliser des Humanoïdes dans des cas où ils ne sont pas requis - Les NPC statiques qui ne se déplacent pas n'ont généralement pas besoin de la classe Humanoid.
  • Jouer des animations sur un grand nombre de NPC depuis le serveur - Les animations des 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 provoquent la reconstruction de FastCluster. Essayez de réduire cela pendant le jeu si vous constatez des problèmes de performance liés à FastCluster. De même, d'autres changements de propriété peuvent également entraîner la reconstruction de FastCluster, donc en général, réduisez ces changements autant que possible.

Atténuation

  • Jouer 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 de faire fonctionner les animations localement. Cela réduit la charge sur le serveur et le besoin de répliques inutiles. Cela permet également des optimisations supplémentaires possibles (par exemple, ne jouer des animations que pour les NPC qui sont proches du personnage).
  • Utiliser des alternatives respectueuses des 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 simplement de jouer des animations.
    • Pour les NPC en mouvement, envisagez de mettre en œuvre votre propre contrôleur de mouvement et d'utiliser un AnimationController pour les animations, en fonction de la complexité de vos NPC.
  • Désactiver les états humanoïdes inutilisés - Utilisez Humanoid:SetStateEnabled() pour n'activer que les états nécessaires pour chaque humanoïde.
  • Mettre en poules les modèles de NPC réapparaissant fréquemment - Au lieu de détruire complètement un NPC, envoyez-le dans une poule de NPC inactifs. De cette façon, lorsque qu'un nouveau NPC est requis pour réapparaître, vous pouvez simplement réactiver l'un des NPC de la poule. Ce processus s'appelle le pooling, ce qui minimise le nombre de fois où les personnages doivent être instanciés.
  • Ne faire apparaître des NPC que quand les utilisateurs sont à proximité - Ne faites pas apparaître des NPC lorsque les utilisateurs ne sont pas à portée, et éliminez-les lorsque les utilisateurs quittent leur portée.
  • Éviter de faire des changements à l'arborescence des avatars après son instanciation - Certaines modifications dans une arborescence d'avatar ont des implications de performance significatives. 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.
    • Si vous avez besoin d'attacher des objets BasePart à l'avatar, faites-le en dehors de l'arborescence du modèle Model de l'avatar.

Portées de MicroProfiler

PorteCalcul associé
stepHumanoidContrôle et physique des humanoïdes
stepAnimationAnimation des humanoïdes et des animateurs
updateInvalidatedFastClustersAssocié à l'instanciation ou la modification d'un avatar

Rendu

Une partie importante 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 un coût élevé. 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 renduTiming dans Studio. Vous pouvez visualiser 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é instancing 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 ayant le même MeshContent sont traités par un seul appel de dessin lorsque :

Autres problèmes courants

  • Densité d'objets excessive - Si un grand nombre d'objets sont concentrés à haute densité, le rendu de cette zone de la scène nécessite davantage d'appels de dessin. Si vous constatez que votre taux de trame chute lorsque vous regardez une certaine partie de la carte, cela peut être un bon signal que la densité des objets dans cette zone est trop élevée.

    Des objets comme des décalcomanies, des textures et des particules ne se groupent 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é des ParticleEmitters peuvent avoir un impact dramatique sur les performances.

  • Opportunités d'instancing ratées - Souvent, une scène inclura le même maillage dupliqué plusieurs fois, mais chaque copie du maillage a des IDs d'actifs de maillage ou de texture différents. Cela empêche le regroupement 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 en une seule fois, plutôt que d'importer chaque actif individuellement dans Roblox, puis les dupliquer après l'importation pour assembler la scène.

    Même un script simple comme celui-ci peut vous aider à identifier des parties de maillage avec le même nom mais qui utilisent des ID de maillage différents :

    for _,descendant in workspace:GetDescendants() do
    if descendant:IsA("MeshPart") then
    print(descendant.Name .. ", " .. descendant.MeshId)
    end
    end

    La 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 dupliqués dans votre jeu :

    LargeRock, rbxassetid://106420009602747 (x144) -- bon
    LargeRock, rbxassetid://120109824668127
    LargeRock, rbxassetid://134460273008628
    LargeRock, rbxassetid://139288987285823
    LargeRock, rbxassetid://71302144984955
    LargeRock, rbxassetid://90621205713698
    LargeRock, rbxassetid://113160939160788
    LargeRock, rbxassetid://135944592365226 -- tous des doublons possibles
  • Complexité 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 de rendu d'une image. Les scènes avec un très grand nombre de maillages très complexes constituent un problème courant, tout comme les scènes dont la propriété MeshPart.RenderFidelity est définie sur Precise pour trop de maillages.

  • Projection d'ombres excessive - La gestion des ombres est un processus coûteux, et les cartes contenant un grand nombre et une grande densité d'objets lumineux qui projettent des ombres (ou un grand nombre et une grande densité de petites parties influencées par les ombres) peuvent avoir des problèmes de performance.

  • Surcouche de transparence élevée - Placer des objets avec une transparence partielle les uns près des autres force le moteur à rendre les pixels qui se chevauchent plusieurs fois, ce qui peut nuire à la performance. Pour plus d'informations sur l'identification et la résolution de ce problème, consultez Supprimer les transparences empilées.

  • Mouvement inutile des MeshPart skinned - Les MeshParts skinned qui font partie d'un modèle sans humanoïde 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, obligeant les clusters à être reconstruits et impactant les performances.

    • Un moyen très efficace de contourner ce problème est d'incorporer un Humanoid dans le modèle. La présence d'un Humanoid contredit le comportement de regroupement spatial par défaut, imposant l'utilisation d'un unique FastCluster unifié pour tout le modèle. Ainsi, les mises à jour de position ne nécessitent plus de reconstructions de clusters, atténuant ce goulet d'étranglement de performance. Cette technique ne doit être réservée qu'aux MeshParts avec des déplacements prévus, car elle peut entraîner des surcharges de mémoire et annuler les avantages de l'optimisation spatiale. Nous recommandons de toujours profiler votre jeu après avoir effectué ce genre de changements. Consultez Conseils de performance pour les Humanoïdes pour des informations supplémentaires.
  • Trop de parties dans un Model - Trop de parties dans un modèle pourraient causer 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

  • Instancier des maillages identiques et réduire le nombre de maillages uniques - Si vous vous assurez que tous les maillages identiques aient les mêmes IDs d'actifs 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 qu'une seule fois dans une carte, puis de les dupliquer dans Studio pour les réutiliser afin de ne pas importer de grandes cartes en une seule fois, ce qui pourrait amener des maillages identiques à avoir des IDs 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 - Culling décrit le processus d'éliminer les appels de dessin pour des objets qui ne font pas partie de l'image finale rendue. Par défaut, le moteur saute les appels de dessin pour des objets en dehors du champ de vision de la caméra (culling de frustum) et les parties, maillages et terrains occlus de 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 salle ou de portail et de faire un culling manuel des objets pour réduire davantage les appels de dessin ou la charge computationnelle globale.

  • Réduire le niveau de détail pour les modèles - Activez le streaming d'instances et définissez la propriété LevelOfDetail de vos modèles de monde sur SLIM pour rendre des maillages SLIM légers optimisés à mesure qu'elles s'éloignent de la caméra.

  • Réduire le niveau de détail pour les avatars - Activez le streaming des instances et définissez Workspace.EnableSLIMAvatars pour rendre les avatars de plateforme en tant que représentations SLIM légères optimisées avec un support complet d'animation à mesure qu'ils s'éloignent de la caméra.

  • Réduire 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 devant être dessinés.

  • Désactiver 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. Quelques exemples d'optimisations que vous pouvez effectuer soit à l'heure d'édition, soit dynamiquement en temps réel :

    • 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 si 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

PorteCalcul associé
Prepare and PerformRendu global
Perform/Scene/computeLightingPerformMises à jour de la grille de lumière et des ombres
LightGridCPUMises à jour de la grille de lumière vocale
ShadowMapSystemCartographie des ombres
Perform/Scene/UpdateViewPréparation pour le rendu et mises à jour de particules
Perform/Scene/RenderViewRendu et post-traitement

Réseau et réplication

Le réseautage et la réplication décrivent le processus par lequel des 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 - L'envoi d'une grande quantité de données via des objets RemoteEvent ou RemoteFunction ou leur invocation très fréquente 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 les entrées des utilisateurs sans mécanisme pour limiter cela.
    • Déployer plus de données que nécessaire. Par exemple, envoyer l'inventaire complet du joueur lorsqu'il achète un article plutôt que simplement les détails de l'article 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 la création et la destruction de grandes hiérarchies d'instances comme des cartes à l'exécution peuvent être très intensives sur le réseau.

    Un coupable courant ici est les données d'animation complexes enregistrées par des plugins Animation Editor dans les rigs. Si celles-ci ne sont pas supprimées avant que le jeu soit publié et que le modèle animé est 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é tweenée est répliquée à chaque client à chaque image. Cela non seulement rend le tween instable au fur et à mesure que la latence des clients fluctue, mais cela entraîne é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, n'envoyez que 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 les cartes et chargez-les en morceaux pour répartir le travail de replication sur plusieurs images.
  • Nettoyez les métadonnées d'animation, en particulier le répertoire d'animation des rigs, après les importations.
  • Limitez la réplication d'instances inutiles, surtout 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.
    • Tweener des objets sur le client plutôt que sur le serveur.

Portées de MicroProfiler

PorteCalcul associé
ProcessPacketsTraitement des paquets réseau entrants, tels que les invocations d'événements et les changements de propriété
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 disponible pour les créateurs afin d'améliorer l'utilisation de la mémoire par le client est d'activer le streaming d'instances.

Streaming d'instances

Le streaming d'instances charge sélectivement des parties du modèle de données qui ne sont pas requises, ce qui peut entraîner considérablement une réduction des temps de chargement et augmenter la capacité du client à prévenir les crashes lorsqu'il est soumis à une pression mémoire.

Si vous rencontrez des problèmes de mémoire et que vous avez désactivé le streaming d'instances, envisagez de mettre à jour votre jeu pour le prendre en charge, en particulier si votre monde 3D est grand. Le streaming d'instances est basé sur la distance dans l'espace 3D, donc les mondes plus grands bénéficient naturellement plus de cette fonctionnalité.

Si le streaming d'instances est activé, vous pouvez en augmenter l'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 les 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, entraînant des IDs d'actifs différents. Cela peut amener le même contenu à être chargé en mémoire plusieurs fois.

  • Volume d'actifs excessif - Même lorsque des 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 des contributeurs surprenants à 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 d'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, il n'y a donc aucun bénéfice de mémoire à télécharger des images dans un modèle de couleur associé à moins d'octets par pixel. De même, compresser des images avant de les télécharger ou supprimer le canal alpha d'images qui n'en ont pas besoin peut diminuer la taille du fichier 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 de l'écran occupé par la texture et d'autres facteurs. Malgré tout, 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 sur les objets et assurez-vous que les mêmes actifs, en particulier les maillages et les images, ne soient pas téléchargés séparément plusieurs fois.

  • Trouvez et corrigez les actifs en double - Recherchez des parties de maillage identiques et des textures qui ont été téléchargées plusieurs fois avec des IDs différents.

    • Bien qu'il n'existe pas d'API pour détecter la similitude des actifs automatiquement, vous pouvez collecter tous les IDs d'actifs d'image dans votre lieu (soit manuellement, soit par le biais d'un script), les télécharger et les comparer à l'aide d'outils externes de comparaison.
    • Pour les parties de maillage, la meilleure stratégie consiste à prendre des IDs 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 différentes teintes.
  • Importez des actifs de la carte séparément - Au lieu d'importer toute une carte en une fois, importez et reconstruisez les actifs de la carte individuellement. L'Importateur n'effectue aucune dé-duplication des maillages, donc si vous deviez importer une grande carte avec beaucoup de tuiles de sol séparées, chacune de ces tuiles serait importée comme un actif séparé (même si elles sont des doublons). Cela peut entraîner des problèmes de performance et de mémoire par la suite, car chaque maillage est traité individuellement et prend 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 sur l'écran, il lui faut généralement au plus 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 des cartes 3D. Pour des étapes et des exemples sur la création de feuilles de découpe, consultez Créer des feuilles de découpe.

    Vous voudrez é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 complètement chargées sans pop-in. Cependant, une erreur courante consiste à utiliser cette méthode de manière excessive 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 prévenir le pop-in 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 charger. Cependant, cela pose 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.

Utilisez plutôt ContentProvider:PreloadAsync() uniquement dans des situations nécessaires, y compris :

  • Images dans l'écran de chargement.
  • Images importantes dans votre menu de jeu, telles que les arrière-plans de boutons et les icônes.
  • Actifs importants dans la zone de départ ou de spawn.

Si vous devez charger un grand nombre d'actifs, nous vous recommandons de fournir un bouton Ignorer le chargement.

©2026 Société Roblox. Roblox, le logo Roblox et Powering Imagination font partie de nos marques déposées aux États-Unis et dans d'autres pays.