Mejorar el rendimiento

*Este contenido se traduce usando la IA (Beta) y puede contener errores. Para ver esta página en inglés, haz clic en aquí.

Esta página describe los problemas comunes de rendimiento y las mejores prácticas para mitigarlos.

Cálculo de scripts

Las operaciones costosas en el código Luau tardan más en procesarse y pueden impactar la tasa de fotogramas. A menos que se esté ejecutando en paralelo, el código Luau se ejecuta de forma sincrónica y bloquea el hilo principal hasta que encuentra una función que cede el hilo.

Problemas comunes

  • Operaciones intensivas en estructuras de tablas - Operaciones complejas como la serialización, deserialización y clonación profunda incurren en un alto costo de rendimiento, especialmente en estructuras de tablas grandes. Esto es especialmente cierto si estas operaciones son recursivas o implican iterar sobre estructuras de datos muy grandes.

  • Eventos de alta frecuencia - Atar operaciones costosas a eventos basados en fotogramas de RunService sin limitar la frecuencia significa que estas operaciones se repiten cada fotograma, lo que a menudo resulta en un aumento innecesario en el tiempo de cálculo. Estos eventos incluyen:

Mitigación

  • Invoca código en los eventos de RunService con moderación, limitando su uso a casos donde la invocación de alta frecuencia es esencial (por ejemplo, actualizar la cámara). Puedes ejecutar la mayoría de otros códigos en otros eventos o con menos frecuencia en un bucle.
  • Divide tareas grandes o costosas utilizando task.wait() para distribuir el trabajo a través de múltiples fotogramas.
  • Identifica y optimiza operaciones innecesariamente costosas y utiliza multithreading para tareas computacionales costosas que no necesitan acceder al modelo de datos.
  • Ciertos scripts del lado del servidor pueden beneficiarse de la generación de código nativo, una simple bandera que compila un script a código de máquina en lugar de bytecode.

Alcances de MicroProfiler

AlcanceCálculo asociado
RunService.PreRenderCódigo ejecutándose en el evento PreRender
RunService.PreSimulationCódigo ejecutándose en el evento Stepped
RunService.PostSimulationCódigo ejecutándose en el evento Heartbeat
RunService.HeartbeatCódigo ejecutándose en el evento Heartbeat

Para obtener más información sobre la depuración de scripts utilizando el MicroProfiler, consulta la biblioteca debug, que incluye funciones para etiquetar código específico y aumentar aún más la especificidad, como debug.profilebegin y debug.profileend. Muchos métodos de la API de Roblox llamados por scripts también tienen sus propias etiquetas asociadas de MicroProfiler que pueden proporcionar una señal útil.

Uso de memoria en scripts

Las fugas de memoria pueden ocurrir cuando escribes scripts que consumen memoria que el recolector de basura no puede liberar adecuadamente cuando ya no se utiliza. Las fugas son especialmente problemáticas en el servidor, porque pueden estar en línea continuamente durante muchos días, mientras que una sesión de cliente es mucho más corta.

Los siguientes valores de memoria en la Consola de desarrollador pueden indicar un problema que necesita más investigación:

  • LuaHeap - Consumo alto o en crecimiento sugiere una fuga de memoria.
  • InstanceCount - Números de instancias que crecen constantemente sugieren que las referencias a algunas instancias en tu código no están siendo recolectadas por la basura.
  • PlaceScriptMemory - Proporciona un desglose del uso de memoria por script.

