“Oyun Nesnesi” - ve bileşen tabanlı tasarım


25

Son 3-4 yıldır hobi projeleri üzerinde çalışıyorum. Sadece basit 2d ve 3d oyunlar. Ama son zamanlarda daha büyük bir projeye başladım. Soo, son birkaç ayda tüm oyun nesnelerimin temeli olabilecek bir oyun nesnesi sınıfı tasarlamaya çalışıyorum. Bu yüzden, birçok deneme ve deneme testinden sonra Google’a döndüm, bu da beni hızlı bir şekilde bazı GDC PDF’lerine ve PowerPuan’lara yönlendirdi. Ve şimdi bileşen tabanlı oyun nesnelerini kavramaya çalışıyorum.

Motorun bir oyun nesnesi yarattığını ve sonra sağlık, fizik, ağ kurma ve ne yaparsanız yapın gibi şeyleri ele alan farklı bileşenler eklediğini anlıyorum. Fakat anlamadığım şey, X bileşeninin Y'nin nesnenin durumunu değiştirip değiştirmediğini nasıl bildiğidir. Mesela, PhysicsComponent, oyuncunun hayatta olup olmadığını nasıl bilebilir, çünkü sağlık, HealthComponent tarafından kontrol edilir. Peki HealthComponent "oyuncu-ölmüş-animasyon" u nasıl oynuyor?

Bunun gibi bir şey olduğu izlenimindeydim (Sağlık Komponenti'nde):

if(Health < 0) {
   AnimationComponent.PlayAnimation("played-died-animation")
}

Ama sonra yine, HealthComponent'in eklediği oyun nesnesinin bir AnimationComponent'in ekli olduğunu nasıl biliyor? Burada gördüğüm tek çözüm

  1. Bir AnimationComponent'in takılı olup olmadığını kontrol edin (Bileşen kodunun içinde veya motor tarafında)

  2. Bileşenlerin başka bileşenlere gereksinimi var, ancak bu bileşen tasarımının tamamı ile mücadele ediyor gibi görünüyor.

  3. Tüm bileşen tasarımı fikri ile tekrar mücadele gibi görünen HealthWithAnimationComponent, HealthNoAnimationComponent ve soo gibi yazın.


1
Soruyu sev. Aynı aylar önce sormam gerekirdi, ama buna hiç cevap vermedim. Karşılaştığım ek bir sorun, bir oyun nesnesinin aynı bileşenin birden fazla örneğine sahip olması (örneğin, birden çok animasyon). Cevaplar buna değerse harika olurdu. Bir Game nesnesinin tüm bileşenleri arasında paylaşılan değişkenlerle paylaşılan bildirimler için mesajlar kullanmaya başladım (bir değişkenin değerini almak için bir mesaj göndermeleri gerekmez).
ADB

1
Oyunun türüne bağlı olarak, muhtemelen sağlık bileşeni olan ve hiçbir animasyon bileşeni olmayan oyun nesnelerine sahip olmayacaksınız. Ve tüm bu gameobjectler muhtemelen Unit gibi bir şeyin temsilidir. Böylece sağlık bileşenini atabilir ve alan sağlığına sahip olan ve birimin olması gereken tüm bileşenlerden haberdar olan UnitComponent'i oluşturabilirsiniz. Bileşenlerin bu ayrıntılı özelliği gerçekten hiçbir şeye yardımcı olmuyor - etki alanı başına bir bileşene sahip olmak daha gerçekçi (render, ses, fizik, oyun mantığı).
Kikaimaru

Yanıtlar:


11

Tüm örneklerinde korkunç bir sorun var. Sağlık bileşeni, işletmenin ölümüne cevap vermesi gereken her bileşen türü hakkında bilgi sahibi olmalıdır. Bu nedenle, senaryolarınızın hiçbiri uygun değildir. Varlığınızın bir sağlık bileşeni var. Bir animasyon bileşenine sahiptir. Ne hakkında ne de ne de ona dayanıyor. Bir mesajlaşma sistemi aracılığıyla iletişim kurarlar.

Sağlık bileşeni, işletmenin 'öldüğünü' tespit ettiğinde, 'öldüm' mesajı gönderir. Uygun animasyonu oynayarak bu mesaja cevap vermek, animasyon bileşeninin sorumluluğundadır.

Sağlık bileşeni, mesajı doğrudan animasyon bileşenine göndermez. Belki o varlıktaki her bileşene, belki de tüm sisteme yayınlar; Belki de animasyon bileşeninin mesajlaşma sisteminin 'öldüm' mesajlarıyla ilgilendiğini bilmesi gerekiyor. Mesajlaşma sistemini uygulamanın birçok yolu vardır. Bununla birlikte, bunu uyguladığınız nokta, sağlık bileşeninin ve animasyon bileşeninin, diğerinin mevcut olup olmadığını bilmek veya önemsemeye gerek duymaması ve yeni bileşenlerin eklenmesi, mevcut olanların kendilerine uygun mesajları göndermek için hiçbir zaman değişiklik yapmasını gerektirmeyeceğidir.


Tamam, bu mantıklı. Fakat kim “ölü” veya “portal-bozuldu” gibi “devletler” i ilan eder. Bileşen mi, motor mu? Çünkü bir devlete asla ölü olmayan bir şey eklemek için sağlık bileşeninin eklenmesini istemiyorum bana biraz zarar veriyor. Sanırım sadece dalıp biraz kodu test etmeye başlayacağım ve ne işe yaradığını göreceğim.
hayer

Michael ve Patrick Hughes yukarıda doğru cevabı var. Bileşenler sadece veridir; bu nedenle, işletmenin ne zaman öldüğünü ve mesaj gönderdiğini tespit eden sağlık bileşeni değil, oyuna özgü bir mantık seviyesi daha yüksek. Soyutlamak size kalmış. Asıl ölüm durumunun hiçbir zaman bir yerde depolanması gerekmez. Eğer sağlık değeri <0 ise nesne ölür ve sağlık bileşeni 'davranış yok' demeden veri bit mantığını kapsüllenebilir! Kısıtlama, yalnızca bileşenin durumunu davranış olarak değiştiren şeyleri düşünüyorsanız.
Blecki

Merak ediyorum, bir MovementComponent ile nasıl başa çıkardın? Giriş tespit ettiğinde, PositionComponent'teki hızı arttırması gerekir. Mesaj neye benzerdi?
İpuçları48

8

Bu şekilde Artemis sorunu çözer Bileşenleri İçinde işleme yapmak getirmemektir. Bileşenler yalnızca ihtiyaç duydukları verileri içerir. Sistemler çoklu bileşen tiplerini okur ve ne gerekiyorsa işlem yapar.

Bu nedenle, sizin durumunuzda, HealthComponent'te (ve diğerlerinde) okuyan ve uygun animasyonları sıralayan bir RenderSysteminiz olabilir. Verileri işlevlerden bu şekilde ayırmak, bağımlılıkları uygun şekilde yönetmeyi kolaylaştırır.


Bu, sorunun üstesinden gelmek için iyi bir yoldur: Bileşenler özellikleri temsil ederken, Sistemler birbirinden farklı özellikleri birbirine bağlar ve bunları çalışmak için kullanır. Geleneksel OOP düşüncesinden uzaklaşan çok büyük bir kayma ve bazılarının kafalarını incitiyor =)
Patrick Hughes

