Bir şey olduğunda ses çalmanın iyi bir yolu var mı? Kulağa nasıl geliyor?


10

Bu yüzden sınıflarımın çok zaman aldığını monolitik olarak düşünüyordum. Örneğin, Charactersınıfın Jumpyönteminde, bir ses efekti nesnesine bir başvuru olabilir ve bunu çalabilir. Tek başına iyi, ancak fizik, animasyon, çarpışma vb. Göz önüne alındığında, Jump yöntemi büyükleşir ve Charactersınıfın birçok farklı şeye çok bağımlılığı vardır. Yine de, bu iyi olabilir. Ancak, karakter atladığında artık bir ses çalmasını istemezsek ne olur? Şimdi, kodun karmakarışıklığında o belirli kod satırını bulmalı Jumpve yorum yapmalıyız.

Yani .. düşünüyordum ..

Bunun yerine, bir çeşit AudioSystemsınıf olsaydı ve tek yaptığı, diğer sınıflarda ilgilendiği rastgele olaylara abone olmaktı. Örneğin, Charactersınıf yöntemde sınıf içinde Jumpedyükseltilmiş bir olay (herhalde statik de olabilir) olabilir Character. Daha sonra Charactersınıf, karakter atladığında çalınan küçük ses efekti hakkında hiçbir şey bilmez. AudioSystemSadece programcı statik olayların kullanımı yoluyla oyunda gerçekleşmesi belirli olaylarla ses efektleri kanca çekilip verebilecek büyük bir sınıf olacaktır. Çok büyük sahipsek Ardından, gibi alt sınıfları için ayrılmış olabilir EffectsAudioSystem, BackgroundAudioSystem, AmbientAudioSystem, vesaire.

Daha sonra, oyun seçeneklerinde, bu tür sesleri etkinleştirmek veya devre dışı bırakmak için bir onay kutusu olabilir ve yapılması gereken tek şey bu sistemi basit ve tek bir Boole bayrağıyla devre dışı bırakmaktır. Bu sistem fikri, fizik, animasyon, vb. Şeylere, oyuncu eylemlerinden kaynaklanan oyun tepkilerinin çoğunun bu ayrıntılı ve ayrıştırılmış sistemler aracılığıyla bağlandığı noktaya kadar genişletilebilir.

Tamam, bu yüzden sorum biraz belirsiz olabilir, ama bu tür bir şey kulağa nasıl geliyor? Bu tür bir sistem hakkında çok fazla konuşma duymadım. Şimdiye kadar herhangi bir kodlama yapılmadan bunların hepsi kafamda. Belki de "teoride iyi ama pratikte değil" anlaşmalarından biri. Bu tür bir sistem daha büyük bir oyunla çalışır mı yoksa sonunda bozulur ve orijinal sistemden daha fazla spagetti karmaşası haline gelir mi?


5
Kulağa hoş bir fikir gibi geliyor :) (Daha ciddi bir notta: Gevşek bağlanmış alt sistemler / sınıflar arasındaki iletişim için mesajları kullanmak genellikle tasarım açısından iyi bir fikirdir)
bummzack

1
işte böyle yapılıyorsa, oluşturma işleminizi ayrı bir sınıfa da koymalısınız, eğer henüz yapmadıysanız (olduğu gibi, Karakter sınıfında bir draw () işlevine sahip olmamalısınız).
dreta

Yanıtlar:


2

Mesajlar hata ayıklamak ve korumak için cehennemdir. Teoride kulağa hoş geliyor, ancak bir kez uygulamaya konduğunda, çoğaltılmış veri gönderimi çok karışık oluyor. Atlama ses efekti sonunda çok daha fazla veriye ihtiyaç duyacaktır, örneğin pozisyon, hız, karakterin üzerinde bulunduğu malzeme, adını siz koyun, liste sonunda uzun olacak.

Bu nedenle, ya bu verileri toplamanız ve verileri kopyalanan verilerle çok özel bir olay / mesaj yoluyla AudioManager'a göndermeniz gerekir ya da mesajdaki karaktere bir referans gönderirsiniz, böylece AudioManager, verilere erişebilir, yollar dağınık hale gelir ve şimdi ses yöneticisi yer altı malzemesi vb. için bir ses seçmelidir.