Problemas comunes

  • Dejar conexiones conectadas - El motor nunca recoge eventos conectados a una instancia y cualquier valor referenciado dentro del callback conectado. Por lo tanto, las conexiones activas de eventos y el código dentro de las instancias conectadas, funciones conectadas y valores referenciados, están fuera del alcance del recolector de basura, incluso después de que se disparan los eventos.

    Aunque los eventos se desconectan cuando se destruye la instancia a la que pertenecen, un error común es asumir que esto se aplica a los objetos de Player. Después de que un usuario abandona un juego, el motor no destruye automáticamente su objeto representativo de Player y el modelo de personaje, por lo que las conexiones al objeto Player y a las instancias bajo el modelo del personaje, como CharacterAdded, aún consumen memoria si no las desconectas en tus scripts. Esto puede resultar en fugas de memoria muy significativas con el tiempo en el servidor a medida que cientos de usuarios se unen y abandonan el juego.

  • Tablas - Insertar objetos en tablas pero no eliminarlos cuando ya no son necesarios causa un consumo innecesario de memoria, especialmente para tablas que rastrean datos de usuarios cuando se unen. Por ejemplo, el siguiente fragmento de código crea una tabla añadiendo información del usuario cada vez que un usuario se une:

    Ejemplo
    local playerInfo = {}
    Players.PlayerAdded:Connect(function(player)
    playerInfo[player] = {} -- alguna información
    end)

    Si no eliminas estas entradas cuando ya no son necesarias, la tabla sigue creciendo en tamaño y consume más memoria a medida que más usuarios se unen a la sesión. Cualquier código que itera sobre esta tabla también se vuelve más costoso computacionalmente a medida que la tabla crece en tamaño.

Mitigación

Para limpiar todos los valores utilizados y prevenir fugas de memoria:

  • Desconectar todas las conexiones - Revisa tu base de código y asegúrate de que cada conexión esté limpiada a través de uno de los siguientes caminos:

    • Desconectando manualmente usando la función Disconnect().
    • Destruyendo la instancia a la que pertenece el evento con la función Destroy().
    • Destruyendo el objeto de script que la conexión rastrea.
  • Eliminar objetos de jugador y personajes después de salir - Habilita Workspace.PlayerCharacterDestroyBehavior para destruir automáticamente objetos de jugador y modelos de personajes después de que un usuario se va. Si prefieres, puedes limpiarlos manualmente:

    Ejemplo de limpieza de jugador y personaje
    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)

Cálculo de física

Una simulación excesiva de la física puede ser una causa clave del aumento del tiempo de cálculo por fotograma tanto en el servidor como en el cliente.

Problemas comunes

  • Frecuencia de pasos de física excesiva - Por defecto, el comportamiento de pasos está en modo adaptativo, donde la física da pasos a 60 Hz, 120 Hz o 240 Hz, dependiendo de la complejidad del mecanismo de física.

    También hay un modo fijo con mayor precisión de la física, que obliga a todos los ensamblajes físicos a dar pasos a 240 Hz (cuatro veces por fotograma). Esto resulta en un cálculo significativamente mayor en cada fotograma.

  • Número excesivo de complejidad de objetos simulados - Cuantos más ensamblajes 3D se simulen, más tiempo tarda el cálculo de física en cada fotograma. A menudo, los juegos tendrán objetos siendo simulados que no necesitan serlo o tendrán mecanismos que tienen más restricciones y juntas de las que necesitan.

  • Detección de colisiones demasiado precisa - Las partes de malla tienen una propiedad CollisionFidelity para detectar colisiones que ofrece una variedad de modos con diferentes niveles de impacto en el rendimiento. El modo de detección de colisiones precisa para partes de malla tiene el costo de rendimiento más elevado y tarda más en calcularse.

Mitigación

  • Anclar partes que no requieren simulación - Ancla todas las partes que no necesitan ser impulsadas por la física, como los NPCs estáticos.

  • Usar pasos de física adaptativos - El paso adaptativo ajusta dinámicamente la tasa de cálculos de física para mecanismos de física, permitiendo que las actualizaciones de física se realicen con menos frecuencia en algunos casos.

  • Reducir la complejidad de los mecanismos

    • Donde sea posible, minimiza el número de restricciones o juntas de física en un ensamblaje.
    • Reduce la cantidad de auto-colisión dentro de un mecanismo, como aplicando límites o restricciones de no-colisión a los miembros de un ragdoll para evitar que colisionen entre sí.
  • Reducir el uso de la fidelidad de colisión precisa para mallas

    • Para objetos pequeños o no interactivos donde los usuarios rara vez notarían la diferencia, utiliza fidelidad de caja.

    • Para objetos de tamaño pequeño a mediano, utiliza fidelidades de caja o casco, dependiendo de la forma.

    • Para objetos grandes y muy complejos, construye colisiones personalizadas utilizando partes invisibles cuando sea posible.

    • Para objetos que no requieren colisiones, desactiva las colisiones y utiliza fidelidad de caja o casco, ya que la geometría de colisión sigue almacenándose en memoria.

    • Puedes renderizar la geometría de colisión para propósitos de depuración en el Studio activando Fidelidad de colisión en el widget de Opciones de visualización en la esquina superior derecha de la vista 3D.

      Alternativamente, puedes aplicar el filtro CollisionFidelity=PreciseConvexDecomposition en el Explorador que muestra un recuento de todas las partes de malla con la fidelidad precisa y permite seleccionarlas fácilmente.

    • Para una guía detallada sobre cómo elegir una opción de fidelidad de colisión que equilibre tus requisitos de precisión y rendimiento, consulta Establecer parámetros de física y renderizado.

