Bileşen tabanlı bir oyunda varlık durumları ve animasyonlar nasıl güncellenir?


10

Öğrenim amacıyla bileşen tabanlı bir varlık sistemi tasarlamaya çalışıyorum (ve daha sonra bazı oyunlarda kullanıyorum) ve varlık durumlarını güncelleme konusunda bazı sorunlar yaşıyorum.

Bileşenler arasında bağımlılıkları önlemek için Bileşen içinde bir update () yöntemi olmasını istemiyorum.

Şu anda aklımda olan şey, bileşenlerin veri tutması ve sistemlerin bileşenleri güncellemesidir.

Yani, Transform, Hareket, Durum, Animasyon ve Rendering bileşenlerine sahip bazı varlıkları (örn. Oyuncu, düşman1, düşman2) içeren basit bir 2D oyunum varsa, sahip olmam gerektiğini düşünüyorum:

  • Tüm Hareket bileşenlerini hareket ettiren ve Durum bileşenlerini güncelleyen bir Hareket Sistemi
  • Animasyon bileşenlerini güncelleyen bir RenderSystem (animasyon bileşeninin her durum için bir animasyon (yani bir dizi kare / doku) içermesi ve güncellenmesi, mevcut duruma karşılık gelen animasyonu (örn. Atlama, moving_left, vb.) Seçmesi ve çerçeve indeksinin güncellenmesi). Ardından, RenderSystem, Render bileşenlerini her bir varlığın Animasyonunun geçerli karesine karşılık gelen doku ile günceller ve her şeyi ekranda görüntüler.

Artemis çerçevesi gibi bazı uygulamalar gördüm, ancak bu durumu nasıl çözeceğimizi bilmiyorum:

Diyelim ki oyunumda aşağıdaki varlıklar var. Her varlığın bir dizi durumu ve her bir durum için bir animasyonu vardır:

  • oyuncu: "boşta", "moving_right", "atlama"
  • enemy1: "moving_up", "moving_down"
  • enemy2: "moving_left", "moving_right"

Her bir kurumun mevcut durumunu güncellemek için en kabul edilen yaklaşımlar nelerdir? Aklıma gelen tek şey, her varlık grubu için ayrı sistemlere ve ayrı Durum ve Animasyon bileşenlerine sahip olmaktır, bu yüzden PlayerState, PlayerAnimation, Enemy1State, Enemy1Animation ... PlayerMovementSystem, PlayerRenderingSystem ... ama bunun kötü olduğunu düşünüyorum çözüm ve bileşen tabanlı bir sisteme sahip olma amacını bozar.

Gördüğünüz gibi, burada çok kayboldum, bu yüzden herhangi bir yardımı çok takdir ediyorum.

DÜZENLEME: Bence bu işi yapmayı amaçladığım çözüm şudur:

Statecomponent ve animationcomponent bileşenini tüm varlıklar için kullanılacak kadar genel yaparsınız. İçerdikleri veriler, hangi animasyonların oynatıldığı veya hangi durumların kullanılabilir olduğu gibi şeyleri değiştirmek için değiştirici olacaktır. - Byte56

Şimdi, bu 2 bileşeni yeterince genel olarak nasıl tasarlayacağımı anlamaya çalışıyorum. Her durum için bir UID'ye sahip olabilir (örneğin yürüme, koşma ...) ve animasyonları bu tanımlayıcı tarafından anahtarlanan AnimationComponent'e bir haritaya kaydetmek iyi bir çözüm olabilir mi?


Bunu gördüğünüzü varsayalım: Varlıklar veya bileşenlerdeki durum değişiklikleri ? Sorunuz temelde bundan farklı mı?
MichaelHouse

