GameManager tanrı nesnesini nasıl önleyebilirim?


51

Oyun kodunu yapılandırmayla ilgili bir soruya cevap okudum . Her yerde bulunan GameManagersınıfı ve üretim ortamında sıkça nasıl bir sorun haline geldiğini merak etmemi sağladı . Bunu tarif edeyim.

İlk önce prototip yapımı var. Kimse harika kod yazmayı umursamıyor, sadece oyunun eklenip eklenmediğini görmek için çalışan bir şey almaya çalışıyoruz.

Sonra yeşil bir ışık var ve işleri temizlemek için biri yazıyor GameManager. Muhtemelen bir demet tutmak GameStates, belki birkaç tane saklamak GameObjects, gerçekten büyük bir şey değil. Sevimli, küçük bir yönetici.

Ön-üretimin barışçıl aleminde oyun güzel bir şekilde şekilleniyor. Kodlayıcılar, Büyük Tasarım Desenleriyle olan şeyi mimariye dönüştürmek için uygun uyku gecelerine ve birçok fikre sahiptir.

Daha sonra üretim başlar ve yakında, elbette, gevrek zaman vardır. Dengeli beslenme uzun sürdü, böcek takipçisi sorunlarla çatlıyor, insanlar stresli ve oyun dün piyasaya sürülmeli.

Bu noktada, genellikle, GameManagerbir olan gerçek büyük karışıklık (kibar kalmak).

Bunun nedeni basit. Sonuçta, bir oyun yazarken, peki ... tüm kaynak kodları aslında oyunu yönetmek için burada . Bu küçük ekstra özelliği veya bugfix'i , her şeyin zaten depolanmış olduğu yere eklemek kolaydır . Zaman bir sorun haline geldiğinde, ayrı bir sınıf yazmanın ya da bu dev yöneticiyi alt yöneticilere bölmenin bir yolu yoktur.GameManager

Elbette bu klasik bir anti-kalıptır: tanrı nesnesi . Kötü bir şey, birleştirmek için bir acı, sürdürmek için bir acı, anlamak için bir acı, dönüştürmek için bir acı.

Bunun olmasını önlemek için ne önerirsiniz?

DÜZENLE

İsmi suçlamanın cazip olduğunu biliyorum. Elbette bir GameManagersınıf yaratmak hiç de iyi bir fikir değil. Ancak aynı şey, bir temizliğin başına gelebilir GameApplicationya GameStateMachineda GameSystembir projenin sonunda koli şeridi tarafından favori olarak sonuçlanabilir. Adlandırma ne olursa olsun, oyun kodunuzda bir yerde o sınıfa sahipsiniz, şu an için sadece bir embriyo: sadece ne olacağını henüz bilmiyorsunuz. Bu yüzden "adlandırma suçu" cevapları beklemiyorum. Bunun olmasını engellemenin bir yolunu, bir kodlama mimarisini ve / veya bir ekibin bunun üretimin bir noktasında olacağını bilerek izleyebileceği bir süreci istiyorum. Sadece bir ay süren hata düzeltmeleri ve son dakika özelliklerinden kurtulmak çok kötü, çünkü hepsi şu anda tek bir devasa idare edilemez yöneticide.


GameManager ya da ControllerOfTheGame olarak adlandırılmak ya da ne çağırmak istersen, tüm oyun için mantığı kontrol etmekten sorumlu bir sınıftan kaçınmak istiyorum. Yapmayı düşündüğünüz şey ne olursa olsun, bunu yaparken yaptığınızı biliyorsunuz. Sanırım son oyunum, sadece tasarruf seviyesini tutmak için yola çıkan bir seviye kontrolöre sahipti, ancak durduyup düşünürsem, bu nesnenin olması gerekenden daha fazla ayrıntıya sahip olması gerektiği açıktı.
brandon

@brandon Sana sorumu tekrar yazayım: tüm oyun mantığını kendin GameManageryukarıda anlattığım etkiye maruz bırakmadan nasıl kontrol edebilirsin ?
Laurent Couvidou