Alcances de MicroProfiler

AlcanceCálculo asociado
physicsSteppedCálculo total de física
worldStepPasos de física discretos tomados en cada fotograma

Uso de memoria en física

El movimiento de física y la detección de colisiones consumen memoria. Las partes de malla tienen una propiedad CollisionFidelity que determina el enfoque que se utiliza para evaluar los límites de colisión de la malla.

Problema común

Los modos de detección de colisiones por defecto y precisa consumen significativamente más memoria que los otros dos modos con formas de colisión de menor fidelidad.

Si ves niveles altos de consumo de memoria bajo PhysicsParts, es posible que necesites explorar la reducción de la fidelidad de colisión de objetos en tu juego.

Cómo mitigar

Para reducir la memoria utilizada para la fidelidad de colisión:

  • Para partes que no necesitan colisiones, desactiva sus colisiones configurando BasePart.CanCollide, BasePart.CanTouch y BasePart.CanQuery en false.
  • Reduce la fidelidad de las colisiones utilizando la configuración CollisionFidelity. Box tiene la sobrecarga de memoria más baja, y Default y Precise son generalmente más costosos.
    • Generalmente es seguro establecer la fidelidad de colisión de cualquier parte anclada pequeña en Box.
    • Para mallas grandes y muy complejas, puedes querer construir tu propia malla de colisión a partir de objetos más pequeños con fidelidad de colisión de caja.

Humanos

Humanoid es una clase que proporciona una amplia gama de funcionalidades a personajes jugadores y no jugadores (NPCs). Aunque es poderosa, una Humanoid tiene un costo de cálculo significativo.

Problemas comunes

  • Dejar habilitados todos los HumanoidStateTypes en NPCs - Hay un costo de rendimiento por dejar ciertos HumanoidStateTypes habilitados. Desactiva cualquiera que no sea necesaria para tus NPCs. Por ejemplo, a menos que tu NPC vaya a escalar escaleras, es seguro desactivar el estado Climbing.
  • Instanciar, modificar y reaparecer modelos con Humanoids o MeshParts esqueléticamente frecuentemente
    • Esto puede ser intensivo para que el motor lo procese, particularmente si estos modelos utilizan ropa en capas. Esto también puede ser particularmente problemático en juegos donde los avatares reaparecen a menudo.
    • En el MicroProfiler, las largas etiquetas updateInvalidatedFastClusters (más de 4 ms) son a menudo una señal de que la instanciación/modificación de avatares está provocando invalidaciones excesivas.
  • Usar Humanoides en casos donde no son necesarios - Los NPCs estáticos que no se mueven generalmente no tienen necesidad de la clase Humanoid.
  • Reproducir animaciones en un gran número de NPCs desde el servidor - Las animaciones de NPCs que se ejecutan en el servidor necesitan ser simuladas en el servidor y replicadas al cliente. Esto puede ser una sobrecarga innecesaria.
  • Realizar cambios de tamaño y escala innecesarios - Los cambios de tamaño/escala provocan la reconstrucción del FastCluster. Intenta reducir esto durante el juego si ves problemas de rendimiento relacionados con el FastCluster. De manera similar, otros cambios de propiedad también pueden provocar la reconstrucción del FastCluster, así que, en general, reduce estos cambios tanto como sea posible.

