Piensa en cómo foreachfunciona un :
foreach (var number in Enumerable.Range(1, 1000000))
{
if (number > 10) break;
}
El control sobre la iteración está en la persona que llama; si detiene la iteración (aquí con break), eso es todo.
La yieldpalabra clave es una forma simple de hacer un enumerable en C #. El nombre sugiere esto: yield returndevuelve el control a la persona que llama (en este caso, nuestra foreach); Es la persona que llama quien decide cuándo continuar con el siguiente elemento. Entonces puedes hacer un método como este:
IEnumerable<int> ToInfinity()
{
var i = 0;
while (true) yield return i++;
}
Parece ingenuo que se ejecutará para siempre; pero en realidad, depende completamente de la persona que llama. Puedes hacer algo como esto:
var range = ToInfinity().Take(10).ToArray();
Esto puede ser un poco confuso si no estás acostumbrado a este concepto, pero espero que también sea obvio que esta es una propiedad muy útil. Era la forma más sencilla en la que podía ceder el control a su interlocutor, y cuando la persona que llama decide hacer un seguimiento, solo puede hacer el siguiente paso (si Unity se creó hoy, probablemente lo usaría en awaitlugar de yield, pero awaitno existía) entonces).
Todo lo que necesita para implementar sus propias rutinas (no hace falta decir que las más simples y más estúpidas) es esto:
List<IEnumerable> continuations = new List<IEnumerable>();
void StartCoroutine(IEnumerable coroutine) => continuations.Add(coroutine);
void MainLoop()
{
while (GameIsRunning)
{
foreach (var continuation in continuations.ToArray())
{
if (!continuation.MoveNext()) continuations.Remove(continuation);
}
foreach (var gameObject in updateableGameObjects)
{
gameObject.Update();
}
}
}
Para agregar una WaitForSecondsimplementación muy simple , solo necesita algo como esto:
interface IDelayedCoroutine
{
bool ShouldMove();
}
class Waiter: IDelayedCoroutine
{
private readonly TimeSpan time;
private readonly DateTime start;
public Waiter(TimeSpan time)
{
this.start = DateTime.Now;
this.time = time;
}
public bool ShouldMove() => start + time > DateTime.Now;
}
Y el código correspondiente en nuestro bucle principal:
foreach (var continuation in continuations.ToArray())
{
if (continuation.Current is IDelayedCoroutine dc)
{
if (!dc.ShouldMove()) continue;
}
if (!continuation.MoveNext()) continuations.Remove(continuation);
}
Ta-da: eso es todo lo que necesita un sistema de rutina simple. Y al ceder el control a la persona que llama, la persona que llama puede decidir cualquier cantidad de cosas; podrían tener una tabla de eventos ordenada en lugar de iterar a través de todas las rutinas en cada cuadro; pueden tener prioridades o dependencias. Permite una implementación muy simple de la multitarea cooperativa. Y mira lo simple que es esto, gracias a yield:)
"Fire1", ¿es algo que puede configurar en el motor para permitir reasignaciones de teclas en lugar de escribirKeycode.Foo?