Pikirkan cara foreach
kerjanya:
foreach (var number in Enumerable.Range(1, 1000000))
{
if (number > 10) break;
}
Kontrol atas iterasi ada pada penelepon - jika Anda menghentikan iterasi (di sini dengan break
), itu saja.
Kata yield
kunci adalah cara sederhana untuk membuat enumerable dalam C #. Nama mengisyaratkan hal ini - yield return
menghasilkan kontrol kembali ke penelepon (dalam hal ini, kami foreach
); peneleponlah yang memutuskan kapan untuk melanjutkan ke item berikutnya. Jadi Anda bisa membuat metode seperti ini:
IEnumerable<int> ToInfinity()
{
var i = 0;
while (true) yield return i++;
}
Ini secara naif sepertinya akan berjalan selamanya; tetapi pada kenyataannya, itu sepenuhnya tergantung pada penelepon. Anda dapat melakukan sesuatu seperti ini:
var range = ToInfinity().Take(10).ToArray();
Ini bisa sedikit membingungkan jika Anda tidak terbiasa dengan konsep ini, tapi saya harap itu juga jelas bahwa ini adalah properti yang sangat berguna. Itu adalah cara paling sederhana bahwa Anda dapat memberikan kendali kepada penelepon Anda, dan ketika penelepon memutuskan untuk menindaklanjuti, itu hanya dapat melakukan langkah berikutnya (jika Unity dibuat hari ini, itu mungkin akan menggunakan await
alih-alih yield
; tetapi await
tidak ada kembali kemudian).
Yang Anda butuhkan untuk mengimplementasikan coroutine Anda sendiri (tidak perlu dikatakan, coroutine paling bodoh yang paling sederhana) adalah ini:
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();
}
}
}
Untuk menambahkan WaitForSeconds
implementasi yang sangat sederhana , Anda hanya perlu sesuatu seperti ini:
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;
}
Dan kode yang sesuai di loop utama kami:
foreach (var continuation in continuations.ToArray())
{
if (continuation.Current is IDelayedCoroutine dc)
{
if (!dc.ShouldMove()) continue;
}
if (!continuation.MoveNext()) continuations.Remove(continuation);
}
Ta-da - itu saja kebutuhan sistem coroutine sederhana. Dan dengan memberikan kendali kepada penelepon, penelepon dapat memutuskan sejumlah hal; mereka mungkin memiliki tabel acara yang diurutkan daripada iterasi melalui semua coroutine pada setiap frame; mereka mungkin memiliki prioritas, atau ketergantungan. Hal ini memungkinkan untuk implementasi multi-tasking koperasi yang sangat sederhana. Dan lihat betapa sederhananya ini, terima kasih yield
:)
"Fire1"
, apakah itu sesuatu yang dapat Anda atur di mesin untuk memungkinkan remapping kunci daripada mengetikKeycode.Foo
?