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 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 ainsi impacter le taux de trames. À moins qu'elles ne soient 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 laisse 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é, surtout sur de grandes structures de table. Cela est particulièrement vrai si ces opérations sont récursives ou impliquent l'itération sur des structures de données très volumineuses.

  • Événements à haute fréquence - Lier des opérations coûteuses à des événements basés sur des trames de RunService sans limiter la fréquence signifie que ces opérations sont répétées à chaque trame, 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 son utilisation aux cas où une 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 lourdes ou coûteuses à l'aide de task.wait() pour répartir le travail sur plusieurs trames.
  • Identifiez et optimisez les opérations inutilement coûteuses et utilisez le multithreading pour les tâches coûteuses en calcul 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 flag qui compile un script en code machine plutôt qu'en bytecode.

Portées de MicroProfiler

PortéeCalcul associé
RunService.PreRenderCode exécuté lors de l'événement PreRender
RunService.PreSimulationCode exécuté lors de l'événement Stepped
RunService.PostSimulationCode exécuté lors de l'événement Heartbeat
RunService.HeartbeatCode exécuté lors de l'événement Heartbeat

Pour plus d'informations sur le débogage des scripts en utilisant le MicroProfiler, consultez la bibliothèque debug, qui inclut des fonctions pour marquer un code spécifique et augmenter la spécificité, telles que debug.profilebegin et debug.profileend. De nombreuses méthodes API Roblox appelées par les scripts ont également leurs propres tags MicroProfiler associés qui peuvent fournir des signaux utiles.

Utilisation de la mémoire par les scripts

Des fuites de mémoire peuvent survenir 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 côté serveur, car elles peuvent rester en ligne pendant de nombreux jours, alors qu'une session client est beaucoup plus courte.

Les valeurs de mémoire suivantes dans la Console du Développeur peuvent indiquer un problème nécessitant des investigations complémentaires :

  • 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 certaines références à des 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 les 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 des é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 la portée du 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 et son modèle de personnage représentatif, donc les connexions à l'objet Player et aux instances sous le modèle du personnage, telles que CharacterAdded, consomment toujours 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 alors que des centaines d'utilisateurs rejoignent et quittent le jeu.

  • Tables - Insérer des objets dans des tables mais ne pas les retirer 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, l'exemple de code suivant crée une table ajoutant des informations sur les utilisateurs chaque fois qu'un utilisateur se connecte :

    Exemple

    local playerInfo = {}
    Players.PlayerAdded:Connect(function(player)
    playerInfo[player] = {} -- quelques infos
    end)

    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 au fur et à mesure que d'autres utilisateurs rejoignent la session. Tout code qui itère sur cette table devient également plus coûteux en calcul à mesure que la table croît.

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 par l'un des chemins suivants :

    • Déconnexion manuelle en utilisant la fonction Disconnect().
    • Détruire l'instance à laquelle appartient l'événement avec la fonction Destroy().
    • Détruire l'objet script auquel la connexion revient.
  • Supprimez les objets et personnages de joueurs après leur départ - Activez Workspace.PlayerCharacterDestroyBehavior pour détruire automatiquement les objets de joueurs et les modèles de personnages après le départ d'un utilisateur. 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 la physique

Une simulation physique excessive peut être une cause clé d'augmentation du temps de calcul par trame, tant côté serveur que client.

Problèmes courants

  • Fréquence de pas de temps physique excessive - Par défaut, le comportement de pas est en mode adaptatif, où la physique s'exécute à 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 à pas à 240 Hz (quatre fois par trame). Cela entraîne des calculs considérablement plus lourds à chaque trame.

  • Nombre excessif d'objets simulés complexes - Plus il y a d'assemblages 3D simulés, plus les calculs physiques prennent de temps à chaque trame. Souvent, les jeux auront des objets simulés qui n'ont pas besoin de l'être ou auront des mécanismes ayant 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 les calculs.

Atténuation

  • Ancrez les parties qui ne nécessitent pas de simulation - Ancrez toutes les parties qui n'ont pas besoin d'être animées par la physique, telles que les NPC statiques.

  • Utilisez le pas de physique adaptatif - Le pas adaptatif ajuste dynamiquement le taux des 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

    • Dans la mesure du possible, minimisez le nombre de contraintes ou de joints physiques dans un assemblage.
    • Réduisez le taux de collision interne dans 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 petits objets ou les objets 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 à l'aide de 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 afficher la géométrie de collision à des fins de débogage dans Studio en activant Collision fidelity 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 approfondi 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 physiques et de rendu.

Portées de MicroProfiler