Mantığa bağlı. Açıkça kendi mantığına sahip olan oyuncu, düşman, yapı vb. Gibi belirgin şeyler kendi sınıflarına girer. En çok sorduğunuz şey oyunun durumunu ele almak. Genelde, tüm oyunun durumunu izleyen bir sınıf olacak, ama benim deneyimime göre prototip yaparken endişelenmeniz gereken en son şeylerden biri ve bunun amacı çok açık olmalıdır. Temel olarak prototiplemeden önce ilk planlama yaparsınız veya yalnızca test amaçlı önemsiz sınıfları kullanmaktan kaçınmak için üretime başladığınızda sıfırdan başlarsınız.
brandon

İlginçtir, XNA bu potansiyel felaketi sizin için yaratır. Varsayılan olarak, her şeyi yönetmek için bir Game sınıfı oluşturulur. Ana güncelleme, çizim, başlatma ve yükleme yöntemlerini içerir. Aslında yeni bir projeye geçme sürecindeyim, çünkü (o kadar karmaşık değil) oyunumun o sınıfa sıkışan her şeyle başa çıkması çok zor oldu. Ayrıca, Microsoft dersleri teşvik ediyor gibi görünüyor.
Fibericon

Yanıtlar:


23

Sonra bir yeşil ışık var ve işleri temizlemek için birileri bir GameManager yazıyor. Muhtemelen bir avuç GameStates tutmak, belki de bir kaç GameObject saklamak, büyük bir şey değil, gerçekten. Sevimli, küçük bir yönetici.

Biliyor musun, bunu okurken kafamda küçük alarmlar vardı. "GameManager" isimli bir nesne asla sevimli veya küçük olmayacak. Ve biri kodu temizlemek için mi yaptı? Daha önce neye benziyordu? Tamam, bir kenara şakalar: Bir sınıfın adı, sınıfın ne yaptığının açık bir göstergesi olmalı ve bu bir şey olmalıdır (aka: tek sorumluluk ilkesi ).

Ayrıca, GameManager gibi bir nesneyle hala bitebilirsin ama açıkça çok yüksek bir seviyede var ve üst düzey görevlerle ilgilenmeli. Oyun nesnelerinin bir kataloğunun bakımı? Belki. Oyun nesneleri arasında iletişimi kolaylaştırmak? Elbette. Nesneler arasındaki çarpışmaları hesaplamak? Hayır! Ayrıca, Yönetici adı üzerine kaşlarını çattığının nedeni de budur - çok geniş ve bu başlık altında çok fazla suistimal yapılmasına izin veriyor.

Sınıf boyutlarına ilişkin hızlı bir kural: Sınıf başına yüzlerce kod satırına giriyorsanız bir şeyler ters gitmeye başlar. Aşırı kıskanç olmadan, herhangi bir şey, yani, 300 LOC benim için bir kod kokusudur ve 1000'den fazla gidiyorsanız, uyarı zilleri çalınmalıdır. Her nasılsa, 1000 kod satırının her biri 250 iyi yapılandırılmış 4 sınıftan daha kolay anlaşılması gerektiğine inanmakla, kendinizi kandırıyorsunuzdur.

Zaman bir sorun haline geldiğinde, ayrı bir sınıf yazmanın ya da bu dev yöneticiyi alt yöneticilere bölmenin bir yolu yoktur.

Bence durum böyle çünkü sorunun her şeyin tam bir karışıklığa yol açtığı noktaya yayılmasına izin veriliyor. Pratiği üstlenmeden - Aradığınız şey olduğu sürece sürekli minik artışlarla kodun tasarımını geliştirmek gerekir .

Bunun olmasını önlemek için ne önerirsiniz?

