2010-08-09 6 views
10

Obtuve este método (dentro de Unity C# Script), pero no entiendo cómo funciona realmente la parte de "rendimiento".¿Cómo funciona esto con un "rendimiento" en detalle?

Sé por MSDN que la función devolverá un IEnumerator que podría iterar a través, pero este código espera 1,5 segundos y no se itera porque significaría que los objetos creados en el interior se crearon varias veces. ¿Hay alguien aquí que pueda explicarme cómo funciona este código?

IEnumerator DestroyShip() 
{ 
    // create new gameobject 
    Instantiate(ExplosionPrefab, transform.position, transform.rotation); 
    // make current gameobject invisible 
    gameObject.renderer.enabled = false; 
    // set new position for the current gameobject 
    transform.position = new Vector3(0f, transform.position.y, transform.position.z); 
    // wait for 1,5 seconds 
    yield return new WaitForSeconds(1.5f); 
    // make the current gameobject visible again 
    gameObject.renderer.enabled = true; 
} 
+0

El título de la pregunta podría ser más descriptivo. De alguna manera, Google aún recogió las palabras clave, sin embargo. – ftvs

Respuesta

21

el empadronador el compilador genera para usted está siendo iterado. Una vez.

El compilador generará una clase que implementa IEnumerator, que tiene una función MoveNext() y una propiedad Current. La clase tendrá todos los miembros necesarios para almacenar el estado de la función entre llamadas. Los detalles exactos se pueden considerar "Magia del compilador".

El objeto de esta clase generada será manejado y administrado por el Motor Unity3d. El motor Unity3d llamará a MoveNext() en cada corrutina activa una vez por cuadro (a menos que se indique lo contrario).

Esto permitió al programador Unity3d escribir scripts que se reproducen un cuadro a la vez. Una combinación de la magia del compilador de C# y la magia del motor de Unity3d da como resultado una secuencia de comandos muy poderosa pero fácil de usar.

Para responder a su pregunta: el código en su función se ejecutará una vez, pero se detendrá en la declaración 'yield return'.

Como se indicó anteriormente, el compilador de C# crea un objeto especial que implementa IEnumerator.

En la primera llamada a MoveNext(), su función crea una explosión y establece el objeto actual como "new WaitForSeconds (1.5f)".

El motor Unity3d inspecciona este objeto, ve que es una instancia de la clase especial "WaitForSeconds", por lo que pone el enumerador en una cola de espera y no solicitará el segundo elemento hasta que hayan transcurrido 1.5 segundos. Mientras tanto, se renderizarán muchos cuadros y se reproducirá la explosión.

Después de 1,5 segundos, Unity colocará el enumerador de la cola y llamará a MoveNext() nuevamente. La segunda parte de su función se ejecutará ahora, pero no generará un segundo objeto. MoveNext() devolverá false para indicar que no pudo obtener un nuevo elemento, que es la señal a Unity3d para descartar este enumerador. El recolector de basura recuperará la memoria en algún momento.

Como dije: está ocurriendo un montón de compiladores y magia Unity3d. Siempre que recuerde que su función se mantendrá en espera hasta el próximo cuadro en cada declaración de rendimiento, sabrá lo suficiente como para beneficiarse de esas funciones especiales.

+0

Escribir ese código en un proyecto de C# independiente, y mirar el ensamblado de .net generado en ILSPy es un rápido vistazo sobre cómo funciona toda la magia. –

5

Si yield se utiliza una vez, es como si se devuelve un IEnumerator con un elemento, por eso se tiene la impresión de que no iterar.

Es un uso bastante extraño de la palabra clave yield, es difícil entender por qué se implementó sin ver todo el contexto.

+1

Se llama en una función llamada "StartCoroutine": Unity.StartCoroutine (DestroyShip), creo que esto es muy específico de Unity Engine http://unity3d.com –

+0

Referencia: http://unity3d.com/support/documentation /ScriptReference/MonoBehaviour.StartCoroutine.html –

+1

Veo ... bueno, esto seguramente tiene sentido en el contexto del motor de Unity. –

1

Es mejor devolver IEnumerable en lugar de IEnumerator ya que es más flexible y fácil de usar. Incluso es mejor usar IEnumerable<T>. El rendimiento de retorno es solo azúcar sintáctica para implementar un bloque iterador, el compilador genera el código relevante ya que es esencialmente placa de caldera estándar que se puede generar fácilmente mediante programación. Por lo general, utiliza el retorno de rendimiento cuando se quiere hacer una serie de acciones individuales apear a ser una colección, por ejemplo .:

public IEnumerable<Thing> GetThings() 
{ 
    yield return GetNextThing(); 
} 
+1

Excepto que el motor Unity3d es el único que usa ese IEnumerator, y ese motor requiere que sea un IEnumerable. Se puede argumentar que IEnumrable es mejor, pero uno también tiene que jugar junto con las desiciones de diseño realizadas por Unity3d. – Sjoerd

Cuestiones relacionadas