Kompozisyon ağır OOP vs saf varlık bileşen sistemleri? [kapalı]


13

İtiraf ediyorum, aşırı kullanımın ve hatta mirasın kötüye kullanılmasının günahını yaptım. OOP kursumu alırken yaptığım ilk (metin) oyun projesi, "Kapı" ve "Tek kapılı oda", "İki kapılı oda" ve "Kilitli kapı" ve "kilitli kapı" "Oda" dan öyle.

Son zamanlarda üzerinde çalıştığım (grafik) oyunla dersimi öğrendiğimi ve miras kullanmayı sınırladığımı sanıyordum. Ancak yakında ortaya çıkmaya başlayan sorunları fark ettim. Kök sınıfım gittikçe şişmeye başlamıştı ve yaprak sınıflarım yinelenen kodlarla doluydu.

Hala yanlış şeyler yaptığımı sanıyordum ve çevrimiçi baktıktan sonra bu problemle tek ben olmadığımı keşfettim. Bu kadar kapsamlı bir araştırmadan sonra Entity sistemlerini keşfettim (read: googlefu)

Üzerine okumaya başladığımda, geleneksel OOP hiyerarşisi ile yaşadığım sorunları bileşenlerle ne kadar açık bir şekilde çözebildiğini görebildim. Ancak bunlar ilk okumalarda vardı. T-makinesinde olduğu gibi daha fazla… “radikal” ES yaklaşımına tökezlediğimde .

Kullandıkları yöntemlere katılmamaya başladım. Saf bir bileşen sistemi, aşırı derecede ya da daha doğrusu, muhtemelen OOP'un gücü olan sezgisel görünüyordu. Yazar, ES sisteminin OOP'nin tersi olduğunu söyleyecek kadar ileri gider ve OOP boyunca kullanılabilir olsa da, gerçekten olmamalıdır. Yanlış olduğunu söylemiyorum, ama uygulamak istediğim bir çözüm gibi hissetmedim.

Bu yüzden benim için ve görevin başında yaşadığım sorunları çözmek için, sezgilerime karşı çıkmadan, hala bir hiyerarşi kullanmak, ancak daha önce kullandığım gibi monolitik bir hiyerarşi olmayacak, aksine birkaç tane daha küçük ağaçtan oluşan çok kutuplu bir kelime (monolitik karşıt bir kelime bulamadım).