Sorun teknolojik bir problem değil, bunun için teknolojik düzeltmeler aramamalısınız. Sorun şudur: Ekibinizde yekpare kod parçaları oluşturma eğilimi ve bunun gibi bir şekilde orta / uzun vadede yararlı olduğu inancı var. Ayrıca, takımın oyunun mimarisini yönlendirecek güçlü bir mimari iptali olmadığı görülüyor (ya da en azından bu kişi bu görevi yerine getirmek için çok meşgul). Temel olarak, tek çıkış yolu ekip üyelerinin bu düşüncenin yanlış olduğunu fark etmesini sağlamaktır. Kimsenin lehine değil. Ürünün kalitesi kötüleşecek ve ekip işleri düzeltmek için sadece daha fazla gece harcayacak.

İyi haber şu ki, temiz kod yazmanın acil ve somut faydaları o kadar büyük ki, neredeyse tüm geliştiriciler faydalarını çok hızlı bir şekilde gerçekleştiriyor. Takımı bir süre bu şekilde çalışmaya ikna edin, sonuçlar gerisini halleder.

Zor olan kısım, kötü kodu neyin oluşturduğuna dair bir his geliştirmenin (ve daha iyi bir tasarımla hızlı bir şekilde ortaya çıkma yeteneğinin) gelişimde öğrenmesi daha zor becerilerden biri olmasıdır. Önerim, ekipte bunu yapabilen yeterince kıdemli birisinin olması umuduna dayanıyor - insanları bu şekilde ikna etmek çok daha kolay.

Düzenleme - Biraz daha fazla bilgi:

Genel olarak, sorununuzun oyun geliştirme ile sınırlı olduğunu sanmıyorum. Özünde, bu bir yazılım mühendisliği sorunu, bu yüzden yorumlarımı bu yönde. Farklı olabilir ne oyun geliştirme endüstrisinin doğası, daha fazla sonuç ve diğer gelişme türlerine göre daha son tarih odaklı, emin değilim.

Özellikle oyun geliştirme için, "özellikle oyun mimarisi" ipuçlarıyla ilgili StackOverflow'ta bu sorunun kabul edilen cevabı şöyle diyor:

Takip nesne yönelimli tasarım Katı prensipleri ....

Bu aslında tam olarak söylediğim şey. Baskı altında olduğumda kendimi de büyük miktarda kod yazarken buluyorum, ancak bunu teknik borç olduğunu kafama soktum. Benim için iyi çalışma eğilimi, günün ilk yarısını (veya dörtte üçünü) büyük miktarda orta kalite kodu üreterek geçirmek ve daha sonra bir süre geriye yaslanmak ve bir süre düşünmek; biraz kod geliştirmek için kafamda veya kağıt / beyaz tahta üzerinde biraz tasarım yapmak. Çoğunlukla, tekrarlayan kodları farkederim ve okunabilirliği geliştirirken her şeyi parçalayarak toplam kod satırlarını gerçekten azaltabilirim. Bu sefer yatırım çok hızlı bir şekilde karşılığını veriyor, buna "yatırım" demek aptalca geliyor - oldukça sık sık (bir hafta sonra), günümün yarısını boşa harcamış olabilecek böcekleri toplayacağım.

  • Onları kodladığınız günde düzeltin.
  • Birkaç saat içinde yaptığınız için memnun olacaksınız.

Aslında yukarıdakilere inanmak zor; Bunu kendi işim için yapmayı başardım, çünkü etkileri tekrar ve tekrar deneyimledim. Öyle olsa bile, daha fazla çalkalama yaparken kod çözmeyi haklı çıkarmam hala zor. Ne yazık ki, bu öneri belki de çok genel ve yapmak kolay değil. Ancak buna şiddetle inanıyorum! :)

Özel örneğinizi yanıtlamak için:

