Oyunların geliştirilmesinde globallerin / singletonların yararlı olduğu durumlar var mı? [kapalı]


11

Global değişkenlere veya singleton sınıflarına sahip olmanın, test edilmesi / yönetilmesi zor olabilecek durumlar yarattığını biliyorum ve bu kalıpları kodda kullanmaktan sıkıldım, ancak çoğu zaman gemi göndermelisiniz.

Peki küresel değişkenlerin veya singletonların oyun geliştirmede gerçekten yararlı olduğu durumlar var mı?

Yanıtlar:


30

Bunlar her zaman yararlı olabilir . Bu en güzel ya da en güvenli çözüm olsun ya da olmasın başka bir konudur, ancak oyun geliştirme bir dereceye kadar pragmatizm içerir.


Mantrama çok yakın.
furlafur Waage

15

Kesinlikle kapsamlı olmayan bir liste, ama işte gidiyor:

Eksileri

  • Ömür boyu yönetim . Tektonlar ve globaller, nasıl kurduğunuza bağlı olarak, anahtar sistemler (örn. Yığın) başlatılmadan önce başlamak isteyebilir. Bunları yıkmak istiyorsanız (örneğin, kaçak takibi yapıyorsanız faydalıdır), söküm sırasına dikkat etmeli veya anka tekilleri gibi şeylere girmeye başlamalısınız . (Bkz. Statik başlatma sırası fiyasko .)
  • Erişim kontrolü . Güncelleme sabit değilken, oluşturma işleminin oyun verilerine yalnızca const erişimi olmalı mı? Bu, singletonlar ve globaller ile uygulanması zor olabilir.
  • Eyalet . Kaj'ın işaret ettiği gibi, paylaşılmayan bir bellek mimarisinde çalışmak için tektonları işlevsel olarak ayrıştırmak ve dönüştürmek daha zordur. Ayrıca diğer NUMA sistemleri (yerel olmayan belleğe erişim) için potansiyel performans etkileri vardır . Tektonlar genellikle merkezi durumu temsil eder ve bu nedenle saflıkla daha kolay hale getirilen dönüşümlerin antitezidir.

Pro ya da con

  • Eşzamanlılık . Eşzamanlı bir ortamda, singletonlar bir ağrı (veri yarışı / yeniden ortaya çıkma sorunlarını düşünmelisiniz) veya bir nimet (merkezileştirmek daha kolaydır ve kilitleme ve kaynak yönetimi hakkında neden olabilir). Yerel iş parçacığı depolama gibi şeylerin akıllıca kullanılması potansiyel sorunları bir miktar azaltabilir, ancak genellikle kolay bir sorun değildir.
  • Codegen (derleyiciye, mimariye vb. Bağlı olarak): Naif bir ilk kullanımda oluştur tekil uygulama için, her erişim için ek bir koşullu şube değerlendiriyor olabilirsiniz. (Bu eklenebilir.) Bir işlevde kullanılan birden çok genel bilgi değişmez havuzu şişirebilir . "Tüm globallerin yapısı" yaklaşımı değişmez havuzda yerden tasarruf sağlayabilir: Yapının tabanına yalnızca bir giriş ve daha sonra yükleme yönergelerinde kodlanan ofsetler. Son olarak, ne pahasına olursa olsun globallerden ve singletonlardan kaçınıyorsanız, genellikle işaretçileri, referansları ve hatta kopyaları aktarmak için en az biraz fazladan bellek (kayıt, yığın veya yığın) kullanmanız gerekir.

Artıları

  • Sadelik . Yukarıda listelenen eksilerin sizi etkilemediğini biliyorsanız (örneğin, tek bir CPU taşınabilir platform için tek iş parçacıklı bir ortamda çalışıyorsunuz), bazı mimarilerden (yukarıda belirtilen argüman geçişi gibi) kaçınabilirsiniz. Daha az deneyimli kodlayıcılar için singletonlar ve globaller anlaşılması daha kolay olabilir (ancak bunların yanlış kullanılması daha kolay olabilir).
  • Ömür boyu yönetim (tekrar). Bir "global yapı" veya ilk istek üzerine oluşturma dışında bir mekanizma kullanırsanız, başlatma ve imha etme sırası üzerinde kolay okunabilir ve ayrıntılı bir kontrole sahip olabilirsiniz. Bunu bir dereceye kadar otomatikleştiriyorsunuz veya manuel olarak yönetiyorsunuz (yönetmek zorunda olmak, global / singleton sayısına ve bunların bağımlılıklarına bağlı olarak bir pro veya con olabilir).