Tamam, şimdi gerçekten kayboldum .. "Buna karşılık, bir ES'de, eğer bir savaş alanında 100 birim varsa, her biri bir Varlık tarafından temsil ediliyorsa, o zaman bir birime çağrılabilen her yöntemin sıfır kopyası vardır - çünkü Varlıklar yöntem içermez, Bileşenler de yöntem içermez, Bunun yerine, her bir boyut için harici bir sisteminiz vardır ve harici sistem, bununla uyumlu olduğunu işaret eden Bileşene sahip olan herhangi bir Varlığa çağrılabilecek tüm yöntemleri içerir. sistemi." Bir GunComponent'teki veriler nerede depolanıyor? Mermi vb.
hayer

1
Anladığım kadarıyla, tüm varlıklar aynı bileşeni paylaşmaz, her varlığın kendisine bağlı N bileşeni örneği olabilir. Bir Sistem daha sonra oyunu kendilerine bağlı oldukları önemli örnekleri olan tüm varlıkların bir listesi için sorgular ve bunlar üzerinde ne işlem yaparsa yapsın
Jake Woods

Bu sadece sorunu dolaşıyor. Bir sistem hangi bileşenleri kullanacağını nasıl bilir? Bir sistemin başka sistemlere de ihtiyacı olabilir (StateMachine sistemi örneğin bir animasyon çağırmak isteyebilir). Ancak, DSÖ verisinin sahibi sorunu çözmektedir. Aslında, basit bir uygulama oyun nesnesinde bir sözlük kullanmak olacaktır ve her sistem değişkenlerini orada yaratmaktadır.
ADB

Sorunu etrafta dolaştırıyor ama daha maksadı olan bir yere taşıyor. Sistemler, ilgili bileşenlerine kablolu olarak bağlanmıştır. Sistemler Bileşenler aracılığıyla birbirleriyle iletişim kurabilirler (StateMachine, Animation'ın ne yapacağını (veya bir Olayı ateşleyebileceğini) bilmek için okuduğu bir bileşen değeri ayarlayabilir. Sözlük yaklaşımı da çalışabilecek Özellikler Kalıbı gibi ses çıkarır. Bileşenler, ilgili özelliklerin bir arada gruplandığı ve statik olarak kontrol edilebilecekleridir, tuhaf hatalar yoktur, çünkü bir yere "Dammage" eklediniz, ancak başka bir yerde "Hasar" kullanarak geri almaya çalıştınız
Michael

6

Kodunuzda, nesnenin durumunun değişip değişmediğini öğrenmenin yolları olabilir (onları kullandım, muhtemelen başka yollar da olabilir):

  1. Mesaj gönder.
  2. Bileşenden doğrudan verileri okuyun.

1) Bir Animasyon Bileşeninin eklenip eklenmediğini kontrol edin (Bileşen kodunun içinde veya motor tarafında)