Mitigación

  • Reproducir animaciones de NPC en el cliente - En juegos con un gran número de NPCs, considera crear el Animator en el cliente y ejecutar las animaciones localmente. Esto reduce la carga en el servidor y la necesidad de replicación innecesaria. También permite optimizaciones adicionales (como reproducir animaciones solo para NPCs que están cerca del personaje).
  • Usa alternativas amigables para el rendimiento en lugar de Humanoides - Los modelos NPC no necesitan necesariamente contener un objeto humanoide.
    • Para NPCs estáticos, utiliza un simple AnimationController, porque no necesitan moverse, solo necesitan reproducir animaciones.
    • Para NPCs en movimiento, considera implementar tu propio controlador de movimiento y usar un AnimationController para animaciones, dependiendo de la complejidad de tus NPCs.
  • Desactiva estados humanoides no utilizados - Usa Humanoid:SetStateEnabled() para habilitar solo los estados necesarios para cada humanoide.
  • Agrupa modelos NPC con reaparecer frecuente - En lugar de destruir un NPC por completo, envía el NPC a un grupo de NPCs inactivos. De esta manera, cuando sea necesario un nuevo NPC para reaparecer, simplemente puedes reactivar uno de los NPCs del grupo. Este proceso se llama agrupamiento, lo que minimiza la cantidad de veces que los personajes necesitan ser instanciados.
  • Solo genera NPCs cuando los usuarios estén cerca - No generes NPCs cuando los usuarios no estén al alcance, y elimínalos cuando los usuarios abandonen su rango.
  • Evita hacer cambios en la jerarquía del avatar después de ser instanciado - Ciertas modificaciones a la jerarquía de un avatar tienen implicaciones de rendimiento significativas. Algunas optimizaciones están disponibles:

Alcances de MicroProfiler

AlcanceCálculo asociado
stepHumanoidControl y física humanoide
stepAnimationAnimación humanoide y animador
updateInvalidatedFastClustersAsociado con la instanciación o modificación de un avatar

Renderizado

Una parte significativa del tiempo que el cliente pasa en cada fotograma es en renderizar la escena en el fotograma actual. El servidor no realiza ningún renderizado, por lo que esta sección es exclusiva del cliente.

Llamadas de dibujo

Una llamada de dibujo es un conjunto de instrucciones del motor a la GPU para renderizar algo. Las llamadas de dibujo tienen una sobrecarga significativa. En general, cuantas menos llamadas de dibujo por fotograma, menos tiempo computacional se gasta en renderizar un fotograma.

Puedes ver cuántas llamadas de dibujo están ocurriendo actualmente con el elemento Estadísticas de renderizadoTemporización en Studio. Puedes ver las Estadísticas de renderizado en el cliente presionando ShiftF2.

Cuantos más objetos necesiten ser dibujados en tu escena en un fotograma dado, más llamadas de dibujo se realizan a la GPU. Sin embargo, el motor de Roblox utiliza un proceso llamado instanciación para colapsar mallas idénticas con las mismas características de textura en una sola llamada de dibujo. Específicamente, múltiples mallas con el mismo MeshContent se manejan en una sola llamada de dibujo cuando:

