Saya baru mengenal Unity. Saya belajar coroutine dan saya menulis ini.
private void Fire()
{
if(Input.GetButtonDown("Fire1"))
{
StartCoroutine(FireContinuously());
}
if(Input.GetButtonUp("Fire1"))
{
StopAllCoroutines();
}
}
IEnumerator FireContinuously()
{
while(true)
{
GameObject laser = Instantiate(LaserPrefab, transform.position, Quaternion.identity) as GameObject;
laser.GetComponent<Rigidbody2D>().velocity = new Vector2(0, 10f);
yield return new WaitForSeconds(firetime);
}
}
Ketika tombol ditekan coroutine dipanggil dan memasuki loop 'while'. Ketika saya meninggalkan tombol itu menghentikan coroutine. Tidakkah seharusnya macet di loop 'while' karena itu adalah loop tak terbatas? Mengapa?
unity
c#
coroutines
otak bayi
sumber
sumber
"Fire1"
, apakah itu sesuatu yang dapat Anda atur di mesin untuk memungkinkan remapping kunci daripada mengetikKeycode.Foo
?yield
adalah kependekan dari "Kontrol hasil kepada penelepon sampai item berikutnya dalam Enumerable diminta."StopAllCoroutines()
dalam hal ini. Tidak apa-apa ketika Anda hanya menggunakan satu coroutine, tetapi jika Anda pernah berencana untuk memiliki lebih dari satu, ini akan memiliki efek yang tidak diinginkan. Alih-alih, Anda harus menggunakanStopCoroutine()
dan menghentikan saja yang relevan alih-alih semuanya. (StopAllCoroutines()
akan berguna misalnya ketika mengakhiri level atau memuat area baru, dll., tetapi tidak untuk hal-hal spesifik seperti "Saya tidak lagi menembak".)Jawaban:
Alasannya adalah kata kunci
yield
yang memiliki makna khusus dalam C #.Saat menemukan kata-kata
yield return
fungsi dalam C # kembali, seperti yang diharapkan.Jadi tidak ada loop tanpa batas. Ada fungsi / iterator yang bisa disebut tak terhingga kali.
Fungsi Unity
StartCoroutine()
membuat kerangka Unity memanggil fungsi / iterator sekali per frame.Fungsi Unity
StopAllCoroutines
membuat kerangka Unity berhenti memanggil fungsi / iterator.Dan kembali
WaitForSeconds(time)
dari iterator membuat kerangka Unity menunda memanggil fungsi / iteratortime
.Komentar yang membingungkan dan suara yang sama-sama membingungkan pada komentar itu mendorong saya untuk menguraikan lebih lanjut tentang apa yang
yield
dilakukan dan tidak dilakukan kata kunci .Jika Anda menulis ini:
Anda bisa juga menulis ini:
Oleh karena itu kata kunci
yield
tidak terkait dengan multi-threading dan sama sekali tidak meneleponSystem.Threading.Thread.Yield()
.sumber
On encountering the words yield return a function in C# returns
". Tidak. Teks yang Anda kutip menjelaskannya, seperti halnya Wikipedia - "In computer science, yield is an action that occurs in a computer program during multithreading, of forcing a processor to relinquish control of the current running thread, and sending it to the end of the running queue, of the same scheduling priority.
". Pada dasarnya, "` tolong hentikan saya di mana saya berada dan biarkan orang lain lari sebentar ".Ketika tombol api diangkat, pernyataan kedua dimasukkan, dan StopAllCoroutines dijalankan. Ini berarti bahwa Coroutine yang menjalankan loop sementara berakhir, sehingga tidak ada lagi loop tak terbatas. Coroutine seperti wadah untuk mengeksekusi kode.
Saya dapat merekomendasikan Unity Manual dan Unity Scripting API untuk lebih memahami apa itu coroutine dan seberapa kuat mereka.
Blog ini dan mencari posting youtube juga membantu saya menggunakan coroutine dengan lebih baik.
sumber
Coroutine adalah binatang aneh. Imbal hasil menyebabkan metode untuk menunda eksekusi sampai nanti melangkah. Di belakang layar, mungkin terlihat seperti ini:
Dan internal ke Unity / C # (karena hasil pengembalian adalah fitur c # asli), ketika Anda memanggil StartCoroutine, itu menciptakan
FireContinuouslyData
objek, dan meneruskannya ke metode. Berdasarkan nilai kembali, ia menentukan kapan harus memanggilnya lagi nanti, cukup menyimpan objek FireContinuouslyData untuk meneruskannya di waktu berikutnya.Jika Anda pernah melakukan penghentian panen, secara internal bisa saja diatur
data.shouldBreak = true
dan kemudian Unity hanya akan membuang data dan tidak menjadwalkannya lagi.Dan jika ada data yang perlu disimpan di antara eksekusi, itu juga akan disimpan dalam data untuk nanti.
Contoh bagaimana Unity / C # dapat mengimplementasikan fungsionalitas coroutine:
sumber
Jawaban lain menyebutkan bahwa Anda menghentikan co-rutin ketika
"Fire1"
sudah habis - ini benar, sejauh mengapa coroutine tidak melanjutkan instantiating GameObjects setelah tekan pertama dari"Fire1"
.Namun dalam kasus Anda, kode ini tidak akan menjadi 'macet' dalam loop tak terbatas, yang sepertinya Anda cari jawabannya - yaitu
while(true) {}
loop, bahkan jika Anda tidak menghentikannya secara eksternal.Itu tidak akan macet tetapi coroutine Anda tidak akan berakhir (tanpa menelepon
StopCoroutine()
atauStopAllCoroutines()
). Ini karena Unity coroutine memberikan kendali kepada penelepon mereka.yield
berbeda denganreturning
:return
pernyataan akan menghentikan eksekusi suatu fungsi, bahkan jika ada lebih banyak kode yang mengikutinyayield
pernyataan akan menjeda fungsi, mulai dari baris berikutnya setelahyield
ketika dilanjutkan.Biasanya, coroutine akan dilanjutkan setiap frame tetapi Anda juga mengembalikan
WaitForSeconds
objek.Baris tersebut secara
yield return new WaitForSeconds(fireTime)
kasar diterjemahkan sebagai "sekarang tunda saya, dan jangan kembali sampaifireTime
detik berlalu".Kecuali berhenti, ini adalah coroutine yang, setelah dimulai, akan melakukan seluruh loop sekali setiap
fireTime
detik.sumber
Penjelasan sederhana: di bawah tenda Unity mengulangi koleksi (dari YieldInstruction s atau nulls atau apa pun yang Anda
yield return
) menggunakanIEnumerator
fungsi yang dikembalikan oleh fungsi Anda.Karena Anda menggunakan
yield
kata kunci, metode Anda adalah iterator . Ini bukan hal Unity, ini fitur bahasa C #. Bagaimana cara kerjanya?Itu malas dan tidak menghasilkan semua koleksi sekaligus (dan koleksi mungkin tak terbatas dan tidak mungkin dihasilkan sekaligus). Elemen-elemen koleksi dihasilkan sesuai kebutuhan. Fungsi Anda mengembalikan iterator untuk digunakan Unity. Ia memanggil
MoveNext
metodenya untuk menghasilkan elemen danCurrent
properti baru untuk mengaksesnya.Jadi loop Anda tidak terbatas, ia menjalankan beberapa kode, mengembalikan elemen dan mengembalikan kontrol ke Unity sehingga tidak macet dan dapat melakukan pekerjaan lain seperti menangani input Anda untuk menghentikan coroutine.
sumber
Pikirkan cara
foreach
kerjanya: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, kamiforeach
); peneleponlah yang memutuskan kapan untuk melanjutkan ke item berikutnya. Jadi Anda bisa membuat metode seperti ini:Ini secara naif sepertinya akan berjalan selamanya; tetapi pada kenyataannya, itu sepenuhnya tergantung pada penelepon. Anda dapat melakukan sesuatu seperti ini:
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-alihyield
; tetapiawait
tidak ada kembali kemudian).Yang Anda butuhkan untuk mengimplementasikan coroutine Anda sendiri (tidak perlu dikatakan, coroutine paling bodoh yang paling sederhana) adalah ini:
Untuk menambahkan
WaitForSeconds
implementasi yang sangat sederhana , Anda hanya perlu sesuatu seperti ini:Dan kode yang sesuai di loop utama kami:
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
:)sumber