Unity3D Game Engine'in 'getiri dönüşü www' deki temel mekanizma


14

Unity3D oyun motorunda, uzak verileri almak için ortak bir kod sırası şudur:

WWW www = new WWW("http://remote.com/data/location/with/texture.png");
yield return www;

Buradaki temel mekanizma nedir?

İndirme tamamlanırken bir sonraki karenin işlenmesine izin vermek için verim mekanizmasını kullandığımızı biliyorum. Ama biz davlumbazın altında neler oluyor yield return www?

Hangi yöntem deniyor (varsa, WWW sınıfında)? Unity iş parçacığı kullanıyor mu? "Üst" Birlik katmanı www örneğini alıyor mu ve bir şey yapıyor mu?

DÜZENLE:

  • Bu soru özellikle Unity3D iç bileşenleri hakkındadır. yieldC # ifadesinin nasıl çalıştığına dair açıklamalarla ilgilenmiyorum . Bunun yerine, Unity'nin bu yapılarla nasıl başa çıkacağına dair içsel bir görünüm arıyorum, örneğin WWW'ye bir parça veriyi birkaç kareye dağıtılmış bir şekilde indirmesine izin vermek için.

1
yield returnEşzamansız işlemler için kullanmanın bir saldırı olduğunu unutmayın. "Gerçek" bir C # programında bunun Taskiçin a kullanırsınız . Unity, muhtemelen kullanılmadığı için .Net 4.0'dan önce oluşturulduğu için bunları kullanmıyor Task.
BlueRaja - Danny Pflughoeft

Yanıtlar:


8

Bu C # verim anahtar kelime ile yapmıyor özel bir şey - eylem wwwÖzellikle bu anahtar kelime yalnızca döndüren bir yöntemle bir kullanılabilir nesne, onun içerdiği yöntem için oldukça getirme aracı özel bir şey. IEnumerable(Veya IEnumerator) ve kullanılır MoveNext çağrıldığında numaralandırıcı tarafından hangi nesnenin "döndürüleceğini" belirtmek için .

Derleyici, tüm yöntemi bir durum makinesi kullanarak IEnumerable(veya IEnumerator) uygulayan ayrı bir sınıfa dönüştürdüğü için çalışır - net sonuç, biri dönüş değeriyle numaralanana kadar yöntemin gövdesinin yürütülmemesidir. Bu herhangi bir tür ile çalışacak, kesinlikle özel bir şey yok WWW, daha ziyade özel içeren yöntem.

C # derleyicisinin ne tür bir kod oluşturduğuna dair daha fazla bilgi için C # verim anahtar kelimesinin perde arkasına bakın veya IL Spy gibi bir şey kullanarak kodu kendiniz deneyin ve inceleyin


Güncelleme: Açıklığa kavuşturmak için

  • Unity bir yield returnifade içeren bir couteini çağırdığında, olan tek şey bir numaralandırıcının döndürülmesidir - bu aşamada yöntem gövdesinin hiçbiri yürütülmez
  • Yöntem gövdesinin çalıştırılmasını sağlamak için Unity MoveNextdizideki ilk değeri almak için yineleyiciyi çağırmalıdır . Bu, yöntemin ilk yeild returnifadeye kadar çalışmasına neden olur; bu noktada, çağıranın devam ettiği nokta (ve muhtemelen Unity, çerçevenin geri kalanını oluşturmak için devam eder)
  • Anladığım kadarıyla Unity normalde daha MoveNextsonra her bir karede bir kez yineleyici üzerindeki yöntemi çağırmaya devam eder, bu da yöntemin yield returnsonuna veya bir yield breakifadeye ulaşana kadar yöntemin her karede bir sonraki ifadeye kadar tekrar yürütülmesine neden olur. dizinin sonu)