Otros problemas comunes

  • Densidad de objetos excesiva - Si una gran cantidad de objetos están concentrados con una alta densidad, entonces renderizar esta área de la escena requiere más llamadas de dibujo. Si encuentras que tu tasa de fotogramas disminuye al mirar una cierta parte del mapa, esto puede ser una buena señal de que la densidad de objetos en esta área es demasiado alta.

    Objetos como calcomanías, texturas y partículas no se agrupan bien e introducen llamadas de dibujo adicionales. Presta especial atención a estos tipos de objetos en una escena. En particular, los cambios de propiedad en ParticleEmitters pueden tener un impacto dramático en el rendimiento.

  • Oportunidades de instanciación perdidas - A menudo, una escena incluirá la misma malla duplicada varias veces, pero cada copia de la malla tiene diferentes ID de activos de malla o textura. Esto impide la instanciación y puede llevar a llamadas de dibujo innecesarias.

    Una causa común de este problema es cuando toda una escena se importa a la vez, en lugar de que se importen activos individuales a Roblox y luego se dupliquen después de la importación para ensamblar la escena.

    Incluso un script simple como este puede ayudarte a identificar partes de malla con el mismo nombre que utilizan diferentes ID de malla:

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

    La salida (con Stack Lines habilitado) podría parecerse a esto. Las líneas repetidas indican reutilización de la misma malla, lo cual es bueno. Las líneas únicas no son necesariamente malas, pero dependiendo de tu esquema de nombres, podrían indicar mallas duplicadas en tu juego:

    LargeRock, rbxassetid://106420009602747 (x144) -- bueno
    LargeRock, rbxassetid://120109824668127
    LargeRock, rbxassetid://134460273008628
    LargeRock, rbxassetid://139288987285823
    LargeRock, rbxassetid://71302144984955
    LargeRock, rbxassetid://90621205713698
    LargeRock, rbxassetid://113160939160788
    LargeRock, rbxassetid://135944592365226 -- todos posibles duplicados
  • Complejidad excesiva de objetos - Aunque no es tan importante como el número de llamadas de dibujo, el número de triángulos en una escena influye en cuánto tiempo tarda en renderizarse un fotograma. Las escenas con un número muy grande de mallas muy complejas son un problema común, así como las escenas con la propiedad MeshPart.RenderFidelity establecida en Precise en demasiadas mallas.

  • Proyección de sombras excesiva - Manejar sombras es un proceso costoso, y mapas que contienen un alto número y densidad de objetos de luz que proyectan sombras (o un alto número y densidad de partes pequeñas influenciadas por sombras) pueden tener problemas de rendimiento.

  • Exceso de traslape de transparencia - Colocar objetos con transparencia parcial cerca unos de otros obliga al motor a renderizar los píxeles superpuestos múltiples veces, lo que puede afectar el rendimiento. Para más información sobre cómo identificar y solucionar este problema, consulta Eliminar transparencias en capas.

  • Movimiento de MeshPart esqueléticos innecesarios - Los MeshParts esqueléticos que son parte de un Modelo sin un Humanoide se agrupan utilizando FastClusters organizados espacialmente. Cuando estos MeshParts se mueven, deben ser continuamente añadidos y eliminados de estos clústeres espaciales, obligando a reconstruir los clústeres y afectando el rendimiento.

    • Una solución altamente efectiva es incrustar un Humanoide dentro del Modelo. La presencia de un Humanoide anula el comportamiento de agrupamiento espacial por defecto, obligando al uso de un único FastCluster unificado para todo el Modelo. En consecuencia, las actualizaciones de posición ya no requieren reconstrucciones de clúster, mitigando así el cuello de botella de rendimiento. Esta técnica debe reservarse exclusivamente para MeshParts que se espera que se muevan, ya que puede introducir sobrecarga de memoria y anular los beneficios de la optimización espacial. Se recomienda siempre perfilar tu juego después de realizar este tipo de cambios. Consulta Consejos de rendimiento de humanoides para obtener información adicional.
  • Demasiadas partes en un Model - Demasiadas partes en un Modelo podrían causar reconstrucciones más frecuentes debido a la posibilidad de que una propiedad de una parte cambie, lo que llevaría a requerir una reconstrucción completa. Encuentra el equilibrio adecuado de partes en un Modelo cuando utiliza FastCluster.

