
Este es el quinto de una serie de artículos que desglosan consejos de optimización para tus proyectos de Unity. Úsalos como guía para funcionar a tasas de fotogramas más altas con menos recursos. Una vez que hayas probado estas mejores prácticas, asegúrate de revisar las otras páginas de la serie:
La física puede crear una jugabilidad intrincada, pero esto viene con un costo de rendimiento. Una vez que conozcas estos costos, puedes ajustar la simulación para gestionarlos adecuadamente. Usa estos consejos para mantenerte dentro de tu tasa de fotogramas objetivo y crear una reproducción fluida con la física integrada de Unity (NVIDIA PhysX).
Consulta nuestras últimas guías de optimización para desarrolladores y artistas de Unity 6:
Las mallas utilizadas en física pasan por un proceso llamado cocción. Esto prepara la malla para que pueda trabajar con consultas de física como raycasts, contactos, etc.
Un MeshCollider tiene varias OpcionesDeCocción para ayudarte a validar la malla para física. Si estás seguro de que tu malla no necesita estas verificaciones, puedes desactivarlas para acelerar tu tiempo de cocción.
En las OpcionesDeCocción para cada MeshCollider, simplemente desmarca EnableMeshCleaning, WeldColocatedVertices y CookForFasterSimulation. Estas opciones son valiosas para mallas generadas proceduralmente en tiempo de ejecución, pero se pueden desactivar si tus mallas ya tienen los triángulos adecuados.
Además, si estás apuntando a PC, asegúrate de mantener habilitado Use Fast Midphase. Esto cambia a un algoritmo más rápido de PhysX 4.1 durante la fase media de la simulación (lo que ayuda a reducir un pequeño conjunto de triángulos potencialmente intersectantes para consultas de física).
Aprende más en la documentación de OpcionesDeCocción.

Si estás generando mallas proceduralmente durante el juego, puedes crear un Mesh Collider en tiempo de ejecución. Agregar un componente MeshCollider directamente a la malla, sin embargo, cocina/hornéa la física en el hilo principal. Esto puede consumir un tiempo significativo de CPU.
Utiliza Physics.BakeMesh para preparar una malla para su uso con un MeshCollider y guarda los datos horneados con la malla misma. Un nuevo MeshCollider que referencia esta malla reutilizará estos datos precocinados (en lugar de hornear la malla nuevamente). Esto puede ayudar a reducir el tiempo de carga de la escena o el tiempo de instanciación más adelante.
Para optimizar el rendimiento, puedes descargar la cocción de mallas a otro hilo con el C# job system.
Consulta este ejemplo para obtener detalles sobre cómo hornear mallas a través de múltiples hilos.

En Player Settings, marca Prebake Collision Meshes siempre que sea posible. También recomendamos revisar la configuración de la Collision Matrix para asegurarte de que los objetos del jugador y de la mecánica del juego estén en las capas correctas.
Eliminar callbacks de triggers para capas innecesarias puede ser una gran ventaja, así que intenta simplificar tu Layer Collision Matrix. Puedes editar tus Physics Settings a través de Project Settings > Physics.
Aprende más en la documentación de la Collision Matrix.

Los motores de física funcionan ejecutándose en un paso de tiempo fijo. Para ver la tasa fija a la que se está ejecutando tu proyecto, ve a Edit > Project Settings > Time.
El campo Fixed Timestep define el delta de tiempo utilizado por cada paso de física. Por ejemplo, el valor predeterminado de 0.02 segundos (20 ms) es equivalente a 50 fps, o 50 Hz.
Debido a que cada fotograma en Unity toma una cantidad variable de tiempo, no está perfectamente sincronizado con la simulación de física. El motor cuenta hasta el siguiente paso de tiempo de física. Si un fotograma se ejecuta ligeramente más lento o más rápido, Unity utiliza el tiempo transcurrido para saber cuándo ejecutar la simulación de física en el paso de tiempo adecuado.
En el caso de que un fotograma tarde mucho en prepararse, esto puede llevar a problemas de rendimiento. Por ejemplo, si tu juego experimenta un pico (por ejemplo, instanciando muchos GameObjects o cargando un archivo desde el disco), el fotograma podría tardar 40 ms o más en ejecutarse. Con el paso de tiempo fijo predeterminado de 20 ms, esto haría que se ejecutaran dos simulaciones de física en el siguiente fotograma para "ponerse al día" con el paso de tiempo variable.
Las simulaciones de física adicionales, a su vez, añaden más tiempo para procesar el fotograma. En plataformas de gama baja, esto puede llevar a un espiral descendente de rendimiento.
Un fotograma subsiguiente que tarda más en prepararse hace que la acumulación de simulaciones de física sea más larga también. Esto lleva a fotogramas aún más lentos y aún más simulaciones que ejecutar por fotograma. El resultado es un rendimiento cada vez peor.
Eventualmente, el tiempo entre actualizaciones de física podría exceder el paso de tiempo máximo permitido. Después de este corte, Unity comienza a descartar actualizaciones de física, y el juego se entrecorta.
Para evitar problemas de rendimiento con la física:
Simula el paso de física manualmente si es necesario eligiendo el Modo de Simulación durante la fase de actualización del fotograma. Esto te permite tomar el control de cuándo ejecutar el paso de física. Pasa Time.deltaTime a Physics.Simulate para mantener la física sincronizada con el tiempo de simulación. Este enfoque puede causar inestabilidades en la simulación de física en escenas con física compleja o tiempos de fotogramas altamente variables, así que úsalo con precaución.
Aprende más en la documentación de Physics.Simulate.

