Saya mengerti prinsip coroutine. Saya tahu bagaimana cara mendapatkan standar StartCoroutine
/ yield return
pola untuk bekerja di C # di Unity, misalnya memanggil metode yang kembali IEnumerator
melalui StartCoroutine
dan dalam metode itu melakukan sesuatu, lakukan yield return new WaitForSeconds(1);
untuk menunggu sebentar, kemudian lakukan sesuatu yang lain.
Pertanyaan saya adalah: apa yang sebenarnya terjadi di balik layar? Apa yang StartCoroutine
sebenarnya dilakukan? Apa IEnumerator
yang WaitForSeconds
kembali? Bagaimana StartCoroutine
mengembalikan kontrol ke bagian "sesuatu yang lain" dari metode yang dipanggil? Bagaimana semua ini berinteraksi dengan model konkurensi Unity (di mana banyak hal terjadi pada saat yang sama tanpa menggunakan coroutine)?
IEnumerator
/IEnumerable
(atau setara dengan generik) dan yang mengandungyield
kata kunci. Cari iterator.Jawaban:
Coroutine Unity3D yang sering dirujuk dalam tautan detail sudah mati. Karena itu disebutkan dalam komentar dan jawaban saya akan memposting konten artikel di sini. Konten ini berasal dari cermin ini .
sumber
Judul pertama di bawah ini adalah jawaban langsung untuk pertanyaan itu. Dua judul setelah itu lebih bermanfaat bagi programmer sehari-hari.
Kemungkinan Detail Implementasi Coroutine yang Membosankan
Coroutine dijelaskan di Wikipedia dan di tempat lain. Di sini saya hanya akan memberikan beberapa detail dari sudut pandang praktis.
IEnumerator
,,yield
dll. adalah fitur bahasa C # yang digunakan untuk tujuan berbeda di Unity.Sederhananya,
IEnumerator
klaim memiliki koleksi nilai yang dapat Anda minta satu per satu, seperti jenis aList
. Di C #, fungsi dengan tanda tangan untuk mengembalikanIEnumerator
tidak harus benar-benar membuat dan mengembalikannya, tetapi dapat membiarkan C # memberikan implisitIEnumerator
. Fungsi kemudian dapat menyediakan konten yang dikembalikanIEnumerator
di masa depan dengan cara yang malas, melaluiyield return
pernyataan. Setiap kali pemanggil meminta nilai lain dari implisit ituIEnumerator
, fungsi dieksekusi sampaiyield return
pernyataan berikutnya , yang memberikan nilai berikutnya. Sebagai produk sampingan dari ini, fungsi berhenti sampai nilai berikutnya diminta.Di Unity, kami tidak menggunakan ini untuk memberikan nilai di masa depan, kami mengeksploitasi fakta bahwa fungsi berhenti. Karena eksploitasi ini, banyak hal tentang coroutine di Unity tidak masuk akal (Apa yang
IEnumerator
harus dilakukan dengan apa pun? Apa ituyield
? Mengapanew WaitForSeconds(3)
? Dll.). Apa yang terjadi "di bawah tenda" adalah, nilai yang Anda berikan melalui IEnumerator digunakan olehStartCoroutine()
untuk memutuskan kapan harus meminta nilai berikutnya, yang menentukan kapan coroutine Anda akan dihentikan lagi.Game Unity Anda adalah Single Threaded (*)
Coroutine bukan utas. Ada satu loop utama Unity dan semua fungsi yang Anda tulis dipanggil oleh utas utama yang sama secara berurutan. Anda dapat memverifikasi ini dengan menempatkan
while(true);
di salah satu fungsi atau coroutine Anda. Ini akan membekukan semuanya, bahkan editor Unity. Ini adalah bukti bahwa semuanya berjalan dalam satu utas utama. Tautan yang disebutkan Kay dalam komentarnya di atas juga merupakan sumber yang bagus.(*) Unity memanggil fungsi Anda dari satu utas. Jadi, kecuali Anda membuat utas sendiri, kode yang Anda tulis adalah utas tunggal. Tentu saja Unity menggunakan utas lainnya dan Anda dapat membuat utas sendiri jika Anda mau.
Deskripsi Praktis Coroutine untuk Pemrogram Game
Pada dasarnya, ketika Anda menelepon
StartCoroutine(MyCoroutine())
, itu persis seperti fungsi panggilan biasa untukMyCoroutine()
, sampai yang pertamayield return X
, di manaX
adalah sesuatu sepertinull
,new WaitForSeconds(3)
,StartCoroutine(AnotherCoroutine())
,break
, dll Ini adalah ketika mulai berbeda dari fungsi. Unity "jeda" yang berfungsi tepat diyield return X
garis itu, berjalan dengan bisnis lain dan beberapa frame berlalu, dan ketika saatnya tiba lagi, Unity melanjutkan fungsi itu tepat setelah garis itu. Itu mengingat nilai-nilai untuk semua variabel lokal dalam fungsi. Dengan cara ini, Anda dapat memilikifor
loop yang loop setiap dua detik, misalnya.Kapan Unity akan melanjutkan coroutine Anda tergantung pada apa yang
X
ada di Andayield return X
. Misalnya, jika Anda menggunakannyayield return new WaitForSeconds(3);
, akan dilanjutkan setelah 3 detik berlalu. Jika Anda menggunakannyayield return StartCoroutine(AnotherCoroutine())
, ia kembali setelahAnotherCoroutine()
sepenuhnya selesai, yang memungkinkan Anda untuk bersarang perilaku dalam waktu. Jika Anda baru saja menggunakanyield return null;
, itu dilanjutkan tepat di bingkai berikutnya.sumber
Itu tidak bisa lebih sederhana:
Unity (dan semua mesin gim) berbasis bingkai .
Seluruh pokok keseluruhan, raison d'etre dari Unity, adalah bahwa ia berbasis bingkai. Mesin melakukan "setiap frame" untuk Anda. (Animasi, merender objek, melakukan fisika, dan sebagainya.)
Anda mungkin bertanya .. "Oh, bagus sekali. Bagaimana jika saya ingin mesin melakukan sesuatu untuk saya setiap frame? Bagaimana saya memberi tahu mesin untuk melakukan ini-dan-itu dalam bingkai?"
Jawabannya adalah ...
Itulah tepatnya apa yang dimaksud dengan "coroutine".
Sederhana saja.
Dan pertimbangkan ini ....
Anda tahu fungsi "Pembaruan". Cukup sederhana, apa pun yang Anda menempatkan di sana dilakukan setiap frame . Secara harfiah persis sama, tidak ada perbedaan sama sekali, dari sintaksis coroutine-yield.
Sama sekali tidak ada perbedaan.
Catatan Kaki: seperti yang ditunjukkan semua orang, Persatuan tidak memiliki utas . "Frame" di Unity atau di mesin permainan apa pun sama sekali tidak memiliki koneksi ke utas.
Coroutine / yield hanyalah cara Anda mengakses frame di Unity. Itu dia. (Dan memang, itu sama dengan fungsi Update () yang disediakan oleh Unity.) Hanya itu yang ada, sesederhana itu.
sumber
Update()
? Maksud saya setidaknya harus ada sedikit perbedaan antara kedua implementasi ini dan kasus penggunaannya yang cukup jelas.Belilah ini belakangan, tulis sebuah posting di sini - http://eppz.eu/blog/understanding-ienumerator-in-unity-3d/ - yang memberi penerangan pada bagian internal (dengan contoh kode padat),
IEnumerator
antarmuka yang mendasarinya , dan bagaimana ini digunakan untuk coroutine.sumber
Fungsi dasar di Unity yang Anda dapatkan secara otomatis adalah fungsi Mulai () dan fungsi Pembaruan (), jadi fungsi Coroutine pada dasarnya sama seperti fungsi Mulai () dan Pembaruan (). Setiap fungsi fungsi lama () dapat dipanggil dengan cara yang sama seperti Coroutine dapat dipanggil. Unity jelas telah menetapkan batas-batas tertentu untuk Coroutine yang membuatnya berbeda dari fungsi biasa. Salah satu perbedaannya adalah bukan
Anda menulis
untuk coroutine. Dan dengan cara yang sama Anda dapat mengontrol waktu dalam fungsi normal dengan baris kode seperti
Coroutine memiliki pegangan khusus tentang cara waktu dapat dikendalikan.
Meskipun ini bukan satu-satunya hal yang dapat dilakukan di dalam IEnumerator / Coroutine, ini adalah salah satu hal berguna yang digunakan Coroutine. Anda harus meneliti API skrip Unity untuk mempelajari penggunaan khusus Coroutine lainnya.
sumber
StartCoroutine adalah metode untuk memanggil fungsi IEnumerator. Ini mirip dengan hanya memanggil fungsi void sederhana, bedanya adalah Anda menggunakannya pada fungsi IEnumerator. Jenis fungsi ini unik karena dapat memungkinkan Anda untuk menggunakan fungsi hasil khusus , perhatikan bahwa Anda harus mengembalikan sesuatu. Itu yang saya tahu. Di sini saya menulis permainan flicker sederhana Atas metode teks dalam kesatuan
Saya kemudian menyebutnya keluar dari IEnumerator itu sendiri
Seperti yang Anda lihat bagaimana saya menggunakan metode StartCoroutine (). Semoga saya bisa membantu. Saya sendiri seorang pengemis, jadi jika Anda mengoreksi saya, atau menghargai saya, umpan balik jenis apa pun akan bagus.
sumber