Sonuçta belirli olay (sadece bu mesaj için çok özel bir sınıftır) bu sınıfları tekrar derinleştirecektir. Çok fazla kazanılmadı ve sonunda, sadece zaten var olan ve güncel olmayan ve güncel olmayan ve yinelenen verilerin diğer tüm sorunlarından muzdarip olacak çok belirli olayların / sınıfların dağınık büyük bir listesine sahip olacaksınız. .

Bu yüzden, kaynak kodun her tarafına dağılmış olması haricinde, karakter ve AudioManager arasında derin bir bağlantı sağlayan sürdürülmesi gereken çok sayıda gereksiz sınıf listesi olacak. Yalnızca Character- ve AudioManager sınıflarında değil.

Kodunuzu ayırmak için hala iyi bir fikir, ancak Mesajlar gerçekten derin bağlantıların başka bir yoludur. Bazı kodların birleştirilmesi gerekir, bunları birleştirmek için en doğrudan yolu kullanın, fazla mühendislik yapmayın.


1
İyi tasarlanmış bir mesajlaşma sistemi “derin bağlantıların sadece bir başka yolu” nasıldır? Mesaj göndermek, nesneler asla iletişim kurmadan mutlak minimum bağlantıdır. Tasarlama şekliniz sorunlara neden olabilir, ancak sistem yalnızca bir ses, konum ve tür alırsa, tüm sorunlarını çözer ve önerdiğiniz sorunların hiçbirini ortaya çıkarmaz. Ses sistemi hangi sesin gerekli olduğunu hesaplamamalı, tüm ayarları ve tercihen difüzyon sorunlarını soyutlamalıdır. en.wikipedia.org/wiki/Coupling_(computer_programming)
ClassicThunder

1
Mesele şu ki, pratikte bu yaklaşım çok iyi ölçeklenmemektedir. Basit uygulamalar için iyi çalışır ve ihtiyacınız olan tek şey genel bir PlaySoundEvent olduğu sürece. Ancak soru AudioManager'ın özel bir OnJump () - olayını dinlemesiyle ilgilidir, böylece karakter ses işinden kurtulabilir. Bununla birlikte, karakterin sesi seçmesi ve ses çalışmasından kurtulmak için OnJumpEvent'i tanıtmanın orijinal noktasını geçersiz kılan AudioManager'a göndermesi gerektiğinden, bu basit bir PlaySoundEvent için geçerli olmayacaktır.
Maik Semder

1
Bununla birlikte, OnJumpEvent'i kullanırken, olaya karaktere referans eklemeyi veya karakterdeki tüm önemli verileri etkinliğe kopyalamayı seçebilirsiniz. Tabii ki haklısınız, ikincisi derin bir bağlantı getirmeyecek, ancak veri çoğaltma sorunları ve diğer tüm yeni olaylar gibi korunması gereken yeni bir veri geçirme nesnesinden muzdarip olacak.
Maik Semder

1
-1 çünkü bu kadar özel (OnJump) mesajlara sahip olmanın muhtemelen kötü bir fikir olduğunu kabul ederken, kişinin adını alan bir PlaySound olayı yapmasını sağlamak için yararlı bilgiler yerine bu sadece uzun bir 'Hayır bu kötü bir fikir' ses efekti ve 3B konumu ve / veya ses seviyesi ortaya çıktı.
James

@James girdi için teşekkürler, bir PlaySound olayı kullanmak demek istemedim, olayların bir GUI-veritabanı uygulaması için güzel bir soyutlama olduğunu, ancak karmaşık bir oyun için pratik olmadığını söylemek istedim.
Maik Semder

2

Bir mesaj geçiş sisteminin mühendislik üzerinde olduğunu sanmıyorum. Aslında cila aşamasında işlerin yapılmasını önemli ölçüde kolaylaştırabilir. Doğru yapıyorsun!

Açıkladığınız şey, geçen yıl Global Game Jam oyunumuz için birlikte attığım şeydi. SFX'i oluşturmak ve düzenlemek, kendim ve başka bir bestecinin oyuna yazdığı müziği emişsiz bir şekilde entegre etmekten sorumluydum.