Mitigación

  • Instanciar mallas idénticas y reducir la cantidad de mallas únicas - Si aseguras que todas las mallas idénticas tengan los mismos ID de activos subyacentes, el motor puede reconocerlas y renderizarlas en una sola llamada de dibujo. Asegúrate de subir solo cada malla en un mapa una vez y luego duplicarlas en Studio para reutilización, en lugar de importar grandes mapas como un todo, lo que podría causar que mallas idénticas tengan IDs de contenido separados y sean reconocidas como activos únicos por el motor. Paquetes son un mecanismo útil para reutilización de objetos.

  • Culling - Culling describe el proceso de eliminar llamadas de dibujo para objetos que no influyen en el fotograma renderizado final. Por defecto, el motor omite llamadas de dibujo para objetos fuera del campo de visión de la cámara (culling de frustum) y partes, mallas y terrenos ocultos de la vista por otros objetos (occlusion culling). En ciertos escenarios, como entornos interiores, podrías implementar un sistema de habitaciones o portal y eliminar objetos manualmente para reducir aún más las llamadas de dibujo o la carga computacional total.

  • Reducir el nivel de detalle para modelos - Habilita streaming de instancias y establece la propiedad LevelOfDetail de tus modelos del mundo en SLIM para renderizar mallas SLIM ligeras optimizadas a medida que aumenta la distancia de la cámara.

  • Reducir el nivel de detalle para avatares - Habilita el streaming de instancias y establece Workspace.EnableSLIMAvatars para renderizar avatares de plataforma como representaciones SLIM ligeras optimizadas con soporte completo de animaciones a medida que aumenta la distancia de la cámara.

  • Reducir la fidelidad de renderizado - Establece MeshPart.RenderFidelity en Automatic o Performance. Esto permite que las mallas caigan en alternativas menos complejas, lo que puede reducir la cantidad de polígonos que necesitan ser dibujados.

  • Desactivar la proyección de sombras en partes y objetos de luz apropiados - El motor de Roblox degrada automáticamente la calidad de la sombra a medida que disminuye el nivel de calidad gráfica del cliente, desactivando eventualmente las sombras por completo a niveles de calidad por debajo de 4. Sin embargo, puedes desactivar selectivamente las propiedades de proyección de sombras en objetos de luz y partes para mejorar el rendimiento mientras las sombras están habilitadas y aumentar la probabilidad de que las sombras sigan habilitadas. Algunos ejemplos de optimizaciones que puedes realizar ya sea al editar o dinámicamente en tiempo de ejecución:

    • Usa la propiedad BasePart.CastShadow para desactivar la proyección de sombras en partes pequeñas donde es poco probable que las sombras sean visibles. Esta estrategia es particularmente efectiva cuando se aplica a partes que están lejos de la cámara del usuario.

    • Desactiva las sombras en objetos en movimiento cuando sea posible.

    • Desactiva Light.Shadows en instancias de luz donde el objeto no necesita proyectar sombras.

    • Limita el rango y el ángulo de las instancias de luz.

    • Usa menos instancias de luz.

    • Considera desactivar luces que estén fuera de un rango específico o en una base habitación por habitación para entornos interiores.

Alcances de MicroProfiler

AlcanceCálculo asociado
Prepare and PerformRenderizado total
Perform/Scene/computeLightingPerformActualizaciones de luz y sombra
LightGridCPUActualizaciones de la cuadrícula de luz voxel
ShadowMapSystemMapeo de sombra
Perform/Scene/UpdateViewPreparación para el renderizado y actualizaciones de partículas
Perform/Scene/RenderViewRenderizado y post procesamiento

Redes y replicación

La red y la replicación describen el proceso por el cual los datos se envían entre el servidor y los clientes conectados. La información se envía entre el cliente y el servidor en cada fotograma, pero cantidades más grandes de información requieren más tiempo de cálculo.

Problemas comunes

  • Tráfico remoto excesivo - Enviar una gran cantidad de datos a través de objetos RemoteEvent o RemoteFunction o invocarlos con demasiada frecuencia puede llevar a que se gaste mucho tiempo de CPU procesando paquetes entrantes en cada fotograma. Errores comunes incluyen:

    • Replicar datos cada fotograma que no necesitan ser replicados.
    • Replicar datos en la entrada del usuario sin ningún mecanismo para limitarlo.
    • Despachar más datos de los necesarios. Por ejemplo, enviar todo el inventario del jugador cuando compra un ítem en lugar de solo detalles del ítem comprado.
  • Creación o eliminación de árboles de instancias complejas - Cuando se realiza un cambio en el modelo de datos en el servidor, se replica a los clientes conectados. Esto significa que crear y destruir grandes jerarquías de instancias como mapas en tiempo de ejecución puede ser muy intensivo en red.

    Un culpable común aquí es el complejo conjunto de datos de animación guardado por plugins de Animation Editor en rigs. Si estos no se eliminan antes de que se publique el juego y el modelo animado se clone regularmente, se replicará una gran cantidad de datos innecesariamente.

  • TweenService del lado del servidor - Si se utiliza TweenService para animar un objeto del lado del servidor, la propiedad animada se replica a cada cliente en cada fotograma. Esto no solo resulta en que la animación sea inestable a medida que fluctúa la latencia de los clientes, sino que causa un gran tráfico de red innecesario.

