Jump to content

Search the Community

Showing results for tags 'scripting optimization'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • General
    • Proyectos
    • Offtopic
    • Unity Feeds
    • Website
    • Youtube
  • Mesa de ayuda
    • Unity
    • Arte
    • Builds & Dispositivos
    • Otras Especialidades
  • Aportes de la Comunidad
    • Recursos
    • Eventos
  • Bolsa de trabajo & Colaboraciones
    • Ofertas y Demandas
  • Post Antiguos
    • General (Antiguo)

Categories

  • Roadmap

Blogs

There are no results to display.

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Especialidad

Found 1 result

  1. Estoy leyendo el libro "Unity Game Optimization" que está en Packt y la tercera edición es de noviembre de 2019. He hecho un resumen de los apartados dedicados a scripting que me parecen muy buenos. Algunos los conoceréis, otros no y otros es posible que no supiérais porqué utilizar una manera u otra. En todos los casos el concepto de optimización ve sus frutos cuando es un desarrollo de cierto tamaño. Desde mi punto de vista, si empiezas con buenos hábitos, luego no tendrás los mismos problemas de rendimiento que el resto de desarrolladores. La optimización se debe realizar desde el día 1. Paso a relatar. Optimización 1 Eliminar las callbacks vacías de Start() y Update() al crear un script si no son necesarias. El tenerlas afectará a la inicialización de la scene y al instanciar prefabs. La de OnGUI() es especialmente problemática ya que puede llamarse más de una vez por frame. En la de Update() se realiza un Native-Managed Bridge, o sea, hay que enlazar el modo managed de C# con el del código nativo dependiente de plataforma. En general no dejar nunca una callback vacía. Optimización 2 Cómo obtener los componentes de un GameObject. Hay tres maneras de hacerlo, aunque a la práctica se utilizan dos de ellas. Los datos hablan por si mismos para 30.000 objetos. // 6413 ms test = (TestComponent)GetComponent("TestComponent"); // 89 ms test = GetComponent<TestComponent>(); // 95 ms test = (TestComponent)GetComponent(typeof(TestComponent)); El mejor es del uso del template o tipo genérico. Como en C++ ;) Optimización 3 Cachear los GetComponent, preferiblemente en el Awake. Esto es realmente crítico si se realiza en el Update. Al final obtendremos un mejor rendimiento a cambio de un coste de memoria mínimo (entre 32 ó 64 bytes por item dependiendo de la plataforma). Optimización 4 El uso de funciones dentro de Update. Si las acciones no requieren se llamadas en cada frame es mucho mejor convertirlo a un InvokeRepeating que puede llamarse en el Start y cancelarse en el OnDestroy: private void Start() { InvokeRepeating("ProcessAI", 0f, _aiProcessDelay); } Optimización 5 La comparación de objetos null. La llamada directa de "gameobject == null" genera una conversión Native-Managed Bridge con la consiguiente sobrecarga. Es mucho mejor utilizar el ReferenceEquals que no utiliza la conversión. Por eso se incluyó en Unity: if (!System.Object.ReferenceEquals(gameObject, null)) { // No es null } Optimización 6 La comprobación con Tag directa genera memoria adicional y hará actuar al GC posteriormente. Utilizar el CompareTag no utiliza memoria ya que evita el Native-Managed Bridge completamente y tarda la mitad de tiempo: // Asignación de memoria y GC. Tarda el doble de tiempo if (gameObject.tag == "Player") { // realizar acción } // Evita el Native-Managed Bridge totalmente. No asigna memoria adicional if (gameObject.CompareTag ("Player")) { // realizar acción } Optimización 7 Dictionary vs List. Las List son mejores para iteraciones. Los Dictionary son mejores para búsquedas aleatorias. El Dictionary es peor para las iteraciones debido a que debe realizar una comparación hash para cada uno de los elementos. De todos modos tener los dos tipos en algunas situaciones no es mala idea. Optimización 8 La Transform. Cuando instanciamos un nuevo GameObject con GameObject.Instantiate(), uno de sus argumentos es el componente de la Transform del parent que queremos asignar, que por defecto es null y colocará el GameObject en el root. Todas las Transforms que está a nivel root necesitar crear un buffer de memoria para poder almacenar los children que tienen más aquellos que vendrán después. Esto no ocurre con las Transforms que son child. Pero si una Transform en root le cambiamos el parent una vez creada y la reasignamos, se procederá a descartar el buffer de memoria que iniciamos en el Instantiate. Para evitar esto es mejor proveer del parent en la función. Otro apartado interesante es que, hay una propiedad en la Transform llamada hierarchyCapacity. Si somos capaces de estimar el número de Transform child de este objeto root, podremos reducir el número de asignaciones de memoria. Optimización 9 World Position, World Rotation, World Scale. Cuánto más profundo esté en la jerarquía un objeto mayores cálculos son necesarios para determinar el resultado final de su estado. Esto significa que es mucho más eficiente utilizar los elementos de Local que de World. Optimización 10 Cambios en la Transform. Si es posible, agrupar todos los cambios en una Transform y no realizarlos hasta el final de todos los cálculos y en FixedUpdate. Esto evitará movimientos extraños o teleportaciones de los objetos debido a que Unity lanza eventos internos cada vez que una Transform es modificada. private bool _positionChanged; private Vector3 _newPosition; public void SetPosition(Vector3 position) { _newPosition = position; _positionChanged = true; } private void FixedUpdate() { if (_positionChanged) { transform.position = _newPosition; _positionChanged = false; } } Optimización 11 SendMessage y Find. El método SendMessage() y la familia de métodos GameObject.Find() so especialmente costosos y deben evitarse en su totalidad. El método SendMessage() es como 2,000 veces más lento que una simple llamada a una función, y el coste de Find() se escala pobremente según la complejidad de la scene aumente ya que tiene que iterar por todos los GameObject de la misma. Optimización 12 No solamente Occlusion Culling/Frustum Culling. Para los objetos que solamente tienen renderizado es factible utilizarlas únicamente. Otros objetos que utilicen cálculos internos de manera constante continuarán consumiendo a pesar del Culling. Una buena solución a este problema es utilizar las callbacks OnBecameVisible() y OnBecameInvisible(). Como los nombres dicen, estas callbacks son invocadas cuando un objeto renderizado se ha vuelto visible a una cámara o invisible respecto a todas las cámaras de la scene. Además, cuando hay múltiples cámara en la scene (por ejemplo en un juego multiplayer) las callbacks son solamente invocadas cuando es visible para una cámara o invisible para todas ellas de igual modo. Esto significa que las callback serán llamadas en el momento preciso que se necesitan. Si nadie puede ver el objeto se llamará a OnBecameInvisible(), si como mínimo un player puede verlo se llamará a OnBecameVisible(). Optimización 13 Distance vs sqrMagnitude. El cálculo de raíces cuadradas para las CPU implica bastante proceso comparado con otras instrucciones. Cuando tengamos que utilizar un cálculo de distancia, y si no requerimos de una precisión extrema, es mejor utilizar sqrMagnitude y valor a comparar por su potencia de 2. // Utilizar la raíz cuadrada en Distance() float distance = (transform.position – other.transform.position).Distance(); if (distance < targetDistance) { // dentro de distancia } // No realiza el proceso anterior float distanceSqrd = (transform.position – other.transform.position).sqrMagnitude; if (distanceSqrd < (targetDistance * targetDistance)) { // dentro de distancia } Optimización 14 Datos de Prefab a un Scriptable Object. Si tenemos muchos diferentes tipos de Prefabs que contienen datos que pueden compartirse entre ellos, como fuerza, velocidad, puntos, etc. entonces todos estos datos serán serializados en cada Prefab que luego se instancie. Una mejor solución es serializar estos datos en un ScriptableObject. Esto reduce la cantidad de datos a serializar en el Prefab, el tiempo de deserialización y el tamaño del Prefab en sí mismo reduciendo el tiempo de acciones que serán repetitivas. Optimización 15 Update(). Una mejor solución al problema del Update() es no utilizar nunca, o mejor dicho, una sola vez. Cuando Unity llama al callback Update(), o cualquiera relacionado, cruza la ya comentada frontera del Native-Managed Bridge que es una tarea costosa en términos relativos. En otras palabras, el coste de procesamiento de 1.000 Update() independiente será mucho más costoso que la ejecución de un Update() con 1.000 funciones. Para poder minimizar este problema es mejor agrupar todos los Update() en un solo Update() global que luego llame a las diferentes funciones que requieran la acción.
UnitySpain © Todos los derechos reservados 2020
×
×
  • Create New...