El bilgisayarlarında "küresel tektonların yapısı" kullanıyoruz. PC ve konsol başlıkları bunlara daha az güvenme eğilimindedir; etkinlik odaklı / mesajlaşma mimarisine daha fazla geçiş yapacağız. Bununla birlikte, pc / konsol başlıkları hala merkezi bir TextureManager kullanır; genellikle tek bir paylaşılan kaynağı (doku hafızasını) sardığından bu bizim için mantıklıdır.

API'nizi nispeten temiz tutarsanız, ihtiyacınız olduğunda tek bir modelden (veya içine!) Yeniden düzenleme yapmak çok zor olmayabilir ...


Harika bir liste. Şahsen ben paylaşılan (muhtemelen değişebilir) durumdan kaynaklanan sorunlar nedeniyle tekil ve küresellerde sadece negatif değer buluyorum. Gerçi bir sorun olarak "codegen" sorunu bulamıyorum; ya yazmaçları işaretçiler geçmek ya da bunu elde etmek için bazı işlemler dizisi yapmak gerekir, bence kodu veri boyutu vs gözle görülür değiştirir, ancak toplamı yaklaşık aynı olacaktır.
dash-tom-bang

Evet, kodgen, aslında önemli bir fark yaratabildiğimiz tek şey, bireysel küresellerden küreselleşmeye doğru gidiyordu: değişmez havuzları ve dolayısıyla .text bölüm boyutunu yüzde birkaç küçülttü. Bu küçük sistemlerde çok güzel bir şey. =) Değişmezler için dcache'ye çok fazla vurmamanın performans faydaları sadece güzel (çoğu durumda küçük de olsa) bir yan faydaydı. Küresel bir masaya geçmenin bir diğer avantajı, onu daha hızlı bellekte bulunan bir bölüme gerçekten kolayca taşıma yeteneğiydi ...
leander

4

Özellikle prototip oluşturma veya deneysel uygulama sırasında çok yararlı olabilirler, ancak genel olarak, yapılar gibi yönetici için referansları iletmeyi tercih ederiz, bu şekilde en azından nereden erişildikleri üzerinde kontrol sahibi olursunuz. Globaller ve singletonlarla ilgili en büyük sorun (benim görüşüme göre) çok multithread dostu olmamaları ve bunları kullanan kodun SPU'lar gibi paylaşılmayan belleğe taşınması çok daha zor olmasıdır.


2

Singleton tasarımının kendisinin hiç kullanışlı olmadığını söyleyebilirim. Global değişkenler kesinlikle yararlı olabilir, ancak onların varlığının farkında olmamanız için onları iyi yazılmış bir arayüzün arkasında gizli görmeyi tercih ederim. Singletons ile onların varlığının kesinlikle farkındasınız.

Genelde değişkenleri bir motor üzerinden erişilmesi gereken şeyler için kullanıyorum. Performans aracım, aramak için motorun her yerinde kullandığım iyi bir örnektir. Aramalar basit; ProbeRegister (), ProbeHit () ve ProbeScoped (). Gerçek erişimleri biraz daha zor ve bazı şeyler için küresel değişkenler kullanıyor.


2

Küreseller ve kötü uygulanmış tektonlarla ilgili temel sorun, belirsiz inşaat ve yapıbozum hatalarıdır.

Dolayısıyla, bu sorunları olmayan veya bir işaretçi ile sorunun çok farkında olan ilkellerle çalışıyorsanız. Sonra güvenle kullanılabilirler.

Globaller gotolarla aynı yerdedir ve elden çıkarılmamalı, bunun yerine özenle kullanılmalıdır.

Google C ++ Stil Kılavuzu'nda bunun iyi bir açıklaması var


Bunun ana sorun olduğuna katılmıyorum; "küreselleri kullanma" varoluş kurucularından daha ileri gider. Onlarla ilgili iki büyük sorun olduğunu söyleyebilirim. İlk olarak, bir program hakkındaki akıl yürütmeyi zorlaştırırlar. Bir genel erişen bir işlev varsa, bu işlevin davranışı sadece kendi bağımsız değişkenlerine değil, aynı zamanda genel erişen diğer tüm işlevlere bağlıdır. Düşünmek için çok daha fazlası var. İkincisi, hepsini kafanızda tutabilseniz bile (yapamazsınız), yine de daha karmaşık eşzamanlılık sorunlarına neden olurlar.

@Joe anahtar kelime "bağımlılıklar" dır. Globallere (veya singletonlara veya herhangi bir paylaşılan duruma) erişen bir işlev, tüm bu şeylere dolaylı bağımlılıklar gösterir. Tüm bağımlılıkları açıksa, bir bağımlılık listesinin tamamı bağımsız değişken listesinde belgelendiğinde elde ettiğiniz şey, kodun bir kısmının gerekçelendirilmesi çok daha kolaydır.
dash-tom-bang

1