Mitigación

Puedes emplear las siguientes tácticas para reducir la replicación innecesaria:

  • Evita enviar grandes cantidades de datos a la vez a través de eventos remotos. En su lugar, envía solo los datos necesarios a una frecuencia más baja. Por ejemplo, para el estado de un personaje, réplicalo cuando cambie en lugar de cada fotograma.
  • Divide árboles de instancias complejos como mapas y cárguelos en partes para distribuir la tarea replicando esto a través de múltiples fotogramas.
  • Limpia los metadatos de animación, especialmente el directorio de animación de los rigs, después de importar.
  • Limita la replicación innecesaria de instancias, especialmente en casos donde el servidor no necesita tener conocimiento de las instancias que se crean. Esto incluye:
    • Efectos visuales como una explosión o un hechizo mágico. El servidor solo necesita saber la ubicación para determinar el resultado, mientras que los clientes pueden crear visuales localmente.
    • Modelos de vista de ítem de primera persona.
    • Tween objetos en el cliente en lugar de en el servidor.

Alcances de MicroProfiler

AlcanceCálculo asociado
ProcessPacketsProcesamiento de paquetes de red entrantes, como invocaciones de eventos y cambios de propiedades
Allocate Bandwidth and Run SendersEventos salientes relevantes en los servidores

Uso de memoria de activos

El mecanismo de mayor impacto disponible para los creadores para mejorar el uso de memoria del cliente es habilitar el streaming de instancias.

Streaming de instancias

El streaming de instancias carga selectivamente partes del modelo de datos que no son requeridos, lo que puede llevar a tiempos de carga considerablemente reducidos e incrementar la capacidad del cliente para prevenir bloqueos cuando se enfrenta a presión de memoria.

Si estás experimentando problemas de memoria y tienes el streaming de instancias deshabilitado, considera actualizar tu juego para soportarlo, especialmente si tu mundo 3D es grande. El streaming de instancias se basa en la distancia en el espacio 3D, así que los mundos más grandes se benefician más de él.

Si el streaming de instancias está habilitado, puedes aumentar su agresividad. Por ejemplo, considera:

  • Reducir el uso de Enum.ModelStreamingMode.Persistent donde sea posible. Puede que necesites actualizar tus scripts si lo estás usando como medida de compatibilidad.
  • Reducir el Workspace.StreamingMinRadius y Workspace.StreamingTargetRadius.

Para obtener más información sobre las opciones de streaming y sus beneficios, consulta propiedades de streaming.

Otros problemas comunes

  • Duplicación de activos - Un error común es subir el mismo activo varias veces resultando en diferentes IDs de activos. Esto puede llevar a que el mismo contenido se cargue en memoria múltiples veces.

  • Volumen excesivo de activos - Incluso cuando los activos no son idénticos, hay casos donde se pierden oportunidades de reutilizar el mismo activo y ahorrar memoria.

  • Archivos de audio - Los archivos de audio pueden ser un sorprendente contribuyente al uso de memoria, particularmente si cargas todos ellos en el cliente a la vez en lugar de solo cargar lo que necesitas para una parte del juego. Para estrategias, consulta Tiempos de carga.

  • Texturas de alta resolución - El consumo de memoria gráfica para una textura es independiente del tamaño de la textura en el disco; el número de píxeles en la textura determina el uso de memoria. Por ejemplo, una textura de 1024x1024 píxeles consume cuatro veces la memoria gráfica de una textura de 512x512.

    Las imágenes subidas a Roblox se transcodifican a un formato fijo, por lo que no hay beneficios de memoria al subir imágenes en un modelo de color asociado con menos bytes por píxel. Similarmente, comprimir imágenes antes de subirlas o eliminar el canal alfa de imágenes que no lo necesitan puede disminuir el tamaño de la imagen en disco, pero no mejora el uso de memoria.

    A medida que un juego se carga, el motor comienza automáticamente con texturas de menor calidad y luego aumenta la calidad según la memoria del dispositivo disponible, la distancia desde la cámara, la cantidad de espacio en pantalla que ocupa la textura y otros factores. Aún así, dimensionar estratégicamente tus texturas puede mejorar el uso de memoria en tu juego.