Sadece özel burada biraz (ve bir de çiftin arasında diğer durumlarda ) yerine sadece indirme tamamlandığında (yürütme devam etmek yöntemi neden olan) yineleyici ilerletir, Birlik bu özel yineleyici bir sonraki kareyi ilerlemek olmamasıdır. Her ne kadar bir yineleyici ilerlemesi gerektiğinde Unity'ye sinyal vermek için genel bir mekanizma içeren bir temel YieldInstruction sınıfı var gibi görünse de , WWWsınıf bu sınıftan miras almıyor gibi görünüyor, bu yüzden sadece özel bir durum olduğunu varsayabilirim. Unity motorunda bu sınıf.

Açık olmak gerekirse - yieldanahtar kelime WWWsınıfa özel bir şey yapmaz , bunun yerine Unity'nin bu davranışa neden olan döndürülen numaralandırma üyelerine verdiği özel işlemdir.


İkincisini güncelleyin:WWW Web sayfalarını eşzamansız olarak indirmek için kullanılan mekanizmaya gelince, muhtemelen dahili olarak eşzamansız IO kullanacak veya alternatif olarak (özel bir iş parçacığı oluşturarak veya bir iş parçacığı havuzu kullanarak) iş parçacığı kullanabilen HttpWebRequest.BeginGetResponse Yöntemi'ni kullanır .


5
Aslında, Birlik'te, bir WWWnesneye verildiği zaman özel bir şey olur , bkz . WWWReferans .
Eric

9

yieldesas olarak birlik içinde bir koroutin bağlamda kullanılıyor gibi görünmektedir. Coroutines ve neden C # 's kullanmak hakkında daha fazla bilgi için yieldbu blog makalesini öneririz: Unity3D coroutines ayrıntılı . Bu cevaptaki araştırmanın çoğu bu makaleden geliyor.

Birlikteki eşgüdümler, aşağıdakileri yapan görevleri kapsüllemek için kullanılır:

  1. Oluşturulacak bir çerçeveden daha uzun sürebilir (bu nedenle yavaşlamalara neden olabilir) ve
  2. Oyun döngüsünden ayrı olarak gerçekleştirilebilir (çünkü sonucun geçerli çerçeve için mevcut olması gerekmez).

Bu tür görevlere örnek olarak yol bulma (yeniden) hesaplamaları veya sorularınızda olduğu gibi bir web sitesinden veri alma verilebilir.

Alt sorularınızı cevaplamak için (biraz değiştirilmiş bir sırayla):

Hangi yöntem deniyor (varsa, WWW sınıfında)? "Üst" Birlik katmanı www örneğini alıyor mu ve bir şey yapıyor mu?

Birlik WWWsınıfı bir koroutinden elde edilmek üzere tasarlanmıştır. Yukarıda bağlantılı blog makalesi yorumlarına göre, s hakkında spekülatif kod bloğu ('"üst" katmanı) YieldInstructionaslında verilmiş s olup olmadığını kontrol eden bir anahtar içerir WWW. Bu kod daha sonra indirme işleminin WWWreferansında açıklandığı gibi koroutinin otomatik olarak bitmesini sağlar .

Unity iş parçacığı kullanıyor mu?

Bu durumda, "oyunun geri kalanını engellemeden" verileri indirmek için: evet, büyük olasılıkla. (Ve iş parçacığı, kesinlikle kanıtlandığı gibi, indirilen verileri açmak için kullanılır WWW.threadPriority.)


Güzel! Altdevblogaday.com/2011/07/07/unity3d-coroutines-in-detail/… yorumunu gördüm ve WWW'ye özel muamele edildiği anlaşılıyor. Bu yüzden, iş parçacıkları kullanmadan indirme işleminin birkaç karede yapılmasına izin vermek için bunun nasıl yapıldığını bilmek isterim?
thyandrecardoso

İyi bir nokta! Her şeyden önce o seviyede bir dizi iş parçacığı olması gerektiğini düşünüyorum, bunu yansıtmak için cevabımı düzenleyeceğim.
Eric

1
@ thyandrecardoso Sanırım HttpWebRequest.BeginGetResponse veya benzeri kullanıyor , ancak sizin için gerçekten önemliyse bunu onaylamak için montajı kodabilirsiniz .
Justin

Şimdilik, gerçekten sadece "en iyi açıklama" yı bekliyorum ... Unity dev ekibinden herhangi biri "doğru cevabı" 8 -) verdiyse harika olurdu ... nihayetinde, gerçek uygulama olmayacak burada verilenlerden çok uzakta ... Meclisin koda dönüştürülmesine ve tüm bunların kesin olarak bilinmesine gerek yok. Ama daha sonra deneyebilirim :)
thyandrecardoso