Bunun için kullandım, 1. GameObject'in HasComponent işlevi, veya 2. bileşen eklediğinizde, bazı inşa işlevindeki bağımlılıkları denetleyebilirsiniz veya 3. Bu nesnenin bu bileşene sahip olduğundan emin olduğumda, onu kullanıyorum.

2) Bileşenlerin başka bileşenler gerektirmesini sağlayın, ancak bu bütün bileşen tasarımı ile mücadele ediyor gibi görünüyor.

Okuduğum bazı makalelerde, İdeal sistem bileşenlerinin birbirlerine bağlı olmadıklarını, ancak gerçek hayatta öyle olmadıklarını.

3) Yine, tüm bileşen tasarımı fikri ile mücadele gibi görünen HealthWithAnimationComponent, HealthNoAnimationComponent ve soo gibi yazın.

Bu tür bileşenleri yazmak kötü bir fikirdir. Uygulamamda en bağımsız Sağlık bileşenini oluşturdum. Şimdi abonelere belirli bir olay hakkında bilgi veren bazı gözlemci kalıplarını düşünüyorum (örneğin, "hit", "heal" vb.). Bu yüzden AnimationComponent'in ne zaman animasyon oynayacağına kendisinin karar vermesi gerekir.

Ancak CBES hakkında bir makale okuduğumda beni etkiledi, bu yüzden şimdi CBES'i kullandığımda ve yeni olasılıklar bulduğumda çok mutluyum.


1
Eh, google.no/… @ slayt 16
hayer

@bobenko, lütfen CBES ile ilgili makaleye bir link verin. Ben de onunla çok ilgiliyim;)
Edward83

1
Ve lambdor.net/?p=171 @ dipte, sorumun bir özeti bu tür göreceli karmaşık, temel olmayan bileşenler açısından nasıl farklı işlevler tanımlanabilir? En temel bileşenler nelerdir? Temel bileşenler saf fonksiyonlardan hangi şekilde farklıdır? Mevcut bileşenler yeni bileşenlerden gelen yeni iletilerle otomatik olarak nasıl iletişim kurabilir? Bir bileşenin bilmediği bir mesajı yok saymanın anlamı nedir? Sonuçta girdi-süreç-çıktı modeline ne oldu?
hayer

1
İşte CBES'e iyi cevap: stackoverflow.com/a/3495647/903195 Araştırdığım makalelerin çoğu bu cevaptan geldi. Cowboyprogramming.com/2007/01/05/evolve-your-heirachy ile başladım ve ilham aldım, sonra Gems 5'de (hatırladığım gibi) örneklerle iyi bir yazı vardı.
Yevhen

Fakat işlevsel-reaktif programlama hakkında başka bir konsept ne, benim için bu soru hala açık, ama sizin için olabilir araştırmalar için iyi bir yön.
Yevhen

3

Aynen Michael, Patrick Hughes ve Blecki diyor. Sorunu basitçe dolaşmaktan kaçınmanın çözümü, ilk başta soruna neden olan ideolojiyi terk etmektir.

Daha az OOD ve daha çok İşlevsel Programlama gibi. Bileşen Tabanlı Tasarım ile denemeye başladığımda, bu konuyu yoldan tespit ettim. Biraz daha googledim ve çözüm olarak "Functive Reactive Programming" (Functive Reactive Programming) programını buldum.

Artık benim bileşenim şu anki durumunu tanımlayan değişkenler ve alanlar koleksiyonundan başka bir şey değil. Sonra kendileriyle ilgili tüm bileşenleri güncelleyen bir grup "Sistem" sınıfım var. Reaktif kısım, sistemler iyi tanımlanmış bir sırada çalıştırılarak elde edilir. Bu, işleme ve güncellemesini yapmak için sıradaki sistemin ne olduğunu ve hangi bileşenleri ve varlıkları okumak ve güncellemek istediğini, daima güncel veriler üzerinde çalışmasını sağlar.

Ancak, yine de, sorunun yine de bir kez daha hareket ettiğini iddia edebilirsiniz. Çünkü eğer sistemlerinizin çalıştırılması gereken hangi düzlükte değilse? Döngüsel ilişkiler varsa ve bunun bir if-else karmaşasına bakmadan ve ifadeleri değiştirmeden önce sadece bir zaman meselesi varsa? Bu örtük bir mesajlaşma biçimi, değil mi? İlk bakışta, bunun küçük bir risk olduğunu düşünüyorum. Genellikle, işler sırayla işlenir. Gibi bir şey: Oyuncu Girişi -> Varlık Pozisyonları -> Çarpışma Algılama -> Oyun Mantığı -> Rendering -> Baştan başla. Bu durumda, her biri için bir Sisteminiz olurdu, her bir Sistem'e bir update () yöntemi sağlayın ve ardından bunları gameloop'unuzda sırayla çalıştırın.

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.