Bob Amca'nın Temiz Kodu , kaliteli kodun neye benzediğini özetlemek için harika bir iş çıkardı. Neredeyse tüm içeriğine katılıyorum. Bu nedenle, bir 30 000 LOC yönetici sınıfı örneğini düşündüğümde, "iyi sebep" bölümüne gerçekten katılıyorum. Kulağa rahatsız edici gelmek istemem ama bu şekilde düşünmek soruna yol açacaktır. Tek bir dosyada bu kadar fazla kodun olması için iyi bir neden yoktur - neredeyse 1000 sayfa metindir! Yerelliğin herhangi bir yararı (uygulama hızı veya tasarım "basitlik"), geliştiricilerin o canavarlığı yönlendirmeye çalışırken tamamen tıkanmasıyla derhal etkisiz hale getirilecek ve bu birleşme, vb.

Eğer ikna olmamışsanız, en iyi önerim yukarıdaki kitabın bir kopyasını almak ve bir göz atmak olacaktır. Bu tür bir düşünceyi uygulamak, gönüllü olarak, güzel bir şekilde yapılandırılmış temiz, kendi kendini açıklayan bir kod yaratmaya çalışanlara yol açar.


Bu bir kez gördüğüm bir kusur değil. Bunu birkaç takımda, birkaç projede gördüm. Bununla mücadele eden birçok yetenekli ve yapılandırılmış insan gördüm. Baskı altındayken 300 satırlık kod limiti, üreticinizin umursadığı bir şey değildir. Ne de oyuncu btw. Elbette bu güzel ve tatlı, ama şeytan ayrıntıda gizli. GameManagerŞimdiye kadar gördüğüm en kötü durum yaklaşık 30.000 kod satırındaydı ve bunun çok iyi bir sebep için burada olduğundan eminim. Bu elbette aşırı, ama bunlar gerçek dünyada olur. Bu GameManageretkiyi sınırlamanın bir yolunu istiyorum .
Laurent Couvidou

@lorancou - Gönderiye çok fazla ek bilgi ekledim, bir yorum için biraz fazla oldu, umarım biraz daha fazla fikir verir, hatta herhangi bir somut mimariyi gösteremesem bile örnekleri.
Daniel B

Ah, o kitabı okumadım, bu yüzden kesinlikle iyi bir öneri. Ve binlerce satırlık bir sınıfa kod eklemek için iyi bir neden olduğunu kastetmedim. Demek istediğim, bu tür bir tanrı nesnesindeki tüm kodlar işe yarar bir şey yapar . Muhtemelen biraz fazla hızlı yazdım;)
Laurent Couvidou

@lorancou Hehe, bu iyi ... bu şekilde delilik yatıyor :)
Daniel B

“Yeniden canlandırma uygulaması gerçekten aradığınız şeydir - küçük adımlarla kodun tasarımını sürekli olarak geliştirmeniz gerekir.”. Orada çok güçlü bir noktaya sahip olduğunu düşünüyorum. Karışıklık karışıklığı kendine çekiyor, bunun arkasındaki gerçek sebep bu yüzden uzun vadede kargaşanın mücadele etmesi gerekiyor. Bu cevabı kabul edeceğim, ancak diğerlerinde değer olmadığı anlamına gelmez!
Laurent Couvidou

7

Bu gerçekten oyun programlamasıyla değil, genel olarak programlamayla ilgili bir sorun.

Tüm kaynak kodları aslında oyunu yönetmek için burada.

Bu nedenle, adında "Yönetici" olan sınıfları önerecek herhangi bir Nesneye Yönelik kodlayıcıda kaşlarını çatmanız gerekir. Adil olmak gerekirse, oyunda "yarı-tan" nesnelerden kaçınmanın neredeyse imkansız olduğunu düşünüyorum, ama biz sadece "sistem" diyoruz.

Herhangi bir yazılım, son tarih yaklaştığında kirlenme eğilimindedir. Bu işin bir parçası. Üstelik, " kanal tipi programlama " konusunda, özellikle birkaç saat içinde ürününüzü göndermeniz gerektiğinde, yanlış bir şey yoktur . Bu problemden tamamen kurtulmazsınız, sadece azaltabilirsiniz.