Ses yaklaşımı ile bu yaklaşımın en güzel yanı, sesinizle çok daha ilginç şeyler yapmanıza izin vermesidir. Bir oyundaki ses efektinin yalnızca bir ses dosyası, ses seviyesi ve yatay kaydırma olduğunu düşünüyorsanız, yanlış yapıyorsunuz demektir.

Misal

Oyunumuz için puan kazanmak için gezegenlere koşan bir uzay gemisini uçan bir dinozortunuz. Flash'ta çalışıyorduk, bu nedenle veri odaklı bir altyapıya gerek yoktu. AudioManager, tek amacı bir oyun etkinliğine yanıt olarak seslerin ne olduğunu kontrol etmek olan bir dizi statik yöntemden oluşan bir sınıftı.

C ++ ile yazacak olsaydım, seslerin sahip olabileceği tüm olası davranışları soyutlamak biraz daha zaman alacaktı. Sisteme bir eylemin gerçekleştiğini bildiren bir mesaj için gereklilikler çok karmaşık olmayacaktır. Sadece mesaj türüne, etkilenen köken nesnesine veya nesneye, bir tür oyun durumu bağlamına erişmeye ve başka bir şeye değil. Oyunun ihtiyaçları arttıkça protokol de büyüyebilir. Doğal olarak, tüm bunları kodda uygulamada yaparsanız (kalitesiz GGJ kodumuz gibi), daha kötü bir monolitik sınıf probleminiz var. Ancak bu, veri odaklı bir sistem oluşturarak kolayca hafifletilebilir.

Her neyse, oyun ses sistemimiz çeşitli mesajlara nasıl tepki verdi:

  • Oyuncu gezegenle çarpışır: Bu yeterince basit bir gezegen patlama sesi tetikler. hemen sonra çalışan açılan sayacı sorgulayacaktır. Yeterince yüksek olsaydı, dinozorun yarım saniye kadar sonra bir zafer kükremesi yapmak için bir ses efekti planlayacaktı. Ayrıca arka planda rastgele bir gezegen popülasyon değeri hesaplandı (600 ila 3000 gibi bir şey - bu aralığın neden seçildiğine dair hiçbir fikrim yok, bazı terk edilmiş oyun mekaniği ve sesi ilginç hale getirmek için hala etrafta yatıyordu), ve ben de bunu çığlıkların uzak sesinin hacmini ölçeklendirmek için kullandım (gezegensel vatandaşlar zamansız bir kadere rastlar).

  • Oyuncu ivme için boşluk çubuğu tutar: Bunu aldıktan sonra küçük bir "whoosh" itici sesi çalındı, ancak aynı zamanda düşük döngülü bir motor kükreme de 1,5 saniyeden fazla arttı. Parçacık sistemi bunu bir yayıcı IIRC'yi ateşlemek için de kullandı

  • Oyuncu yavaşlama için boşluk çubuğunu bırakıyor: Artık oyuncu boşluk çubuğunu bıraktığına göre, ses sistemi motor döngüsünü geri indirmesi gerektiğini biliyordu. Eğer daha fazla zamanım olsaydı, bir tür sesi aşağılamak gibi bir ses daha katmanlaştırmak isterdim.

  • Oyuncu kötü uzay madeni ile çarpışır: Uzay mayınları kötüdür, bu yüzden sadece bir patlama ile birleştirilmiş metalik bir darbe sesi değil (sadece bir ses haline getirilir), aynı zamanda rastgele seçilen bir dinozor dehşet sesi de çalınır. Oyuncunun sağlığı azaldıkça daha çok "ağlayan" sesleri seçmek daha olasıdır.

Zaten eğlenceli bir oyun, müziği aktif ve dinamik olduğunda, yukarıda tarif ettiğim gibi sadece küçük basit davranışlarla bile çalmak için bir zevk haline geliyor. Evet, doğru verilerin iletildiğinden emin olmak için çalışmak için bazı lojistikler var. Ama hey, BFD. Oyun kodunun daha geniş kapsamında yazmak zorunda olduğunuz en karmaşık şeyden çok uzak olacak.