Mitigación

  • Sube activos solo una vez - Reutiliza el mismo ID de activo en objetos y asegura que los mismos activos, especialmente mallas e imágenes, no se suban por separado múltiples veces.

  • Encuentra y corrige activos duplicados - Busca partes de malla e imágenes idénticas que se hayan subido múltiples veces con diferentes IDs.

    • Aunque no hay una API para detectar la similitud de activos automáticamente, puedes recolectar todos los IDs de activos de imagen en tu lugar (ya sea manualmente o con un script), descargarlos y compararlos utilizando herramientas de comparación externas.
    • Para partes de malla, la mejor estrategia es tomar IDs de malla únicos y organizarlos por tamaño para identificar duplicados manualmente.
    • En lugar de usar texturas separadas para diferentes colores, sube una sola textura y utiliza la propiedad SurfaceAppearance.Color para aplicar varios tonos a ella.
  • Importa activos en mapas por separado - En lugar de importar un mapa entero a la vez, importa y reconstruye activos en el mapa de forma individual y reconstruyélos. El Importador no hace ninguna deduplicación de mallas, por lo que si importas un gran mapa con muchos azulejos de suelo separados, cada uno de esos azulejos se importará como un activo separado (incluso si son duplicados). Esto puede llevar a problemas de rendimiento y de memoria en el futuro, ya que cada malla se trata como individualmente y ocupa memoria y llamadas de dibujo.

  • Limita los píxeles de las imágenes a no más que la cantidad necesaria. A menos que una imagen ocupe una gran cantidad de espacio físico en la pantalla, generalmente necesita como máximo 512x512 píxeles. La mayoría de las imágenes menores deben ser más pequeñas que 256x256 píxeles.

  • Utiliza hojas de recortes para asegurar una reutilización máxima de texturas en mapas 3D. Para pasos y ejemplos sobre cómo crear hojas de recortes, consulta Crear hojas de recortes.

    También podrías considerar usar hojas de sprites para cargar muchas imágenes de UI más pequeñas como una sola imagen. Luego puedes usar ImageLabel.ImageRectOffset y ImageLabel.ImageRectSize para mostrar porciones de la hoja.

Tiempos de carga

Muchos juegos implementan pantallas de carga personalizadas y utilizan el método ContentProvider:PreloadAsync() para solicitar activos de modo que imágenes, sonidos y mallas se descarguen en segundo plano.

La ventaja de este enfoque es que te permite asegurarte de que las partes importantes de tu juego estén totalmente cargadas sin que aparezcan repentinamente. Sin embargo, un error común es utilizar en exceso este método para precargar más activos de los realmente necesarios.

Un ejemplo de una mala práctica es cargar todo Workspace. Aunque esto podría prevenir la aparición repentina de texturas, aumenta significativamente los tiempos de carga.

Otra práctica similar es utilizar ContentProvider.RequestQueueSize para asegurarte de que todos los activos solicitados hayan terminado de cargarse. Sin embargo, esto presenta el mismo problema de tiempos de carga significativamente aumentados, además de ser un método poco confiable debido a su naturaleza fluctuante.

En su lugar, utiliza ContentProvider:PreloadAsync() solo en situaciones necesarias, que incluyen:

  • Imágenes en la pantalla de carga.
  • Imágenes importantes en el menú de tu juego, como fondos de botones e íconos.
  • Activos importantes en el área de inicio o aparición.

Si necesitas cargar un gran número de activos, te recomendamos que proporciones un botón de Saltar carga.

©2026 Roblox Corporation. Roblox, el logotipo de Roblox y "Powering Imagination" son algunas de nuestras marcas registradas y no registradas en los Estados Unidos y otros países.