@ Byte56 Evet, birkaç saat önce okudum. Orada önerdiğiniz çözüm, burada ortaya koyduğum fikre benzer. Ancak benim durumum StateComponent ve AnimationComponent sistemdeki tüm varlıklar için aynı olmadığında geliyor. Bu sistemi, aynı olası durumlara ve animasyonlara sahip varlık gruplarını işleyen daha küçük sistemlere ayırmalı mıyım? (daha iyi açıklama için orijinal
yazımın

1
Sen yapmak statecomponentve animationcomponentjenerik yeterince tüm varlıklar için kullanılacak. İçerdikleri veriler, hangi animasyonların oynatıldığı veya hangi durumların kullanılabilir olduğu gibi şeyleri değiştirmek için değiştirici olacaktır.
MichaelHouse

Bağımlılık hakkında konuşurken, veri bağımlılığı mı yoksa yürütme sırası bağımlılığı mı demek istediniz? Ayrıca, önerdiğiniz çözümde, MovementSystem artık bir şeyin hareket edebileceği tüm farklı yolları uygulamak zorunda mı? Bu bileşen tabanlı sistem fikrini kırıyor gibi görünüyor ...
ADB

@ADB Veri bağımlılığından bahsediyorum. Animasyonu güncellemek için (örneğin, move_right animasyonundan move_left animasyonuna geçiş) varlığın mevcut durumunu bilmem gerekiyor ve bu 2 bileşenin nasıl daha genel hale getirileceğini göremiyorum.
miviclin

Yanıtlar:


5

IMHO Movementbileşeninin geçerli durumu ( Movement.state) tutması ve Animationbileşen, Movement.stateanimasyona Animation.animationdurum kimliğinin basit bir aramasını kullanarak (OP'nin sonunda önerildiği gibi) geçerli animasyonundaki değişiklikleri ( ) gözlemlemeli ve güncellemelidir . Açıkçası bu araç Animationbağlı olacaktır Movement.

Alternatif bir yapı , temel olarak model-görünüm-denetleyicisi (bu durumda durum-animasyon-hareketi) Stateolan Animationgözlemleyen ve Movementdeğiştiren genel bir bileşene sahip olmak olacaktır .

Başka bir alternatif, varlığın durumu değiştiğinde varlığın bileşenlerine bir olay göndermesini sağlamaktır. Animationbu etkinliği dinler ve animasyonunu buna göre günceller. Bağımlı sürümün daha şeffaf bir tasarım olduğunu iddia edebilirsiniz, ancak bu bağımlılığı ortadan kaldırır.

İyi şanslar.


Animasyon Devleti gözlemler ve Devlet Hareket'i gözlemler ... Bağımlılıklar hala orada ama bunu deneyebilirim. Son alternatif böyle bir şey olur mu: Hareket varlığa yapılan değişiklikleri bildirir ve varlık Devlete bir olay gönderir ve sonra aynı süreç Durum ve Animasyon için tekrarlanır mı? Bu yaklaşım performansı nasıl etkileyebilir?
miviclin

İlk vaka: Movementolur kontrol State (gözlemlemek değil). Son durum: Evet öyle Movementyapardı entity.dispatchEvent(...);ve bu tür bir olayı dinleyen diğer tüm bileşenler bunu alacak. Performans elbette saf yöntem çağrılarından daha kötüdür, ama fazla değildir. Örneğin olay nesnelerini havuzlayabilirsiniz. Btw, varlığı "olay düğümü" olarak kullanmak zorunda değilsiniz, özel bir "olay veri yolu" da kullanabilirsiniz, varlık sınıfı tamamen dışında bırakarak.
12'de

2

Sorununuz hakkında, STATE yalnızca Animasyonlarda kullanılıyorsa, bunu diğer Bileşenlere göstermeniz bile gerekmez. Birden fazla kullanımı varsa, açığa çıkarmanız gerekir.

Tanımladığınız Bileşenler / Alt Sistem sistemi, bileşen tabanlı olmaktan çok hiyerarşi temelli hissediyor. Sonuçta, bileşen olarak tanımladığınız şey aslında veri yapılarıdır. Bunun kötü bir sistem olduğu anlamına gelmez, sadece bileşen tabanlı yaklaşıma çok iyi uyduğunu düşünmüyorum.

Belirttiğiniz gibi, bağımlılıklar bileşen tabanlı sistemlerde büyük bir sorundur. Bununla başa çıkmanın farklı yolları vardır. Bazıları her bileşenin bağımlılıklarını beyan etmesini ve sıkı bir kontrol yapmasını gerektirir. Diğerleri belirli bir arabirimi uygulayan bileşenleri sorgular. Yine de diğerleri, her birini somutlaştırdıklarında bağımlı bileşenlere referansta bulunurlar.

Kullandığınız yöntemden bağımsız olarak, Bileşenler koleksiyonu olarak hareket etmek için bir çeşit GameObject'e ihtiyacınız olacaktır. GameObject'in sağladığı şey çok değişebilir ve sık kullanılan bazı verileri GameObject seviyesine iterek bileşenler arası bağımlılıklarınızı basitleştirebilirsiniz. Birlik bunu örneğin dönüşümle yapar, tüm oyun nesnesini bir tane olmaya zorlar.

Burada, farklı oyun nesneler için farklı devletler / animasyon sormak sorunu ile ilgili ne ben yapardı. İlk olarak, uygulamanın bu aşamasında çok süslü olmazdım: sadece çalışmasını sağlamak için şimdi ihtiyacınız olanı uygulayın, sonra ihtiyacınız olan çan ve ıslık ekleyin.

Yani, bir 'State' bileşeni ile başlardım: PlayerStateComponent, Enemy1State, Enemy2State. Devlet bileşeni, uygun zamanda devleti değiştirmeye özen gösterir. Durum, nesnelerinizin hemen hemen sahip olacağı bir şeydir, bu nedenle GameObject'te bulunabilir.

Sonra bir AnimationCompoment olurdu. Bu, duruma kilitlenmiş bir animasyon sözlüğü içerir. Update () öğesinde durum değişirse animasyonu değiştirin.

Bulamayacağım çerçeve oluşturma hakkında harika bir makale var. Etki alanında deneyiminiz olmadığında, bir sorun seçmeniz ve mevcut sorunu çözen en basit uygulamayı yapmanız gerektiğini söyledi . Sonra başka bir sorun / kullanım örneği ekler ve ilerledikçe çerçeveyi genişletirsiniz, böylece organik olarak büyür. Bu yaklaşımı gerçekten seviyorum, özellikle de yeni konseptle yaptığınız gibi çalışırken.

Önerdiğim uygulama oldukça naif, ancak daha fazla kullanım örneği ekledikçe bazı olası iyileştirmeler:

  • GameObject değişkenini bir sözlükle değiştirin. Her bileşen değerleri depolamak için sözlüğü kullanır. (çarpışmayı doğru şekilde yaptığınızdan emin olun ...)
  • düz değerlerin sözlüğünü bunun yerine referanslarla değiştirin: class FloatVariable () {public value [...]}
  • Birden çok durum bileşeni yerine, değişken durum makineleri oluşturabileceğiniz genel bir StateComponent oluşturun. Üzerinde bir durumun değişebileceği genel bir koşul kümesine sahip olmanız gerekir: tuşa basma, fare girişi, değişken değişiklikler (bunu yukarıda FloatVariable'a bağlayabilirsiniz).

Bu yaklaşım işe yarıyor, bir yıl önce benzer bir şey uyguladım, ancak sorun hemen hemen her bileşenin diğer bileşenlere bağlı olması, bu yüzden benim için daha az esnek görünüyor. Ayrıca en yaygın bileşenleri (örneğin, dönüştürme, oluşturma, durum ...) varlığa itmeyi düşündüm, ancak bence bu bileşenlerin amacını ihlal ediyor, çünkü bazıları kuruma bağlı ve bazı varlıkların bunlara ihtiyacı olmayabilir. Bu yüzden mantığı güncellemekten sorumlu sistemler ile yeniden tasarlamaya çalışıyorum, böylece bileşenler kendilerini güncellemedikleri için birbirleri hakkında hiçbir şey bilmiyorlar.
miviclin

0

ADB'nin cevabına ek olarak, http://en.wikipedia.org/wiki/Dependency_injection kullanabilirsiniz , bu da çok sayıda bileşeni kurucularına referans olarak geçirerek oluşturmanıza yardımcı olur. Açıkçası hala birbirine bağımlı olacaklar (kod tabanınızda gerekliyse), ancak tüm bu bağımlılıkları bağımlılıkların kurulduğu ve kodunuzun geri kalanının bağımlılık hakkında bilgi sahibi olması gerekmeyen bir yere koyabilirsiniz.

Bu yaklaşım, arabirimleri kullanırsanız da iyi çalışır çünkü her bileşen sınıfı yalnızca neye ihtiyaç duyduğunu veya nerede kaydedilmesi gerektiğini ister ve yalnızca bağımlılık enjeksiyon çerçevesi (veya her şeyi ayarladığınız yer, genellikle uygulama) kimin neye ihtiyacı olduğunu bilir .

DI veya temiz kod kullanmadan kurtulabileceğiniz basit sistemler için, RenderingSystem sınıflarınız, bunları statik olarak çağırmanız veya en azından her bir bileşende kullanılabilir hale getirmeniz gerektiği gibi geliyor; Daha temiz bir yaklaşımla ilgileniyorsanız, yukarıdaki DI wiki bağlantısının bağlantılarını kontrol edin ve Temiz Kod hakkında bilgi edinin: http://clean-code-developer.com/


Bileşenlerin birbirine oldukça bağımlı olduğu bir sistemim zaten var. Orada bağımlılık enjeksiyonunu yoğun bir şekilde kullandım ve derin hiyerarşilere tercih etsem de, mümkünse bileşen birleşmesini önlemek için yeni bir tane oluşturmaya çalışıyorum. Statik bir şey demezdim. Her sistemin erişebileceği bir ComponentManager olurdu (her sistem buna bir referans olmalıdır) ve RendererSystem bileşen animasyonundan tüm animasyon bileşenlerini alacak ve her animasyonun mevcut durumunu oluşturacaktır.
miviclin
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.