El motor de física de Unity se ejecuta en dos pasos:
La configuración predeterminada de la fase amplia de Barrido y Poda (Edit > Configuración del Proyecto > Física > Tipo de BroadPhase) puede generar falsos positivos para mundos que son generalmente planos y tienen muchos colisionadores. Si tu escena es grande y mayormente plana, evita este problema y cambia a Poda de Caja Automática o Poda de Multicaja Broadphase. Estas opciones dividen el mundo en una cuadrícula, donde cada celda de la cuadrícula realiza barrido y poda.
La Poda de Multicaja Broadphase te permite especificar manualmente los límites del mundo y el número de celdas de la cuadrícula, mientras que la Poda de Caja Automática calcula eso por ti.
Consulta la lista completa de propiedades de Física aquí.

Si deseas simular un cuerpo de física específico con más precisión, aumenta sus Rigidbody.solverIterations.
Esto anula el Physics.defaultSolverIterations, que también se puede encontrar en Editar > Configuración del Proyecto > Física > Iteraciones del Solucionador Predeterminado.
Para optimizar tus simulaciones de física, establece un valor relativamente bajo en el defaultSolveIterations del proyecto. Luego aplica valores más altos de Rigidbody.solverIterations a las instancias individuales que necesitan más detalle.
Obtén más información sobre Rigidbody.solverIterations.

Por defecto, Unity no sincroniza automáticamente los cambios en los Transforms con el motor de física. En su lugar, espera hasta la próxima actualización de física o hasta que llames manualmente a Physics.SyncTransforms. Cuando esto está habilitado, cualquier Rigidbody o Collider en ese Transform o sus hijos se sincroniza automáticamente con el motor de física.
Cuándo sincronizar manualmente
Cuando autoSyncTransforms está deshabilitado, Unity solo sincroniza las transformaciones antes del paso de simulación de física en FixedUpdate o cuando se solicita explícitamente a través de Physics.Simulate. Es posible que necesites realizar sincronizaciones adicionales si utilizas APIs que leen directamente del motor de física entre cambios de Transform y la actualización de física. Los ejemplos incluyen acceder a Rigidbody.position o realizar Physics.Raycast.
Mejor práctica de rendimiento
Aunque autoSyncTransforms asegura consultas de física actualizadas, incurre en un costo de rendimiento. Cada llamada a una API relacionada con la física fuerza una sincronización, lo que puede degradar el rendimiento, especialmente con múltiples consultas sucesivas. Sigue estas mejores prácticas:
Descubre más sobre Physics.SyncTransforms.

Los arreglos de contacto son generalmente significativamente más rápidos, por lo que la recomendación general es usar esos en lugar de reutilizar callbacks de colisión, sin embargo, considera lo siguiente si tienes un caso de uso específico para ello.
Los callbacks MonoBehaviour.OnCollisionEnter, MonoBehaviour.OnCollisionStay y MonoBehaviour.OnCollisionExit toman una instancia de colisión como parámetro. Esta instancia de colisión se asigna en el montón administrado y debe ser recolectada por el recolector de basura.
Para reducir la cantidad de basura generada, habilita Physics.reuseCollisionCallbacks (también se encuentra en Configuraciones de Proyectos > Física > Reutilizar Callbacks de Colisión). Con esto activo, Unity solo asigna una única instancia de par de colisión a cada callback. Esto reduce el desperdicio para el recolector de basura y mejora el rendimiento.
La recomendación general es habilitar siempre Reutilizar Callbacks de Colisión para beneficios de rendimiento. Solo debes desactivar esta función para proyectos heredados donde el código depende de instancias individuales de la clase Collision, lo que hace impráctico almacenar campos individuales.
Aprende más sobre Physics.reuseCollisionCallbacks.