Aslında, FMOD ve Wwise böyle çalışır. Merkezi bir mesaj dağıtıcısı yoktur, ancak olayları merkezi sistemlerine etkili bir şekilde gönderirsiniz ve bir yazma aracında bir ses uygulayıcısı tarafından önceden tasarlanmış bir ses efekti çalarak tepki verirler. Oyununuza canlı bir DJ vermek gibi düşünün. Olanları izler ve olup bitenleri izler ve işleri ilginç tutmak için ses kliplerini doğru zamanlarda tetikler, bunları önceden mevcut ses ortamına iyi uymaları için karıştırır.

[EDIT] Ayrıca, bu C # etiketlendiğini görüyorum. Bu XNA mı, eğer öyleyse XACT kullanıyor musunuz? XNA kullanıyorsanız, XACT kullanıyor olmalısınız.


1
Bu küçük bir proje için işe yarayabilir, hatta eğlenceli bile olabilir. Bununla birlikte, büyük bir tanesinde, bakımı gereken çok sayıda mesaj sınıfıyla karşılaşırsınız, oysa basit bir işlev çağrısı aynı etkiye sahip olurdu. Bu nedenle etkinlik sistemi iyi ölçeklenmiyor, proje büyüdükçe yönetmek zorlaşıyor.
Maik Semder

1
Stüdyomda FMOD ile çalıştığımızda, mesaj / olay sistemi yok, FMOD'a olay göndermiyorsunuz, sadece bir şey oynamak için c-fonksiyonunu veya c ++ yöntemini çağırıyorsunuz. Sadece seslerini "olaylar" olarak adlandırırlar, bu onu bir olay sistemi yapmaz, sadece ses yerine kullandıkları terimdir.
Maik Semder

Hayır neden? Parametreleri iletmek için bir olay kullanmak yerine işlevi doğrudan çağırırsınız. Bir olay sonunda işlev çağrısı olarak başka bir şey değildir, parametreleri doğrudan olay nesnesine iletmek yerine doğrudan olay nesnesine iletir. Tek fark, olay sistemi tarafından sunulan yeni dolaylamadır, ancak sonunda basit bir işlev çağrısıdır, sadece gereksiz yere aşırı karmaşıktır.
Maik Semder

@MaikSemder Yöntem çağrıları kendi karışıklık ağlarına nasıl ulaşmaz? Ayrıca, bir olay sistemi ile Wwise ve FMOD tarafından kullanılan "olaylar" arasındaki ayrımı not etmeye çalıştım. Anlaştığım fikir, karmaşık ses mantığının oyun nesnesi sınıflarına ait olmaması ve ses mantığını, arayüzün bir olay göndermeye benzeyecek şekilde soyutlaması, zengin ses mantığına sahip olmayı kolaylaştırıyor. Gerçekten arasında çok az işlevsel farkı görmek EventManager->dispatch("Sound:PlayerJump")ve soundSystem->playFMODEvent("/MyGame/Player/Jump").
michael.bartnett

2
Daha kolay kodlamanın yararı olabilir, ancak ücretsiz değildir, performans, bakım ve daha zor hata ayıklama maliyetleri ile birlikte gelir. Demek istediğim, büyük projeler için faydaya değmez. Olay olmadan daha fazla nesne ile ilgileniyor ve bunun bedelini ödemek zorunda. Mesaj sistemi kullanmayı düşünebileceğim tek yer, iş parçacıkları arasında kilitlenmeyi önlemek için iş parçacıkları arası iletişim içindir.
Maik Semder

0

Maik Semder ile bir mesaj geçiş sisteminin aşırı mühendislik olabileceğini kabul ediyorum (şimdilik).

Anladığım kadarıyla, sınıfınız şu anda burada "A monolitik bir sınıfta" görüldüğü gibi Bjorn "monolitik sınıfına" benziyor. .

Bu makaleyi okumanızı öneriyorum ve tam bileşenli bir sistem şimdilik aşırıya kaçmış olsa da, "Gerisini bölmek" konusunu okursanız, bu size davranışlarınızı soyutlamak ve sonunda daha karmaşık bir hale gelmek için iyi bir yol vermelidir. çözüm. Yine de başlamak için iyi bir temel verecektir.

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.