Jump to content
Nico480

Cuando usar corutinas y como mejorar el script para un mejor rendimiento

Recommended Posts

Hola, quiero mejorar mi código, utilizo casi todo en la funcion update y voy llamando funciones desde ahi, como puedo mejorar mis codigos para que en un futuro no genere algun problema con el rendimiento, que funciones o variables no son recomendadas ejecutar frame por frame y me dan ejemplos de corutina? Es que no logro entender bien en que caso usarla

 

Gracias, saludos

Share this post


Link to post
Share on other sites

Hola @Nico480,

en cuestion de variables puedes utilizar tantas como quieras en la funcion Update, o en cualquier otra funcion, y no tendras problemas de rendimiento; tal vez si utilizaras 10.000 variables en una funcion lo notarias en el rendimiento, pero en ese caso los problemas de rendimiento seran el menor de tus preocupaciones ... porque lo que te traeria de cabeza seria aclararte con tal numero de variables xD (esta de mas decir que NUNCA utilizaras un numero tan alto de variables).

En cuestion de funciones debes evitar utilizar en Update todas aquellas que hagan un alto consumo de recursos siempre que te sea posible; uno de los casos mas tipicos es utilizar GetComponent dentro de Update, eso si te preocupas por el rendimiento te deberia hacer daño a la vista.

Edited by Arthure

Share this post


Link to post
Share on other sites

Como dice @Arthure, cosas como GetComponent o Find no se deben utilizar en el Update, generalmente solo se deberían utilizar en Awake, Start o OnEnable. Crear y destruir objetos también es costoso. Lo suyo es utilizar el profiler para ver que es lo que afecta más al rendimiento e intentarlo corregir.

Las corrutinas son útiles para cosas que no necesariamente se tienen que ejecutar a cada frame. Por ejemplo, elementos de una IA, como detectar enemigos se podrían ejecutar cada 0.5 segundos con lo que ahorrarías recursos (en vez de ejecutarse 60 veces por segundo, se ejecutarían 2). En las corutinas hay que tener una cosa clara, cada vez que inicias una corrutina se inicia una nueva, si antes has iniciado la misma corrutina habrán dos corrutinas corriendo a la vez. Además, las corrutinas siguen funcionando aunque se desactive el objeto. Yo las suelo utilizar de esta manera:

    Coroutine rutina; //Variable para poder desactivar la corrutina

    void OnEnable()
    {
        //Iniciamos Corutina en enable asignandola a su variable
        rutina = StartCoroutine(Corrutina());        
    }

    void OnDisable()
    {
        //Cuando desactivamos el objeto nos aseguramos que no se quede la corrutina funcionando
        if (rutina != null)
            StopCoroutine(rutina);
    }


    IEnumerator Corrutina()
    {
        //Entramos en un bucle infinito
        while (true)
        {
            //Hacemos lo que queramos.


            //Aturamos la corrutina durante medio segundo
            yield return new WaitForSeconds(0.5f);
            //También podemos pararla durante un frame usando:
            //yield return null;
        }

    }

 

Como ves, activo las rutinas en OnEnable, se podrían activar cuando quisieras pero tienes que asegurarte de que solo las activas una vez. En OnDisable la paro para asegurarme de que no sigue corriendo.

Espero que te sirva de ayuda.

Edited by TheBullet

Share this post


Link to post
Share on other sites

Para agregar aca tenes un articulo que hizo @Santi Andrade de optimizacion muy bueno que tiene un poco de todo:

https://histeriagamedev.wordpress.com/2017/06/16/optimizacion-en-unity/

11 hours ago, Nico480 said:

como puedo mejorar mis codigos para que en un futuro no genere algun problema con el rendimiento

Y.. esa pregunta no tiene una respuesta exacta, (pero hay trucos, que no son tan trucos sino mas bien sentido comun). Un ejemplo tipico que se ve mucho con el tema del UI es el de:

