Esta página describe problemas comunes de rendimiento y mejores prácticas para mitigarlos.
Computación de scripts
Las operaciones costosas en el código Luau tardan más en procesarse y pueden así afectar la velocidad del marco.A menos que se ejecute en paralelo, el código Luau se ejecuta de forma sincronizada y bloquea el hilo principal hasta que encuentre una función que devuelva el hilo.
Problemas comunes
Operaciones intensivas en estructuras de tabla - Las operaciones complejas como la serialización, la deserialización y la clonación profunda incurren en un alto costo de rendimiento, especialmente en estructuras de tabla grandes.Esto es particularmente cierto si estas operaciones son recursivas o implican iterar sobre estructuras de datos muy grandes.
Eventos de alta frecuencia - Vincular operaciones costosas a eventos basados en marcos de RunService sin limitar la frecuencia significa que estas operaciones se repiten en cada marco, lo que a menudo resulta en un aumento innecesario del tiempo de cálculo.Estos eventos incluyen:
Mitigación
- Invoca código en RunService eventos esporádicamente, limitando el uso a casos en los que la invocación de alta frecuencia es esencial (por ejemplo, actualizar la cámara).Puedes ejecutar la mayoría del código restante en otros eventos o con menos frecuencia en un bucle.
- Divide tareas grandes o costosas usando task.wait() para distribuir el trabajo en múltiples marcos.
- Identifica y optimiza operaciones innecesariamente costosas y usa multihilos para tareas costosas computacionalmente que no necesitan acceder al modelo de datos.
- Ciertos scripts del lado del servidor pueden beneficiarse de generación de código nativo, una bandera simple que compila un script a código de máquina en lugar de código de bytes.
Alcances de perfilador micro
Alcance | Computación asociada |
PreRender de servicio.RunService | Código que se ejecuta en el evento PreRender |
Ejecutar servicio.PreSimulación | Código que se ejecuta en el evento Stepped |
Servicio de ejecución.PostSimulation | Código que se ejecuta en el evento Heartbeat |
Corazón de servicio. latido | Código que se ejecuta en el evento Heartbeat |
Para obtener más información sobre la depuración de scripts con el MicroProfiler, consulte 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 API de Roblox llamados por scripts también tienen sus propias etiquetas de MicroProfiler asociadas que pueden proporcionar una señal útil.
Uso de memoria de script
Los fugas de memoria pueden ocurrir cuando escribes scripts que consumen memoria que el recolector de basura no puede liberar correctamente cuando ya no está en uso.Las fugas son específicamente persistentes 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 del desarrollador pueden indicar un problema que necesita una investigación adicional:
- LuaHeap - Un consumo alto o creciente sugiere una fuga de memoria.
- Número de instancias - Consistente en aumentar constantemente el número de instancias sugiere que las referencias a algunas instancias en tu código no se están recolectando de forma consistente.
- Memoria de script de lugar - Proporciona un script por desglose de uso de memoria.
Problemas comunes
Dejar conexiones conectadas - El motor nunca recoge basura eventos conectados a una instancia y cualquier valor referenciado dentro del llamado conectado.Por lo tanto, las conexiones activas de eventos y código dentro de las instancias conectadas, las funciones conectadas y los valores referenciados están fuera del alcance del recolector de basura de memoria, incluso después de que se activen los eventos.
Aunque los eventos se desconectan cuando la instancia a la que pertenecen se destruye, un error común es asumir que esto se aplica a Player objetos comunes.Después de que un usuario abandone una experiencia, el motor no destruye automáticamente el objeto representativo Player y el modelo de personaje, por lo que las conexiones al objeto Player y las instancias bajo el modelo de personaje, como Player.CharacterAdded, aún consumen memoria si no los 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 dejan la experiencia.
Tablas - insertar objetos en tablas pero no eliminarlos cuando ya no se necesitan causa un consumo innecesario de memoria, especialmente para las tablas que rastrean los datos del usuario cuando se unen.Por ejemplo, el siguiente ejemplo de código crea una tabla que agrega información de usuario cada vez que un usuario se une:
Ejemplolocal playerInfo = {}Players.PlayerAdded:Connect(function(player)playerInfo[player] = {} -- algunos datosend)Si no elimina estas entradas cuando ya no se necesitan, 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 iterar sobre esta tabla también se vuelve más costoso de computar a medida que la tabla crece en tamaño.
Mitigación
Para limpiar todos los valores utilizados para prevenir fugas de memoria:
Desconectar todas las conexiones - Asegúrate de que cada conexión se limpie a través de uno de los siguientes caminos:
- Desconectando manualmente usando la función Disconnect().
- Destruir la instancia a la que pertenece el evento con la función Destroy().
- Destruir el objeto de script al que se remontan las conexiones.
Eliminar objetos y personajes del jugador después de salir - Implementar código para garantizar que no persistan conexiones después de que un usuario se vaya, como en el siguiente ejemplo:
EjemploPlayers.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)
Computación de física
La simulación de física excesiva puede ser una causa clave de un aumento del tiempo de cálculo por marco en el servidor y en el cliente.
Problemas comunes
Frecuencia de paso de física excesiva - Por defecto, el comportamiento de paso está en modo adaptativo , donde los pasos de física a 60 Hz, 120 Hz o 240 Hz, dependiendo de la complejidad del mecanismo de física.
También está disponible un modo fijo con una mayor precisión de la física, que obliga a todas las asambleas de física a pasar a 240 Hz (cuatro veces por marco).Esto resulta en una cantidad significativamente mayor de cálculo por cada marco.
Número excesivo de complejidad de objetos simulados - Cuantas más 3D se ensamblan, más tiempo toman las computaciones de física en cada marco.A menudo, las experiencias tendrán objetos que se simulan que no necesitan ser o tendrán mecanismos que tengan más restricciones y articulaciones de las que necesitan.
Detector de colisión demasiado preciso - Las piezas de malla tienen una propiedad CollisionFidelity para detectar colisiones que ofrece una variedad de modos con diferentes niveles de impacto de rendimiento.El modo de detección de colisión precisa para piezas de malla tiene el costo de rendimiento más alto y tarda más en ejecutarse al motor.
Mitigación
Partes de anclaje que no requieren simulación - Ancla todas las partes que no necesitan ser impulsadas por la física, como para NPC estáticos.
Utilice el paso de física adaptativa - 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 del mecanismo * Si es posible, minimice el número de restricciones o juntas de física en una сборка.
- Reduce la cantidad de colisión entre sí dentro de un mecanismo, como aplicando límites o restricciones de no colisión a las extremidades de ragdoll para evitar que se choquen entre sí.
Reducir el uso de precisa fidelidad de colisión para mallas * Para objetos pequeños o no interactuables donde los usuarios rara vez notarían la diferencia, use la fidelidad de la caja.
Para objetos de tamaño pequeño a mediano, utilice la fidelidad de caja o casco, dependiendo de la forma.
Para objetos grandes y muy complejos, construye colisiones personalizadas usando partes invisibles cuando sea posible.
Para objetos que no requieren colisiones, desactiva las colisiones y usa la fidelidad de la caja o del casco, ya que la geometría de colisión aún se almacena en la memoria.
Puedes renderizar la geometría de colisión con fines de depuración en Studio al alternar en fidelidad de colisión desde el widget de opciones de visualización en la esquina superior derecha del visor 3D.
Alternativamente, puedes aplicar el filtro CollisionFidelity=PreciseConvexDecomposition a la Explorador que muestra un recuento de todas las piezas de malla con la precisión exacta y te permite seleccionarlas fácilmente.
Para una demostración detallada de cómo elegir una opción de fidelidad de colisión que equilibre sus requisitos de precisión y rendimiento, consulte Establecer parámetros de física y renderizado.
Alcances de perfilador micro
Alcance | Computación asociada |
physicsStepped | Cálculo de física general |
paso mundial | Pasos de física discretos tomados en cada marco |
Uso de memoria de física
El movimiento físico y la detección de colisiones consumen memoria.Las piezas de malla tienen una propiedad CollisionFidelity que determina el enfoque que se usa para evaluar los límites de colisión de la malla.
Problema común
Los modos de detección de colisión predeterminados y precisos consumen significativamente más memoria que los otros dos modos con formas de colisión de menor fidelidad.
Si ves altos niveles de consumo de memoria bajo PhysicsParts , es posible que necesites explorar reducir la fidelidad de colisión de los objetos en tu experiencia.
Cómo mitigar
Para reducir la memoria utilizada para la fidelidad de colisión:
- Para las partes que no necesitan colisiones, desactiva sus colisiones al establecer BasePart.CanCollide , BasePart.CanTouch y BasePart.CanQuery a false .
- Reduzca la fidelidad de las colisiones usando la configuración CollisionFidelity.Box tiene la menor sobrecarga de memoria, y Default y Precise son generalmente más caros.
- Generalmente es seguro establecer la fidelidad de colisión de cualquier parte pequeña anclada a Box .
- Para mallas grandes muy complejas, es posible que desees construir tu propia malla de colisión a partir de objetos más pequeños con fidelidad de colisión de caja.
Humanoides
Humanoid es una clase que proporciona una amplia gama de funcionalidades a personajes jugadores y no jugadores (NPCs).Aunque potente, un Humanoid viene con un costo de cálculo significativo.
Problemas comunes
- Dejar todos los tipos de estado humanoide activados en los NPC - Hay un costo de rendimiento al dejar activado cierto HumanoidStateTypes.Deshabilita cualquiera que no sea necesario para tus NPCs.Por ejemplo, a menos que tu NPC vaya a escalar escaleras, es seguro deshabilitar el estado Climbing.
- Instantaneizar, modificar y reaparecer modelos con Humanoids con frecuencia * Esto puede ser intenso para que el motor lo procese, particularmente si estos modelos usan ropa en capas .Esto también puede ser particularmente problemático en experiencias en las que los avatares reaparecen a menudo.
- En el MicroProfiler , las etiquetas de actualización largas updateInvalidatedFastClusters (por encima de 4 ms) a menudo son una señal de que la instanciación/modificación del avatar está desencadenando invalidaciones excesivas.
- Usando humanoides en casos en que no se requieren - Los NPC 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 NPC que se ejecutan en el servidor deben simularse en el servidor y replicarse al cliente.Esto puede ser una carga innecesaria.
Mitigación
- Reproducir animaciones de NPC en el cliente - En experiencias con un gran número de NPC, considere 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 hace posibles optimizaciones adicionales (como solo reproducir animaciones para NPCs que están cerca del personaje).
- Utilice alternativas de rendimiento amigables con los humanoides - Los modelos de NPC no necesariamente deben contener un objeto humanoide.
- Para NPCs estáticos, use un simple AnimationController , porque no necesitan moverse pero solo necesitan reproducir animaciones.
- Para mover NPC, considere implementar su propio controlador de movimiento y utilizar un AnimationController para las animaciones, dependiendo de la complejidad de sus NPC.
- Desactivar estados humanoides no utilizados - Utilice Humanoid:SetStateEnabled() para habilitar solo los estados necesarios para cada humanoide.
- Modelos NPC de piscina con respawning frecuente - En lugar de destruir un NPC completamente, envíe el NPC a una piscina de NPC inactivos.De esta manera, cuando se requiere un nuevo NPC para reaparecer, puedes simplemente reactivar uno de los NPC de la piscina.Este proceso se llama agrupación, que minimiza la cantidad de veces que los personajes deben ser instanciados.
- Solo engendra NPCs cuando los usuarios están cerca - No engendre NPCs cuando los usuarios no estén en rango, y elimínelos cuando los usuarios salgan de su rango.
- Evite hacer cambios en la jerarquía de avatares después de que se instancie - Ciertas modificaciones a una jerarquía de avatares tienen implicaciones de rendimiento significativas.Algunas optimizaciones están disponibles:
- Para las animaciones procedurales personalizadas, no actualice las propiedades JointInstance.C0 y JointInstance.C1. En cambio, actualice la propiedad Motor6D.Transform.
- Si necesitas adjuntar cualquier objeto BasePart a tu avatar, hazlo fuera de la jerarquía del avatar Model .
Alcances de perfilador micro
Alcance | Computación asociada |
stepHumanoido | Control y física humanoides |
paso de animación | Animación humanoide y animador |
actualizar clústeres rápidos inválidos | Asociado con la instalación o modificación de un avatar |
Renderizado
Una porción significativa del tiempo que el cliente pasa en cada marco está en la renderización de la escena en el marco actual.El servidor no hace 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 un overhead significativo.En general, cuantas menos llamadas de dibujo por marco, menos tiempo se gasta en renderizar un marco.
Puedes ver cuántas llamadas de dibujo están ocurriendo actualmente con el elemento Estadísticas de renderizado > Tiempo en Studio.Puedes ver Estadísticas de renderizado en el cliente presionando ShiftF2 .
Cuantos más objetos deben dibujarse en tu escena en un marco determinado, más llamadas de dibujo se hacen 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.En particular, múltiples mallas con el mismo MeshId se manejan en una sola llamada de dibujo cuando:
- Los materiales son idénticos cuando ambos SurfaceAppearance y MeshPart.TextureID no existen.
Otros problemas comunes
Densidad de objetos excesiva - Si un gran número de objetos se concentran con una alta densidad, entonces renderizar esta área de la escena requiere más llamadas de dibujo.Si estás encontrando que tu velocidad 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.
Los objetos como imágenes, texturas y partículas no se batch bien y introducen llamadas de dibujo adicionales.Presta especial atención a estos tipos de objetos en una escena.En particular, los cambios de propiedad a ParticleEmitters pueden tener un impacto dramático en el rendimiento.
Oportunidades de instanciamiento perdidas - A menudo, una escena incluirá la misma malla duplicada varias veces, pero cada copia de la malla tiene diferentes ID de atributos de malla o textura.Esto evita la instanciación y puede conducir a llamadas de dibujo innecesarias.
Una causa común de este problema es cuando se importa una escena completa a la vez, en lugar de importar activos individuales a Roblox y luego duplicarlos después de la importación para montar la escena.
Incluso un simple script como este puede ayudarlo a identificar piezas de malla con el mismo nombre que usan diferentes ID de malla:
local Workspace = game:GetService("Workspace")for _, descendant in Workspace:GetDescendants() doif descendant:IsA("MeshPart") thenprint(descendant.Name .. ", " .. descendant.MeshId)endendLa salida (con Líneas de pila habilitadas) podría verse algo así.Las líneas repetidas indican el uso repetido de la misma malla, lo cual es bueno.Las líneas únicas no necesariamente son malas, pero dependiendo de tu esquema de nomenclatura, podría indicar mallas duplicadas en tu experiencia:
LargeRock, rbxassetid://106420009602747 (x144) -- goodLargeRock, rbxassetid://120109824668127LargeRock, rbxassetid://134460273008628LargeRock, rbxassetid://139288987285823LargeRock, rbxassetid://71302144984955LargeRock, rbxassetid://90621205713698LargeRock, rbxassetid://113160939160788LargeRock, rbxassetid://135944592365226 -- all possible duplicatesComplejidad de objeto excesiva - 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 marco.Las escenas con un número muy grande de mallas muy complejas son un problema común, al igual que las escenas con el conjunto de propiedades MeshPart.RenderFidelity configurado en Enum.RenderFidelity.Precise en demasiadas mallas.
Proyección de sombras excesiva - La manipulación de las sombras es un proceso costoso, y los mapas que contienen un alto número y densidad de objetos que proyectan sombras (o un alto número y densidad de piezas pequeñas influenciadas por las sombras) es probable que tengan problemas de rendimiento.
Sobrecarga de transparencia alta - Colocar objetos con transparencia parcial cerca el uno del otro obliga al motor a renderizar los píxeles superpuestos varias veces, lo que puede dañar el rendimiento.Para obtener más información sobre la identificación y solución de este problema, consulte Eliminar transparencias en capas.
Mitigación
- Instanciando mallas idénticas y reduciendo la cantidad de mallas únicas - Si garantizas que todas las mallas idénticas tengan los mismos ID de activo subyacentes, el motor puede reconocerlas y renderizarlas en una sola llamada de dibujo.Asegúrese de subir solo cada malla en un mapa una vez y luego duplicarlas en Studio para reutilizarlas en lugar de importar grandes mapas en su conjunto, lo que podría causar que las mallas idénticas tengan ID de contenido separados y sean reconocidas como activos únicos por el motor.Los paquetes son un mecanismo útil para la reutilización de objetos.
- Selección - La selección describe el proceso de eliminar llamadas de dibujo para objetos que no facturan en el marco renderizado final.Por defecto, el motor omite las llamadas de dibujo para objetos fuera del campo de visión de la cámara (recorte de frustum), pero no omite las llamadas de dibujo para objetos ocultos de la vista por otros objetos (recorte de occlusión).Si tu escena tiene un gran número de llamadas de dibujo, considera implementar tu propia selección adicional en tiempo de ejecución de forma dinámica para cada marco, como aplicar las siguientes estrategias comunes:
- Para entornos interiores, implementa un sistema de habitación o portal que esconda objetos que no estén actualmente ocupados por ningún usuario.
- Reduciendo la fidelidad del renderizado - Establecer la fidelidad del renderizado en Automático o Rendimiento .Esto permite que las mallas vuelvan a las alternativas menos complejas, lo que puede reducir el número de polígonos que deben dibujarse.
- Desactivar el lanzamiento de sombras en las partes y objetos ligeros apropiados - La complejidad de las sombras en una escena se puede reducir desactivando selectivamente las propiedades de lanzamiento de sombras en objetos ligeros y partes.Esto se puede hacer en el momento de editar o dinámicamente en tiempo de ejecución.Algunos ejemplos son:
Usa la propiedad BasePart.CastShadow para desactivar el lanzamiento de sombras en pequeñas partes donde es poco probable que las sombras sean visibles.Esto puede ser particularmente efectivo cuando solo se aplica a partes que están lejos de la cámara del usuario.
Desactivar las sombras en los objetos móviles cuando sea posible.
Desactivar Light.Shadows en instancias ligeras donde el objeto no necesita lanzar sombras.
Límite del rango y el ángulo de las instancias de luz.
Usa menos instancias ligeras.
Considera desactivar las luces que están fuera de un rango específico o en una base por habitación para entornos interiores.
Alcances de perfilador micro
Alcance | Computación asociada |
Preparar y realizar | Renderizado general |
Ejecutar/Escena/ComputeLightingPerform | Actualizaciones de la cuadrícula ligera y las sombras |
Procesador de cuadrícula ligera | Actualizaciones de la cuadrícula de luz de voxel |
Sistema de mapa de sombras | Mapa de sombras |
Ejecutar/Escena/Actualizar vista | Preparación para la renderización y actualizaciones de partículas |
Ejecutar/Escena/Renderizar vista | Renderizado y postprocesado |
Redes y replicación
La red y la replicación describen el proceso por el cual se envían los datos entre el servidor y los clientes conectados.La información se envía entre el cliente y el servidor en cada marco, pero mayores cantidades de información requieren más tiempo de procesamiento.
Problemas comunes
Tráfico remoto excesivo - Enviar una gran cantidad de datos a través de RemoteEvent o RemoteFunction objetos o invocarlos con mucha frecuencia puede conducir a que se gaste mucho tiempo de CPU procesando paquetes entrantes en cada marco.Los errores comunes incluyen:
- Replicando datos cada marco que no necesita ser replicado.
- Replicar datos en la entrada del usuario sin ningún mecanismo para limitarlo.
- Enviar más datos de los que se requiere.Por ejemplo, enviar todo el inventario del jugador cuando compran un artículo en lugar de solo detalles del artículo comprado.
Creación o eliminación de árboles de instancias complejos - 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 los datos de animación complejos guardados por los plugins del editor de animación en rigs.Si estas no se eliminan antes de que se publique el juego y el modelo animado se clone regularmente, una gran cantidad de datos se replicará innecesariamente.
Servicio de transición del lado del servidor - Si TweenService se usa para transicionar un objeto del lado del servidor, la propiedad transicionada se replica a cada cliente en cada marco.No solo esto resulta en que el preadolescente esté inquieto a medida que fluctúa la latencia de los clientes, sino que también causa mucho tráfico de red innecesario.
Mitigación
Puedes emplear las siguientes tácticas para reducir la replicación innecesaria:
- Evite enviar grandes cantidades de datos a la vez a través de eventos remotos .En cambio, envíe solo los datos necesarios con una menor frecuencia.Por ejemplo, para el estado de un personaje, réplicalo cuando cambie en lugar de cada marco.
- Agrupar árboles de instancias complejos como mapas y cargarlos en pedazos para distribuir el trabajo que replica esto en múltiples marcos.
- Limpiar metadatos de animación , especialmente el directorio de animaciones de rigs, después de importar.
- Límite de la replicación de instancias innecesarias , especialmente en casos en que el servidor no necesita tener conocimiento de las instancias que se están creando.Esto incluye:
- Efectos visuales como una explosión o una explosión de hechizos mágicos.El servidor solo necesita saber la ubicación para determinar el resultado, mientras que los clientes pueden crear visuales localmente.
- Modelos de vista de elementos de primera persona.
- Objetos de intermedio en el cliente en lugar del servidor.
Alcances de perfilador micro
Alcance | Computación asociada |
Paquetes de proceso | Procesamiento de paquetes de red entrantes, como invocaciones de eventos y cambios de propiedad |
Asignar ancho de banda y ejecutar remitentes | Eventos salientes relevantes en los servidores |
Uso de memoria de activos
El mecanismo de mayor impacto disponible para los creadores para mejorar el uso de la memoria del cliente es habilitar transmisión de instancias.
Transmisión de instancias
La transmisión de instancias carga selectivamente partes del modelo de datos que no son necesarias, lo que puede conducir a un tiempo de carga considerablemente reducido y aumentar la capacidad del cliente para evitar colapsos cuando entra en presión de memoria.
Si está experimentando problemas de memoria y tiene deshabilitado el streaming de instancias, considere actualizar su experiencia para admitirlo, particularmente si su mundo 3D es grande.La transmisión de instancias se basa en la distancia en el espacio 3D, por lo que los mundos más grandes se benefician naturalmente más de ella.
Si se habilita el streaming de instancias, puedes aumentar la agresividad. Por ejemplo, considera:
- Reducir el uso del persistente StreamingIntegrity .
- Reducir el radio de transmisión .
Para obtener más información sobre las opciones de transmisión y sus beneficios, consulte Propiedades de transmisión.
Otros problemas comunes
- Duplicación de recursos - Un error común es subir el mismo recurso varias veces resultando en diferentes ID de recurso.Esto puede conducir a que el mismo contenido se cargue en la memoria varias veces.
- Volumen de activos excesivo - Incluso cuando los activos no son idénticos, hay casos en que se pierden oportunidades de reutilizar el mismo activo y ahorrar memoria.
- Archivos de audio - Los archivos de audio pueden ser un contribuyente sorprendente al uso de la memoria, particularmente si los carga todos en el cliente a la vez en lugar de cargar solo lo que necesita para una parte de la experiencia.Para estrategias, vea Tiempos de carga.
- Texturas de alta resolución - El consumo de memoria gráfica para una textura no está relacionado con el tamaño de la textura en el disco, sino más bien con el número de píxeles en la textura.
- Por ejemplo, una textura de píxeles de 1024x1024 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 beneficio de memoria al subir imágenes en un modelo de color asociado con menos bytes por píxel.Del mismo modo, comprimir imágenes antes de subir o eliminar el canal alfa de imágenes que no lo necesitan puede reducir el tamaño de las imágenes en el disco, pero ni mejora ni mejora mínimamente el uso de la memoria.Aunque el motor reduce automáticamente la resolución de textura en algunos dispositivos, el alcance de la reducción depende de las características del dispositivo, y la resolución de textura excesiva aún puede causar problemas.
- Puedes identificar el consumo de memoria gráfica para una determinada textura expandiendo la categoría Textura gráfica en la consola del desarrollador .
Mitigación
Solo sube recursos una vez - Reutilice el mismo ID de recurso entre objetos y asegúrese de que los mismos recursos, especialmente mallas y imágenes, no se suban repetidamente varias veces.
Encuentra y corrige los recursos duplicados - Busca partes de malla y texturas idénticas que se suben varias veces con diferentes ID.
- Aunque no hay API para detectar la similitud de los activos automáticamente, puedes recopilar todas las ID de activos de imagen en tu lugar (ya sea manualmente o con un script), descargarlas y compararlas usando herramientas de comparación externas.
- Para las piezas de malla, la mejor estrategia es tomar IDs de malla únicos y organizarlos por tamaño para identificar manualmente duplicados.
- En lugar de usar texturas separadas para diferentes colores, sube una sola textura y usa la propiedad SurfaceAppearance.Color para aplicar varios tonos a ella.
Importar recursos en el mapa por separado - En lugar de importar un mapa completo a la vez, importa y reconstruye los recursos en el mapa individualmente y reconstruyelos.El importador de 3D no hace ninguna duplicación de mallas, por lo que si importas un mapa grande con muchas baldosas separadas, cada una de esas baldosas se importaría como un activo separado (incluso si son duplicadas).Esto puede conducir a problemas de rendimiento y memoria a lo largo de la línea, ya que cada malla se trata como individualmente y ocupa memoria y llamadas de dibujo.
Límite los píxeles de las imágenes a no más de la cantidad necesaria.A menos que una imagen esté ocupando una gran cantidad de espacio físico en la pantalla, generalmente necesita un máximo de 512x512 píxeles.La mayoría de las imágenes menores deberían ser más pequeñas que 256x256 píxeles.
Utilice hojas de recorte para garantizar el máximo reutilización de texturas en mapas 3D.Para pasos y ejemplos de cómo crear hojas de recorte, vea Crear hojas de recorte.
También podría considerar usar hojas de sprites para cargar muchas imágenes de interfaz de usuario 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
Muchas experiencias implementan pantallas de carga personalizadas y usan el método ContentProvider:PreloadAsync() para solicitar recursos para que las imágenes, los sonidos y las mallas se descarguen en el fondo.
La ventaja de este enfoque es que te permite asegurarte de que las partes importantes de tu experiencia estén completamente cargadas sin interrupciones.Sin embargo, un error común es sobreutilizar este método para precargar más recursos de los que realmente se requieren.
Un ejemplo de una mala práctica es cargar toda la Workspace . Aunque esto podría evitar que aparezca la textura, aumenta significativamente el tiempo de carga.
En cambio, solo use ContentProvider:PreloadAsync() en situaciones necesarias, que incluyen:
- Imágenes en la pantalla de carga.
- Imágenes importantes en el menú de tu experiencia, como fondos de botones y iconos.
- Activos importantes en la zona de inicio o generación.
Si debes cargar un gran número de recursos, te recomendamos que proporciones un botón Saltar carga .