PortéeCalcul associé
physicsSteppedCalcul physique global
worldStepPas de physique discrets pris à chaque trame

Utilisation de la mémoire physique

Le mouvement physique et la détection de collisions 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 commun

Les modes de détection de collision par défaut et précise 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 ne nécessitent pas de collisions, désactivez leurs collisions en réglant BasePart.CanCollide, BasePart.CanTouch et BasePart.CanQuery sur false.
  • Réduisez la fidélité des collisions en utilisant le réglage CollisionFidelity. Box a le plus faible coût de mémoire, et Default et Precise sont généralement plus coûteux.
    • Il est généralement sûr de régler la fidélité de collision de toute petite partie ancrée sur Box.
    • Pour les maillages très complexes et volumineux, vous voudrez peut-être construire votre propre maillage de collision à partir de petits objets ayant une fidélité de collision de boîte.

Humanoïdes

Humanoid est une classe qui fournit une large gamme de fonctionnalités pour les 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 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 poser des problèmes dans les jeux où les avatars réapparaissent souvent.
    • Dans le MicroProfiler, des étiquettes longues updateInvalidatedFastClusters (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 bougent généralement n'ont pas besoin de la classe Humanoid.
  • Jouer des animations sur un grand nombre de NPCs depuis le serveur - Les animations de NPCs qui s'exécutent sur le serveur doivent être simulées sur le serveur et répliquées vers le client. Cela peut entraîner une surcharge inutile.
  • Effectuer des modifications de taille et d'échelle non nécessaires - Les changements de taille/échelle entraînent la reconstruction de FastCluster. Essayez de réduire ceci pendant le gameplay si vous constatez des problèmes de performance liés à FastCluster. De même, d'autres changements de propriété pourraient également entraîner la reconstruction de FastCluster, donc réduisez autant que possible ces changements.

Atténuation

  • Faites jouer les animations des NPCs sur le client - Dans les jeux avec un grand nombre de NPCs, 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é d'une réplication inutile. Cela permet également d'autres optimisations possibles (comme ne jouer des animations que pour les NPCs 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 NPCs statiques, utilisez un simple AnimationController, car ils n'ont pas besoin de se déplacer mais juste de jouer des animations.
    • Pour les NPCs 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 NPCs.
  • 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 à réapparition fréquente - Au lieu de détruire complètement un NPC, envoyez-le à une piscine de NPCs inactifs. Ainsi, lorsque qu'un nouveau NPC doit réapparaître, vous pouvez simplement réactiver l'un des NPCs de la piscine. Ce processus s'appelle le pooling, ce qui minimise le nombre de fois que des personnages doivent être instanciés.
  • Ne générez des NPCs que lorsque les utilisateurs sont à proximité - Évitez d'instancier des NPCs lorsque les utilisateurs ne sont pas à portée, et supprimez-les lorsque les utilisateurs quittent leur portée.
  • Évitez de modifier la hiérarchie de l'avatar après son instanciation - Certains changements dans la hiérarchie d'un avatar ont des implications significatives pour la performance. Certaines optimisations sont disponibles :
    • Pour des 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 devez attacher des objets BasePart à l'avatar, faites-le en dehors de la hiérarchie du Model de l'avatar.

Portées de MicroProfiler

PortéeCalcul associé
stepHumanoidContrôle et physique humanoïdes
stepAnimationAnimation d'humanoïde et d'animateur
updateInvalidatedFastClustersAssocié à l'instanciation ou à la modification d'un avatar

Rendu

Une partie significative du temps que le client passe à chaque trame est consacrée au rendu de la scène dans la trame 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 surcoût significatif. En général, moins il y a d'appels de dessin par trame, moins le temps de calcul est passé à rendre une trame.

Vous pouvez voir combien d'appels de dessin se produisent actuellement avec l'élément Statistiques de RenduTiming 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 lors d'une trame donnée, plus d'appels de dessin sont effectués vers le GPU. Cependant, le moteur Roblox utilise un processus appelé instanciation pour combiner 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 gérés dans un seul appel de dessin lorsque :

Autres problèmes courants

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

    Des objets tels que 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, des changements de propriété sur ParticleEmitters peuvent avoir un impact dramatique sur la performance.

  • 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 IDs d'actif de maillage ou de texture différents. Cela empêche l'instanciation et peut conduire à des appels de dessin inutiles.

    Un coupable courant ici est lorsque toute une scène est importée d'un coup, plutôt que des actifs individuels étant importés dans Roblox et ensuite dupliqués 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 utilisant des IDs 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 duplicata possibles
  • Complexité d'objet excessive - Bien que pas aussi important que le nombre d'appels de dessin, le nombre de triangles dans une scène influence le temps de rendu d'une trame. Les scènes avec un nombre très élevé de maillages 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 densité d'objets lumineux qui projettent des ombres (ou un nombre et une densité élevés de petites parties influencées par des ombres) peuvent rencontrer des problèmes de performance.

  • Surdépassement de la transparence élevée - Placer des objets à transparence partielle côte à côte 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 superposées.

  • Mouvement inutile de MeshPart skinnés - Les MeshParts skinnés faisant partie d'un Modèle sans un Humanoïde sont regroupés en utilisant des 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 la performance.

    • Un contournement très efficace consiste à intégrer un Humanoïde dans le Modèle. La présence d'un Humanoïde remplace le comportement par défaut de regroupement spatial, obligeant à l'utilisation d'un seul et unique FastCluster 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 goulot d'étranglement de performance. Cette technique doit être réservée exclusivement aux MeshParts dont le mouvement est attendu, car elle peut introduire une surcharge mémoire et annuler les avantages de l'optimisation spatiale. Nous vous recommandons de toujours profiler votre jeu après avoir effectué ce type de changements. Consultez conseils de performance pour Humanoïde pour plus d'informations.
  • 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

  • Instanciation des maillages identiques et réduction du nombre de maillages uniques - Si vous vous assurez que tous les maillages identiques ont les mêmes IDs d'actif sous-jacent, le moteur peut les reconnaître et les rendre dans un seul appel de dessin. Veillez à ne télécharger chaque maillage dans une carte qu'une seule fois, puis à les dupliquer dans Studio pour réutilisation plutôt que d'importer de grandes cartes dans leur intégralité, 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 constituent un mécanisme utile pour la réutilisation des objets.

  • Culling - Le culling décrit le processus d'élimination des appels de dessin pour les objets qui ne font pas partie de la trame rendue finale. Par défaut, le moteur saute les appels de dessin pour les objets en dehors du champ de vision de la caméra (culling du frustum) et les parties, maillages et terrains occlus de la vue par d'autres objets (culling d'occlusion). Dans certaines situations, comme dans des environnements intérieurs, vous pourriez être en mesure de mettre en œuvre un système de pièces ou de portails et de faire le culling des objets pour réduire encore plus 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 du monde sur SLIM pour rendre des maillages SLIM optimisés et légers à mesure que la distance à la caméra augmente.

  • Réduction du niveau de détail pour les avatars - Activez le streaming d'instance et définissez la propriété Workspace.EnableSLIMAvatars pour rendre les modèles d'avatars de plateforme avec n'importe quel nombre d'accessoires ou de couches de vêtements comme des représentations d'avatar légères et optimisées avec un support complet pour les animations à mesure que la distance à la caméra augmente.

  • Réduction de la fidélité de rendu - Réglez 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 les ombres complètement à 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 afin d'améliorer la performance tout en maintenant les ombres activées et d'augmenter les chances que les ombres restent activées. Voici quelques exemples d'optimisations que vous pouvez apporter 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 aux parties éloignées de la caméra de l'utilisateur.

    • Désactivez les ombres sur les objets mobiles lorsque cela est possible.

    • Désactivez Light.Shadows sur les instances de lumière où l'objet n'a pas besoin de projeter des ombres.

    • Limitez la portée et l'angle des instances de lumière.

    • 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 de pièce à pièce pour les environnements intérieurs.

Portées de MicroProfiler

PortéeCalcul associé
Prepare and PerformRendu global
Perform/Scene/computeLightingPerformMises à jour de grille lumineuse et d'ombres
LightGridCPUMises à jour de la grille lumineuse voxel
ShadowMapSystemCartographie des ombres
Perform/Scene/UpdateViewPréparation pour le rendu et mises à jour des particules
Perform/Scene/RenderViewRendu 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 trame, mais de plus grandes quantités d'informations nécessitent plus de temps de calcul.

Problèmes courants

  • Trafic distant excessif - Envoyer un grand volume 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 consacrée à traiter les paquets entrants à chaque trame. Les erreurs courantes comprennent :

    • Répliquer des données à chaque trame qui n'ont pas besoin d'être répliquées.
    • Répliquer des données lors de l'entrée utilisateur sans aucun mécanisme pour le limiter.
    • Dispatcher plus de données que nécessaire. Par exemple, envoyer l'inventaire entier du joueur lors de l'achat d'un article plutôt que juste 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 créer et détruire de grandes hiérarchies d'instances comme les cartes à exécution peut être très intensif sur le réseau.

    Un coupable courant ici est les données d'animation complexes sauvegardées par les plugins Animation Editor dans les rigs. Si celles-ci ne sont pas supprimées avant la publication du jeu 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 tween un objet côté serveur, la propriété tweenée est répliquée à chaque client à chaque trame. Cela entraîne non seulement un tween saccadé à mesure que la latence des clients fluctue, mais provoque é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 trame.
  • Divisez les arbres d'instances complexes comme les cartes et chargez-les par morceaux pour répartir le travail de réplication sur plusieurs trames.
  • 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 comprend :
    • Les effets visuels tels qu'une explosion ou un éclat de 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 à la première personne.
    • Tween des objets sur le client plutôt que sur le serveur.

Portées de MicroProfiler

PortéeCalcul associé
ProcessPacketsTraitement des paquets réseau entrants, tels que les invocations d'événements et les modifications de propriété
Allocate Bandwidth and Run SendersÉvénements sortants pertinents sur les serveurs

Utilisation de la mémoire d'actifs

Le mécanisme ayant le plus grand impact disponible pour les créateurs afin d'améliorer l'utilisation de la mémoire 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 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'instances 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'instances est basé sur la distance dans l'espace 3D, donc les mondes plus grands en bénéficient naturellement davantage.

Si le streaming d'instances est activé, vous pouvez augmenter son agressivité. Par exemple, envisagez de :

  • Réduire l'utilisation de Enum.ModelStreamingMode.Persistent dans la mesure du possible. Vous devrez peut-être mettre à jour vos scripts si vous l'utilisez comme mesure de compatibilité.
  • Réduire les Workspace.StreamingMinRadius et 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 engendre des IDs d'actif différents. Cela peut entraîner le chargement du même contenu en mémoire plusieurs fois.

  • Volume excessif d'actifs - 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 de gagner de la mémoire sont ratées.

  • Fichiers audio - Les fichiers audio peuvent contribuer de manière surprenante à l'utilisation de la mémoire, en particulier si vous les chargez tous dans le client à la fois, plutôt que de ne charger que ce dont vous avez besoin pour une partie du jeu. Pour des stratégies, consultez 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 pas d'avantage mémoire à télécharger des images dans un modèle de couleur associé à moins de bytes par pixel. De même, compresser les images avant le téléchargement ou supprimer le canal alpha des images qui n'en ont pas besoin peut diminuer la taille des images sur le disque, mais n'améliore pas l'utilisation de la mémoire.

    À 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 de l'appareil disponible, de la distance à 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 les 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 dupliqués - Recherchez les parties de maillage identiques et les textures qui sont téléchargées plusieurs fois avec des IDs différents.

    • Bien qu'il n'y ait pas d'API pour détecter automatiquement la similarité des actifs, vous pouvez collecter tous les IDs 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 IDs de maillage uniques et à les organiser par taille pour identifier manuellement les duplicatas.
    • 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 nuances.
  • Importez les actifs de la carte séparément - Au lieu d'importer une carte entière d'un coup, importez et reconstruisez les actifs de la carte individuellement et reconstruit-les. L'importateur ne fait pas de dé-duplication des maillages, donc si vous deviez importer une grande carte avec de nombreux carreaux de sol séparés, chacun de ces carreaux serait importé comme un actif distinct (même s'ils sont des duplicatas). Cela peut entraîner des problèmes de performance et de mémoire sur la ligne, chaque maillage étant traité individuellement et occupant de la mémoire ainsi que des appels de dessin.

  • Limitez les pixels des images à ne pas dépasser le minimum nécessaire. À moins qu'une image n'occupe une grande quantité d'espace physique à l'écran, elle n'a généralement besoin que de 512x512 pixels au maximum. La plupart des images mineures devraient être plus petites que 256x256 pixels.

  • Utilisez des feuilles de taille pour garantir un maximum de réutilisation des textures dans des cartes 3D. Pour des étapes et des exemples sur la façon de créer des feuilles de taille, consultez Créer des feuilles de taille.

    Vous pourriez également envisager d'utiliser des feuilles de sprites pour charger de nombreuses images d'interface utilisateur plus petites 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 apparition tardive. Cependant, une erreur courante est d'utiliser excessivement cette méthode pour précharger plus d'actifs que nécessaire.

Un exemple de mauvaise pratique est de charger l'intégralité du Workspace. Bien que cela puisse prévenir l'apparition tardive 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 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, n'utilisez ContentProvider:PreloadAsync() que dans des situations nécessaires, qui incluent :

  • Images dans l'écran de chargement.
  • Images importantes dans le menu de votre jeu, telles que les arrière-plans et les icônes des 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.

©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.