void Update(){
	uiText.text = "moneditas" + monedas.ToString();
}

Porque hacerlo cuadro a cuadro cuando lo podes hacer cada vez que agarras una moneda? ahi en donde los metodos publicos vienen muy a mano para avisar/ser avisado de que se debe realizar un cambio.

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Una muy importante es el Garbage Collector, generalmente hay que ahorrarle trabajo al pobre. Te recomiendo el siguiente articulo (ingles) te da ejemplos y todo y es de unity oficial. https://unity3d.com/es/learn/tutorials/topics/performance-optimization/optimizing-garbage-collection-unity-games:

Los problemas tipicos son: el tiempo en que corre el GC , la frecuencia con la que lo hace y la misma fragmentacion que provoca ya que la heap es una memoria mas (seguro escuchaste algo de los memory leaks, vienen de este tipo de memoria) y no se desfragmenta automaticamente, lo que te puede llevar a tener el espacio requerido pero en partes, y claro el bloque que queres asignar no encuentra lugar (entre comillas, seguro lo encuentra, pero estas desperdiciando espacio, como en un disco duro por ejemplo). Tene en cuenta que si estas reutilizando referencias no hay problema, el problema va en si las creas y te olvidas de usarlas por el motivo que sea y si le sumas que lo haces en un Update peor. Lo mejor es tener un script provocar errores aproposito y ver el profiler, sobre todo la columna que dice GC.

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

El resto de los problemas de performance los tenes que asociar a como lo harias en la realidad, manejarte por eventos o por flags, cuando se esta en cierta situacion realizar una accion. Se supone mas demandante a solo revisar una bool o una entrada, incluso podes revisar todo es no cuadro a cuadro sino cada dos cuadros cada 4, sobre todo si es IA, aunque si debes revisar dos flags no sirve de mucho. Un caso tipico seria ocurre un evento de entrada (teclado, mouse, etc) ahi realizar la accion o condicion ej:

CASO1:

//Es probable : op logica (3 argumentos) + comparacion y salto

if(entrada && condicion 1 && condicion 2)	//comparacion y op logica entre los tres argumentos, realizar o no salto
{			
	//Hacer algo		
	
}

CASO2:

//Es probable : op logica (2 argumentos) + comparacion (salto o no) + comparacion y salto

if(condicion 1 && condicion 2)	//comparacion y op logica entre los dos argumentos, realizar o no salto
{
	if(entrada)		//comparacion de "entrada", realizar o no salto
	{		
		//Hacer algo		
	}
}

CASO3: 

//Es probable : comparacion y salto

if(entrada 1)	//comparacion de "entrada", realizar o no salto 
{
	if(condicion 1 && condicion 2)
	{		
		//Hacer algo		
	}
}

 

Otro es usar el Input manager cuando te convenga usarlo (generalemten en movimiento es muy util)i:

// -----------------------------------------------------------------------------------------------
// funcion(Input) + comapracion + instruccion(mover)

if(input --> W)
{
	mover hacia vector forward;
}else if(input --> S)
{
	mover hacia vector -forward;
}

// -----------------------------------------------------------------------------------------------
//Cuando podes hacer usar las Inputs ya definidas Y QUE ESTAN FUNCIONANDO LO QUIERAS O NO:
//

mover hacia vector (forward * axis("Vertical")) // 1 instruccion

 

Share this post


Link to post
Share on other sites

Otras optimizaciones:

Entre menos declaraciones de Update() tengas mas rapido ira el juego.

En corrutinas usas yield return null para espera 1 cuadro (siguiente update), yield break para salir de la corrutina.

Si vas a esperar siempre la misma cantidad de tiempo guardalo en una variable global, por ejemplo Espera = new WaitForSeconds(1f); y luego llamas desde la corutina yield return Espera; Asi no creas ese objeto en cada llamada.

Share this post


Link to post
Share on other sites

UnitySpain © Todos los derechos reservados 2020
×
×
  • Create New...