Globaller, işlev çağrıları arasında bir durum gerektiren bir sistemi hızlı bir şekilde prototiplerken yararlıdır. Sistemin çalıştığını belirledikten sonra, durumu bir sınıfa taşıyın ve işlevleri o sınıfın yöntemlerine dönüştürün.

Teklitonlar kendinize ve başkalarına sorun çıkarmak için kullanışlıdır. Ne kadar çok küresel durum ortaya koyarsanız, kod doğruluğu, bakım, genişletilebilirlik, eşzamanlılık vb. İle ilgili daha fazla sorun yaşarsınız.


1

Singletons yerine özel ömür boyu yönetim ile bir tür DI / IoC konteyneri kullanmanızı öneriyorum ("tek örnek" yaşam boyu yöneticisi kullansanız bile). En azından, testi kolaylaştırmak için uygulamayı değiştirmek kolaydır.


Bilmeyenler için DI "Bağımlılık Enjeksiyonu" ve IoC "Kontrolün Tersine Çevirilmesi" dir. Link: martinfowler.com/articles/injection.html (Bunları daha önce okumuştum ama kısaltmayı hiç görmedim, bu yüzden biraz arama yaptım.) +1, bu mükemmel dönüşümden bahsettiğim için.
leander


0

Singletons, paylaşılan bir durumu erken bir prototipte saklamanın harika bir yoludur.

Gümüş bir kurşun değildir ve bazı problemlerle birlikte gelirler, ancak belirli UI / Mantık durumları için çok yararlı bir modeldir.

Örneğin iOS'ta, [UIApplication sharedApplication] almak için teklitonlar kullanırsınız, cocos2d'de [CCNotifications sharedManager] gibi belirli nesnelere referans almak için kullanabilirsiniz ve kişisel olarak genellikle bir [Game sharedGame] singletonu ile başlayabilirim. birçok farklı bileşen arasında paylaşılan mağaza durumu.


0

Vay be, bu benim için ilginç, çünkü kişisel olarak tek başına bir problemle karşılaşmadım. Şu anki projem Nintendo DS için bir C ++ oyun motorudur ve global C'yi sarmayı amaçladıkları için birçok donanım erişim yardımcı programını (VRAM Banks, Wifi, iki grafik motoru) tekli örnekler olarak kullanıyorum. temel kütüphanedeki fonksiyonlar.


O zaman sorum şu olurdu, neden hiç singleton kullanıyorsunuz? İnsanların API'leri yalnızca statik işlevlerden oluşan tekil veya sınıflarla sarmayı sevdiklerini görüyorum, ancak neden sınıfla hiç uğraşmıyorsunuz? Sadece fonksiyon çağrılarına sahip olmak benim için daha kolay görünüyor (istediğiniz gibi sarılmış), ama sonra dahili "küresel" duruma erişirler. Log :: GetInstance () -> LogError (...), istemci kodunun bilmesini gerektirmeden herhangi bir küresel duruma dahili olarak erişen LogError (...) da olabilir.
dash-tom-bang

0

Yalnızca tek bir denetleyicisi olan ancak birkaç modül tarafından işlenen bir öğeniz olduğunda.

Örneğin, fare arayüzü. Veya joystick arayüzü. Veya müzik çalar. Veya ses çalar. Veya ekran. Veya dosyaları kaydetme yöneticisi.


-1

Globaller çok daha hızlı! Bu yüzden oyun gibi performans yoğun bir uygulamaya mükemmel uyum sağlar.

Tekiltonlar daha iyi bir küresel, IMO ve dolayısıyla doğru araçtır.

Dikkatli kullanın!


Ne daha hızlı ? Genel bir işaretçi ise rastgele bir bellek sayfasında, bir değer ise sabit ama muhtemelen uzak bir bellek sayfasında olacaktır. Derleyici, üzerinde kullanışlı bir gözetleme deliği optimizasyonu kullanamaz. Düşünebileceğim herhangi bir önlemle, küreseller yavaş .

Alıcılar ve ayarlayıcılardan daha hızlı ve referanslar. Ama çok fazla değil. Boyutları düşük tutmaya yardımcı olur, bu nedenle bazı sistemlerde yardımcı olur. Muhtemelen 'çok' dediğimde abartıldım, ama bir şey kullanmaman gerektiğini söyleyen herkese çok şüpheliyim. Sadece sağduyunuzu kullanmanız gerekir. Sonuçta, singletonlar statik bir sınıf üyesinden başka bir şey değildir ve bunlar globaldir.
jacmoe

Ancak globallerle herhangi bir senkronizasyon problemini çözmek için onlar için alıcılara / ayarlayıcılara ihtiyacınız var, bu gerçekten alakalı değil. Küresel durumla ilgili (ve nadiren yararlanan) problem, arayüzün hız veya (etkili) sözdizimi yönleriyle ilgili herhangi bir endişe değil, küresel durumudur.
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.