Açıkçası, GameManager'a bir şeyler koymak için istekli iseniz, bu çok sağlıklı bir kod tabanına sahip olmadığınız anlamına gelir. İki sorun olabilir:

  • Kodunuz çok karmaşık. Çok fazla desen, erken optimizasyon, artık kimse akışı anlayamıyor. Yapabiliyorsanız geliştirirken daha fazla TDD kullanmaya çalışın, çünkü bu karmaşıklıkla mücadele etmek için çok iyi bir çözüm.

  • Kodunuz iyi yapılandırılmamış. (Ab) globals değişkenini kullanıyorsunuz, sınıflar gevşek bir şekilde bağlanmamış, herhangi bir arayüz yok, olay sistemi yok, vb.

Eğer kod iyi görünüyorsa, her proje için “neyin yanlış gittiğini” hatırlamak zorunda kalacaksınız ve bir dahaki sefere kaçınmalısınız.

Son olarak, bir takım yönetimi sorunu da olabilir: yeterli zaman var mıydı? Gittiğiniz mimariyi herkes biliyor mu? İçinde "Yönetici" kelimesi olan bir sınıfla iş yapmaya kim izin verdi?


Koli bandı programlamasında yanlış olan bir şey yok, bunu sana veriyorum. Ama eminim-Yönetici sınıfları oyun motorlarında her yerdedir, en azından onları çok gördüm. Çok büyüyemedikleri sürece faydalıdırlar ... a SceneManagerveya a'nın nesi var NetworkManager? Onları neden engellememiz gerektiğini ya da -Manager by -System'i nasıl değiştireceğimi bilmiyorum. Genellikle GameManagerdaha az kod girmeyen bir şeyle ilgili olanın yerine geçecek bir mimari için öneriler arıyorum .
Laurent Couvidou

SceneManager'ın nesi var? Peki, bir Sahne ve bir Sahne Yöneticisi arasındaki fark nedir? Bir Ağ ve Bir Ağ Yöneticisi? Diğer taraftan: Bunun bir mimari mesele olduğunu düşünmüyorum, ancak GameManager'da olan bir şeyin somut bir örneğini verirseniz ve orada olmazsanız, bir çözüm önermek daha kolay olurdu.
Raveline

Tamam, yönetici işini unut gitsin. Diyelim ki oyun durumlarınızı idare eden bir sınıfınız var, onu arayalım GameStatesCollection. Başlangıçta, sadece birkaç oyun durumuna ve bunlar arasında geçiş yapmanın yollarına sahip olacaksınız. Sonra gelen ve tüm bunları karmaşıklaştıran yükleme ekranları var. Daha sonra bazı programcılar, Level_A'dan Level_B'ye geçerken kullanıcı diski çıkarırken bir hata ile uğraşmak zorunda kalır ve yarım günlük yeniden düzenleme yapmadan harcama yapmanın tek yolu budur GameStatesCollection. Boom, bir tanrı nesnesi.
Laurent Couvidou,

5

Öyleyse, daha Enterprise-y dünyasından olası bir çözümü getirerek: Kontrol / bağımlılık enjeksiyonunun ters çevrilmesini kontrol ettiniz mi?

Temel olarak, oyununuzdaki her şey için bir konteyner olan bu çerçeveyi elde edersiniz . Bu ve sadece o, herşeyi birbirine nasıl bağlayacağınızı ve nesneleriniz arasındaki ilişkilerin ne olduğunu bilir. Nesnelerin hiçbiri kendi yapıcılarının içindeki hiçbir şeyi başlatmaz. Aksine onlar, ihtiyaç duyduklarını oluşturmak yerine sormak onlar IoC çerçevesinden gerekenler için; yaratıldıktan sonra, IoC çerçevesi bağımlılığı gidermek için hangi nesneye ihtiyaç duyulduğunu "bilir" ve onu doldurur. Gevşek bağlantı FTW.