Aşağıdaki örnek, ne demek istediğimi gösterir (bu, Oyun Motoru Mimarisi, Bölüm 14'te bulduğum bir örnekten esinlenmiştir).

Araçlar için küçük bir ağacım olurdu. Kök araç sınıfının bir oluşturma bileşeni, bir çarpışma bileşeni, konum bileşeni vb.

Daha sonra bir tank, bir araç alt sınıfı, bu bileşenleri ondan devralır ve kendi "top" bileşeni verilir.

Aynı şey Karakterler için de geçerli. Bir karakterin kendi bileşenleri olur, sonra Player Sınıfı onu devralır ve bir Giriş kontrolörü verilirken, diğer düşman sınıfları Karakter sınıfından miras alır ve bir AI kontrolörü verilir.

Bu tasarımla ilgili herhangi bir sorun görmüyorum. Saf bir Varlık Denetleyici Sistemi kullanılmamasına rağmen, köpürme efekti ile ilgili sorun ve büyük kök sınıfı çok ağaçlı bir hiyerarşi kullanılarak çözülür ve ağır, kod çoğaltma yapraklarının sorunu, yaprakların başlamak için herhangi bir kod var, sadece bileşenler. Yaprak düzeyinde bir değişiklik yapılması gerekiyorsa, kodu her yere kopyalamak yerine tek bir bileşeni değiştirmek kadar basittir.

Tabii ki, benim kadar deneyimsiz olmak, tek hiyerarşi, kalıtım ağır modelini ilk kullanmaya başladığımda herhangi bir sorun görmedim, bu yüzden şu anda uygulamayı düşündüğüm modelle ilgili sorunlar varsa, görebilmek.

Senin fikirlerin?

Not: Java kullanıyorum, bu yüzden normal bileşenleri kullanmak yerine bunu uygulamak için birden fazla miras kullanmak mümkün değildir.

PPS: Bileşenler arası iletişim, bağımlı bileşenler birbirine bağlanarak yapılacaktır. Bu birleşmeye yol açacak, ama bence bu bir sorun değil.


2
Bunların hepsi bana iyi geliyor. Hiyerarşinizde veya varlık sisteminizde size "kokan" belirli bir örnek var mı? Sonunda, oyunun bir saflık hissinden daha fazlasını yapmasıyla ilgili.
drhayes

Ben yok, ama dediğim gibi, neredeyse hiç deneyimim yok ve bunun için en iyi hâkim olmaktan çok uzaktayım.
Midori Ryuu

3
Bu soruyu kapatmak için oy kullandım çünkü öznel ve geniş tartışmaya açık. Samimi bir konumdan sorulduğunu takdir ediyorum - ancak burada nasıl ilerleyeceğini seçmek tamamen kişisel bir görüş meselesidir. Bileşenlerinizi bir alt sınıfa sabitlemenin tek dezavantajı, bileşenlerin düzenlenmesinin çalışma zamanında değiştirilememesidir - ancak bu kesinlikle sizin için belirgin olmalı ve yaptığınız bir seçimdir.
Kylotan

4
Ben de kapanmaya oy verdim. Bu iyi ve iyi yazılmış bir soru, ancak GDSE için uygun değil. GameDev.net adresinden yeniden göndermeyi deneyebilirsiniz.
Sean Middleditch

Yazıldığı gibi, soru 'Görüşleriniz?' İle, gerçekten açık uçlu ve cevapsızdır. Ancak, bir sen soru sanki cevap eğer sorumlu 'herhangi şaşkın tuzaklar ben farkında olmadan içine düşebilir var mı?' (En azından, çeşitli mimariler arasında herhangi bir ampirik fark olduğunu düşünüyorsanız.)
John Calsbeek

Yanıtlar:


8

Bu örneği düşünün:

Bir RTS yapıyorsun. Komple mantık nöbeti, bir temel sınıf yapmaya karar GameObjectve sonra iki alt sınıfa Buildingve Unit. Bu elbette gayet iyi çalışıyor ve sonunda şöyle görünen bir şey elde ediyorsunuz:

  • GameObject
    • ModelComponent
    • CollisionComponent
    • ...
  • Building
    • ProductionComponent
    • ...
  • Unit
    • AimingAIComponent
    • WeaponComponent
    • ParticleEmitterComponent
    • AnimationComponent
    • ...

Artık her alt sınıfınız Unitzaten ihtiyacınız olan tüm bileşenlere sahip. Ve bonus olarak, tüm bu sıkıcı kurulum kodu koymak için tek bir yer var newbir yukarı s WeaponComponent, bir bunu bağlayan AimingAIComponentve bir ParticleEmitterComponent-harika!

Ve elbette, hala bileşenlere mantığı etkiliyor, çünkü sonunda Towerbir bina olan ama bir silahı olan bir sınıf eklemek istediğinize karar verdiğinizde , onu yönetebilirsiniz. Öğesinin alt sınıfınıza bir AimingAIComponent, a WeaponComponentve a ekleyebilirsiniz . Tabii ki, o zaman geçip sınıftan başlatma kodunu kazıp başka bir yere koymanız gerekiyor, ancak bu büyük bir kayıp değil.ParticleEmitterComponentBuildingUnit

Ve şimdi, ne kadar öngörüye sahip olduğunuza bağlı olarak, ince hatalarla sonuçlanabilir veya olmayabilir. Oyunda başka bir yerde şöyle görünen bir kod olabileceği anlaşılıyor:

if (myGameObject instanceof Unit)
    doSomething(((Unit)myGameObject).getWeaponComponent());

Silahlı bir şey için Towergerçekten çalışmasını isteseniz bile, bu sessizce binanız için işe yaramaz. Şimdi şöyle bir şey olmalı:

WeaponComponent weapon = myGameObject.getComponent(WeaponComponent.class);
if (weapon)
    doSomething(weapon);

Çok daha iyi! Bunu değiştirdikten sonra yazdığınız erişimci yöntemlerinden herhangi biri bu durumda ortaya çıkabilir. Bu yüzden yapılacak en güvenli şey hepsini çıkarmak ve herhangi bir alt sınıfla çalışabilen bu tek yöntemle her bileşene erişmek getComponent. (Alternatif olarak, her türlü get*Component()üst GameObjectsınıfa ekleyebilir ve bileşeni döndürmek için alt sınıflarda geçersiz kılabilirsiniz. İlkini varsayalım.)

Artık sizin Buildingve Unitsınıflarınız, bileşenlere bile sahip olmadan hemen hemen bileşenlerin parçalarıdır. Ve hiçbir süslü başlatma da, çünkü bir özel durum başka bir nesneyle bir yerde kod çoğaltmasını önlemek için bunların çoğunun dışarı sürüklenmesi gerekiyordu.

Bunu en uç noktaya kadar takip ederseniz , alt sınıflarınızı her zaman tamamen eylemsiz bileşen poşetleri haline getirirsiniz , bu noktada alt sınıfların olduğu herhangi bir nokta bile yoktur. Uygun bileşenleri oluşturan bir yöntem hiyerarşisiyle sınıf hiyerarşisine sahip olmanın hemen hemen tüm avantajlarından yararlanabilirsiniz . Bir Unitsınıfa sahip olmak yerine, addUnitComponentsbir AnimationComponentve ayrıca çağrı addWeaponComponentsyapan AimingAIComponent, a WeaponComponent, a ve a yapan bir yönteminiz vardır ParticleEmitterComponent. Sonuç olarak, bir varlık sisteminin tüm avantajlarına, bir hiyerarşinin tüm kodlarını yeniden kullanmanıza ve instanceofsınıf türünüzü kontrol etme veya yayınlama cazibesinin hiçbirine sahip olmayacaksınız.


İyi dedi. Buna ek olarak, ideal çözümü her varlığı bir komut dosyasıyla veya tanımlayıcı dosyalarıyla başlatmaktır. Varlık başlatma için metin dosyaları kullanıyorum. Hızlıdır ve programcı olmayanların farklı parametreleri test etmesine izin verir.
Coyote

Vay be yazı okumak bana bir kabus verdi! Tabii ki, iyi bir şekilde, gözlerimi ne tür bir kabusa açtığımı görmek demek istiyorum! Keşke böyle ayrıntılı bir cevaba daha fazla cevap verebilseydim, ama gerçekten eklenecek çok şey yok!
Midori Ryuu

Daha basit bir yolla. Kalıtımın fakir fabrikası olarak kullanıldığını düşünüyorsunuz.
Zardoz89

2

Kalıtım üzerine kompozisyon , OOP terminolojisidir (en azından öğrendiğim / öğrendiğim şekilde). Kompozisyon ve kalıtım arasında seçim yapmak için yüksek sesle "Araba bir tekerlek türüdür" (kalıtım) ve "Arabanın tekerlekleri vardır" (kompozisyon) olduğunu söylüyorsunuz. Biri diğerinden daha doğru görünmelidir (bu durumda kompozisyon) ve karar veremiyorsanız, aksi karar verene kadar kompozisyonu varsayılan olarak ayarlayın.


1

Bileşen tabanlı sistemleri oyun nesnelerine dayalı mevcut oyunlara entegre etmek söz konusu olduğunda, kovboy programlamada http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/ adresinde size bazı işaretler verebilecek bir makale var. geçiş yapılabilir.

Sorunlara gelince, modelinizin oynatıcıyı başka bir düşmandan farklı şekilde ele alması gerekecektir. Bir oyuncunun bağlantısı kesildiğinde veya özel durumlarda onu diğer karakterlerden farklı bir şekilde tutmadan durum değiştiremezsiniz (yani oyuncunun AI kontrollü hale gelmesi).

Bileşenlerin farklı varlıklar arasında yoğun olarak yeniden kullanılmasının yanı sıra, bileşen tabanlı oyunlar fikri tüm sistemin tekdüzeliğidir. Her varlık, isteğe bağlı olarak takılabilen ve sökülebilen bileşenlere sahiptir. Aynı türden tüm bileşenler, her tür arabirim (temel bileşen) tarafından kurulan bir dizi çağrı (konum, işlenen, komut dosyası ...) ile aynı şekilde işlenir.

Oyun nesnelerini devralmayı bileşen tabanlı bir yaklaşımla karıştırmak, her iki yaklaşımın dezavantajları ile bileşen tabanlı yaklaşımın bazı avantajlarını getirir.

Sizin için çalışabilir. Ama her ikisini de bir mimariden diğerine geçiş döneminin dışında karıştırmam.

PS bir telefona yazdı, bu yüzden dış kaynaklara bağlanmakta zorlanıyorum.


Telefonda olmanıza rağmen cevabınız için teşekkür ederiz! Ne demek istediğini anlıyorum. Hareket bileşenine dayalı şeyler, şeyleri değiştirmek için daha fazla esnekliğe ihtiyacım var. Bu yüzden devam edip minimal kalıtım ile bir kompozisyon yaklaşımı deneyeceğim. (Önerdiğimden bile daha fazla.)
Midori Ryuu

@ MidoriRyuu varlık nesnelerindeki tüm kalıtımdan kaçınır. Yerleşik yansıma (ve içgözlem) içeren bir dil kullanmak için yeterince şanslısınız. Nesnelerinizi doğru parametrelerle başlatmak için dosyaları (txt veya XML) kullanabilirsiniz. Çok fazla iş değil ve yeniden derlemeden gelişmiş oyun ince ayarına izin verecek. Ancak en azından bileşenler arası iletişim ve diğer yardımcı programlar için Entity sınıfını saklayın. PS hala telefonda :(
Coyote
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.