7

Ne yazık ki, WWW dahili kod olarak yerel kod olarak uygulanmaktadır, yani koda bakamayız. Deneylerden şunu söyleyebilirim ki

  1. WWWolduğu değil türetilmiş YieldInstruction, her ne nedenle sizi olur yieldözel durum kodu ile ele alınması gerekir.
  2. Arasında hiç fark görmedim

    yield return www;

    ve

    while(!www.isDone)
        yield return null;

    Bence bunu uygulamanın en mantıklı yolu ve büyük olasılıkla kaputun altında olan şey bu. Ama kesin olarak bilmiyorum.

  3. Birlik yok değil en azından bazı platformlarda (iOS WebPlayer) üzerine, indirme için yeni bir başlık açın. Ya da varsa WWW.isDone, ana iş parçacığına ayarlanır . Bu kod çünkü biliyorum:

    while(!www.isDone)
        Thread.Sleep(500);

    çalışmıyor.

Unity3d'nin kaynak koduna erişimi olan biri buraya gelmedikçe daha spesifik yanıtlara sahip olabileceğinizi sanmıyorum.


Evet. Gerçekten güzel bilgiler! Teşekkürler! Kendi başına bir iş parçacığı başlatmasa da, olabilecek en olası şey HttpWebRequest.BeginGetResponse (veya bunun gibi bir şey) kullanan WWW (veya motor katmanı) ... değil mi? Tamamen zaman uyumsuz bir şey her iki şekilde de gerçekleşmelidir ... indirme "duraklatılamaz".
thyandrecardoso

** Çerçeveler arasında "duraklatılamaz", yani.
thyandrecardoso

2

Unity3D, komut dosyası motoru olarak C # kullandığından, C # içine yerleştirilmiş standart verim anahtar kelimesini varsayalım . Temel olarak bunun anlamı, www değerini döndürmesidir, böylece bir sonraki yinelemede bir sonraki değeri döndürür, vs. ... Verim temelde arka planda bir durum makinesi ve yineleyici oluşturur.


Evet, verim anahtar kelimesiyle ilgili temel kavramlara sahip olduğumu düşünüyorum. Ancak, WWW'nin kurucusu sırasında bu “devlet makinesine” izin veren neler oluyor? Demek istediğim, "verim dönüşü www" WWW sınıfının içinde hiçbir şey çağırmıyor gibi ... "Bu zaten www değerini döndürüyor demektir" derken, www örnek değeri nedir? Bu örnek bir sonraki "yinelemede" ne yapacak?
thyandrecardoso

1
Birlik değiş tokuş eden kavramlar olarak, WWW veren özel bir durum, bunun için bakınız WWW'ın referans . Dahası, yieldhiçbir şey yarattığından emin değilim . Yineleyici bağlamı, IEnumerablebir dönüş türü olarak uygulanarak veya kullanılarak oluşturulur . "Devlet makinesi" de kapalı görünüyor. Tabii, devlet var, ama bu tek başına yeterli bir özellik değil, değil mi? Belki de bunun üzerinde durabilirsin.
Eric

1
İşte normal C # davranışı hakkında iyi bir referans. shadowcoding.blogspot.nl/2009/01/yield-and-c-state-machine.html . Verim, yineleyicide nerede olduğunu takip etmek için çok sayıda kod üretir. WWW'yi sağlayan Unity'nin özel vakası hakkında bilmiyordum ama belgelere göre normal C # anahtar kelimesi ile yapılacak bir şey yok, bu çok kafa karıştırıcı, sadece bir async yöntemi yapabilirlerdi.
Roy T.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.