EnemyTreasure sınıfınız bir GameLevel nesnesinin kabını istediğinde, çerçeve hangi örneği vereceğini bilir. Nasıl biliyor? Belki daha önce başlattı, belki yakındaki bazı GameLevelFactory'yi sorar. Mesele şu ki, EnemyTreasure GameLevel örneğinin nereden geldiğini bilmiyor. Sadece bağımlılığının artık tatmin olduğunu ve yaşamına devam edebileceğini biliyor.

Oh, PlayerSprite sınıfınızın IUpdateable uyguladığını görüyorum. Bu harika, çünkü çerçeve otomatik olarak her IUpdateable nesnesini ana oyun döngüsünün olduğu Zamanlayıcı'ya abone ediyor. Her Timer :: tick () otomatik olarak tüm IUpdatedable :: update () yöntemlerini çağırır. Kolay değil mi?

Gerçekçi olarak, bunu sizin için yapmak için bu bighugeohmygod çerçevesine ihtiyacınız yok: bunun önemli parçalarını kendiniz yapabilirsiniz. Mesele şu ki, kendinizi Yönetici türü nesneler yaparken bulursanız, olasılıklar, sorumluluklarınızı sınıflarınız arasında doğru bir şekilde dağıtmadığınız veya bir yerde bazı sınıfları kaçırdığınızdır.


İlginç, ilk defa IoC'yi duydum. Bu, oyun programlaması için fazladan bighugeohmygod olabilir, ama bunu kontrol edeceğim!
Laurent Couvidou

IoC, Biz sadece sağduyu demek için kullanmadık mı?
brice,

Yarım şans verildiğinde, bir mühendis her şeyden bir çerçeve yaratacaktır. (= Ayrıca, çerçeveyi kullanarak savunuculuk yapmıyorum, mimari deseni savunuyorum.
drhayes

3

Geçmişte, aşağıdakileri yaparsam, genellikle bir tanrı sınıfına girerim:

  • Bir sınıf şeması yazmadan önce oyun editörüne / IDE / notepad'e oturun (ya da sadece ana nesnelerin bir taslağını)
  • Oyunun çok belirsiz bir fikri ile başlayın ve hemen kodlayın, sonra geldikleri gibi yeni fikirleri yinelemeye başlayın
  • GameManager'ın aslında bir etki alanı nesnesi olduğu, sıra tabanlı bir strateji gibi statebased bir oyun yapmadığım zaman GameManager adında bir sınıf dosyası oluşturun.
  • kod düzenini erken umursamıyorum

Bu tartışmalı olabilir, eğer öyleyse güleceğim, ancak prototiplemede bile oynanabilir bir prototip yazmadan önce çok temel bir sınıf şeması yazmamanız gerektiği konusunda tek bir zaman düşünemiyorum. Planlamadan önce teknoloji fikirlerini test etme eğilimindeyim ama bu konuda. Bu yüzden portal yapmak isteseydim, portalların çalışmasını sağlamak için çok basit bir kod yazardım, o zaman küçük planlama için harika zaman geçirin, o zaman oynanabilir prototip üzerinde çalışabilirim.


1

Bu sorunun şimdi eski olduğunu biliyorum, ancak 2 sentimi de ekleyeceğimi düşündüm.

Oyun tasarlarken, neredeyse her zaman bir Game nesnesine sahibim. Ancak, çok yüksek bir seviyede ve gerçekten de "hiçbir şey yapmıyor".

Örneğin, Graphics sınıfına Render'a bildirir, ancak oluşturma işlemiyle ilgisi yoktur. LevelManager'dan yeni bir seviye yüklemesini isteyebilir, ancak yükleme işlemiyle ilgisi yoktur.

Kısacası, diğer sınıfların kullanımını düzenlemek için yarı tanrıça benzeri bir nesne kullanıyorum.


2
Bu hiç de tanrıya benzemiyor - buna soyutlama deniyor. :)
Vaughan Hilts
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.