Los colliders estáticos son GameObjects con un componente Collider pero sin un Rigidbody.
Ten en cuenta que puedes mover un collider estático, a pesar del término “estático.” Para hacerlo, simplemente modifica la posición del cuerpo físico. Acumula los cambios de posición y sincroniza antes de la actualización de física. No necesitas agregar un componente Rigidbody al collider estático solo para moverlo.
Sin embargo, si deseas que el collider estático interactúe con otros cuerpos físicos de una manera más compleja, dale un Rigidbody cinemático. Usa Rigidbody.position y Rigidbody.rotation para moverlo en lugar de acceder al componente Transform. Esto garantiza un comportamiento más predecible del motor de física.
Nota: Si un Collider Estático 2D necesita ser movido o reconfigurado en tiempo de ejecución, entonces añade un componente Rigidbody 2D y configúralo como tipo de cuerpo Estático, ya que es más rápido simular el Collider 2D cuando tiene su propio Rigidbody 2D. Si un grupo de Colliders 2D necesita ser movido o reconfigurado en tiempo de ejecución, es más rápido que todos sean hijos de un único Rigidbody 2D oculto que mover cada GameObject individualmente.
Obtén más información sobre Rigidbodies.
Para detectar y recoger colliders en proyectos 3D dentro de una cierta distancia y en una cierta dirección, utiliza raycasts y otras consultas de física como BoxCast. Ten en cuenta que
Las consultas de física que devuelven múltiples colliders como un array, como OverlapSphere o OverlapBox, necesitan asignar esos objetos en el montón administrado. Esto significa que el recolector de basura eventualmente necesita recoger los objetos asignados, lo que puede disminuir el rendimiento si sucede en el momento equivocado.
Para reducir este sobrecosto, utiliza las versiones NonAlloc de esas consultas. Por ejemplo, si estás utilizando OverlapSphere para recoger todos los colliders potenciales alrededor de un punto, utiliza OverlapSphereNonAlloc en su lugar.
Esto te permite pasar un array de colliders (el parámetro de resultados) para actuar como un búfer. El método NonAlloc funciona sin generar basura. De lo contrario, funciona como el método correspondiente que asigna.
Ten en cuenta que necesitas definir un búfer de resultados de tamaño suficiente al usar un método NonAlloc. El búfer no crece si se queda sin espacio.
Física 2D
Ten en cuenta que el consejo anterior no se aplica a las consultas de física 2D, porque en el sistema de física 2D de Unity, los métodos no tienen un sufijo "NonAlloc". En cambio, todos los métodos de física 2D, incluidos aquellos que devuelven múltiples resultados, proporcionan sobrecargas que aceptan arrays o listas. Por ejemplo, mientras que el sistema de física 3D tiene métodos como RaycastNonAlloc, el equivalente 2D simplemente utiliza una versión sobrecargada de Raycast que puede tomar un array o List como parámetro, como:
var results = new List();
int hitCount = Physics2D.Raycast(origen, dirección, contactFilter, resultados);
Al usar sobrecargas, puedes realizar consultas sin asignación en el sistema de física 2D sin necesidad de métodos especializados NonAlloc.
Aprende más en la documentación del método NonAlloc.
Puedes ejecutar consultas de raycast con Physics.Raycast. Sin embargo, si tienes un gran número de operaciones de raycast (por ejemplo, calcular la línea de visión para 10,000 agentes), esto puede llevar una cantidad significativa de tiempo de CPU.
Usa RaycastCommand para agrupar la consulta utilizando el sistema de trabajos de C#. Esto descarga el trabajo del hilo principal para que los raycasts puedan ocurrir de manera asíncrona y en paralelo.
Consulta un ejemplo en la documentación de RaycastCommands.
Usa la ventana de depuración de física (Ventana > Análisis > Depurador de Física) para ayudar a solucionar cualquier problema con los colliders o discrepancias. Esto muestra un indicador codificado por colores de los GameObjects que pueden colisionar entre sí.
Para más información, consulta la documentación del Depurador de Física.


Encuentra más prácticas recomendadas y consejos en el centro de prácticas recomendadas de Unity. Elige entre más de 30 guías, creadas por expertos de la industria y por ingenieros y artistas técnicos de Unity, que te ayudarán a desarrollar de manera eficiente con las herramientas y sistemas de Unity.