Así que estaba pensando en cuán monolíticas mis clases se vuelven mucho tiempo. Por ejemplo, en el método de la Character
clase Jump
, uno puede tener una referencia a un objeto de efecto de sonido y reproducirlo. Eso en sí mismo está bien, pero cuando se tiene en cuenta la física, la animación, la colisión, etc., el método Jump se vuelve enorme y la Character
clase tiene muchas dependencias para muchas cosas diferentes. Aún así, esto puede estar bien. Sin embargo, ¿qué pasa si ya no queremos que suene un sonido cuando el personaje salta? Ahora, tenemos que encontrar esa línea específica de código en la confusión del Jump
código y comentarlo o lo que sea.
Entonces ... estaba pensando ...
¿Qué pasa si, en cambio, hubo algún tipo de AudioSystem
clase y todo lo que hizo fue suscribirse a eventos aleatorios que le interesan en otras clases? Por ejemplo, la Character
clase puede tener un Jumped
evento (también estático, supongo) que se genera dentro de la Character
clase en el método. Entonces, la Character
clase no sabría nada sobre el pequeño efecto de sonido que se reproduce cuando el personaje salta. El AudioSystem
no sería más que una clase enorme que el programador podría retirarse a conectar efectos de sonido con ciertos acontecimientos que suceden en el juego a través del uso de eventos estáticos. Entonces, si se hacía demasiado grande que podría ser separado en las subclases como EffectsAudioSystem
, BackgroundAudioSystem
, AmbientAudioSystem
, etcétera.
Luego, en las opciones para el juego, uno podría tener una casilla de verificación para habilitar o deshabilitar este tipo de sonidos y todo lo que tendría que hacer es deshabilitar ese sistema con una bandera booleana simple y única. Esta idea de los sistemas también podría extenderse a cosas como la física, las animaciones, etc., hasta el punto en que la mayoría de las respuestas del juego resultantes de las acciones de los jugadores se conectan a través de estos sistemas elaborados y desacoplados.
Bien, entonces mi pregunta puede ser un poco vaga, pero ¿cómo suena este tipo de cosas? Realmente nunca he oído hablar mucho sobre este tipo de sistema. Todo esto está en mi cabeza en este momento sin ninguna codificación realizada hasta ahora, por lo que tal vez sea uno de esos tipos de acuerdos "buenos en teoría pero no en la práctica". ¿Funcionaría este tipo de sistema con un juego más grande?
fuente
Respuestas:
Los mensajes son un infierno para depurar y mantener. Suena bien en teoría, pero una vez que se pone en práctica se vuelve complicado con un montón de datos duplicados que se envían. El efecto de sonido de salto necesitará muchos más datos al final, por ejemplo, la posición, la velocidad, el material en el que se encuentra el personaje, lo que sea, la lista será larga al final.
Por lo tanto, deberá recopilar estos datos y enviarlos al AudioManager a través de un evento / mensaje muy específico con los datos copiados, o enviará una referencia al personaje en el mensaje, para que el AudioManager pueda acceder a los datos, tanto las formas terminan siendo desordenadas, y ahora el administrador de audio tiene que elegir un sonido para el material subterráneo, etc.
Entonces, al final, el evento específico (que es una clase muy específica solo para este mensaje) volverá a acoplar esas clases muy profundamente. No ganó mucho y al final tendrá una gran lista desordenada de eventos / clases muy específicos que solo sirven para enviar datos, que ya existen y que pueden estar desactualizados y sufrirán todos los demás problemas de datos duplicados .
Por lo tanto, habrá una gran lista de clases innecesarias para mantener que introducen un acoplamiento profundo entre el personaje y el AudioManager, excepto que ahora está disperso por todo el código fuente. No solo en las clases Character y AudioManager.
Sigue siendo una buena idea desacoplar su código, pero los mensajes son realmente otra forma de acoplamientos profundos. Algunos códigos solo tienen que estar acoplados, use la forma más directa para acoplarlos, no haga demasiados ingenieros.
fuente
No creo que un sistema de transmisión de mensajes haya terminado la ingeniería. De hecho, puede hacer que sea mucho más fácil hacer las cosas en la fase de pulido. ¡Lo estás haciendo bien!
Lo que describiste es exactamente lo que reuní para nuestro juego Global Game Jam el año pasado. Fui responsable de crear y editar el SFX, e integrar la música que yo y otro compositor escribimos en el juego de una manera que no apestaba.
Lo bueno de este enfoque desde una perspectiva de audio es que te permite hacer muchas cosas más interesantes con tu sonido. Si crees que un efecto de sonido en un juego es simplemente un archivo de sonido, volumen y panorámica, entonces lo estás haciendo mal.
Ejemplo
Para nuestro juego, eras un dinosaurio volando una nave espacial que se topaba con planetas para ganar puntos. Estábamos trabajando en Flash, por lo que no era necesaria una infraestructura basada en datos. El AudioManager era una clase que constaba de un montón de métodos estáticos cuyo único propósito era controlar qué sonidos ocurrían en respuesta a un evento del juego.
Si lo escribiera en C ++, me habría llevado un poco más de tiempo abstraer todos los comportamientos posibles que podrían tener los sonidos. Los requisitos para un mensaje que notifique al sistema que se ha llevado a cabo una acción no serían demasiado complicados. Solo necesitaría el tipo de mensaje, el objeto de origen o el objeto afectado, el acceso a algún tipo de contexto de estado del juego y no mucho más. El protocolo podría crecer a medida que crecen las necesidades del juego. Naturalmente, si hace todo esto en la implementación en código (como nuestro código GGJ de mala calidad), tiene un problema de clase monolítico peor. Pero eso se mitiga fácilmente al crear un sistema basado en datos.
De todos modos, así es como nuestro sistema de audio del juego reaccionó a varios mensajes:
El jugador choca con el planeta: esto provocaría un sonido de explosión planetaria, lo suficientemente básico. luego, inmediatamente después de consultar el contador combinado en ejecución. Si fuera lo suficientemente alto, programaría un efecto de sonido que se reproduciría medio segundo más o menos después de que el dinosaurio hiciera un rugido de victoria. También en el fondo se calculó un valor aleatorio de la población del planeta (algo así como 600 a 3000; no tengo idea de por qué se eligió ese rango, era una mecánica de juego abandonada y todavía estaba por ahí para que yo use para hacer que el audio sea interesante), así que usé eso para escalar el volumen del sonido distante de los gritos (ciudadanos planetarios que se encuentran con un destino inoportuno).
El jugador tiene la barra espaciadora para la aceleración: al recibir esto, se escuchó un pequeño sonido de propulsor "whoosh", pero también simultáneamente un rugido de motor de bucle bajo aumentó durante 1.5 segundos. El sistema de partículas también usó esto para disparar un emisor IIRC
El jugador suelta la barra espaciadora para desacelerar: ahora que el jugador había soltado la barra espaciadora, el sistema de audio sabía que tenía que volver a bajar el circuito del motor. Si tuviera más tiempo, me hubiera gustado superponer otro sonido que fuera una especie de sonido quejumbroso.
El jugador choca con la mina espacial malvada: las minas espaciales son malas, por lo que no solo hay un sonido de impacto metálico combinado con una explosión (que se convierte en un solo sonido), sino que también se reproduce un sonido de consternación de dinosaurio seleccionado al azar. Es más probable que elija más sonidos de "llanto" a medida que la salud del jugador disminuye.
Un juego ya divertido se convierte en un placer jugar cuando su banda sonora es activa y dinámica, incluso con comportamientos simples como los que describí anteriormente. Sí, hay algo de logística con la que asegurarse de que se pasen los datos correctos. Pero bueno, BFD. Estará lejos de ser lo más complicado que tiene que escribir en el alcance más amplio del código del juego.
De hecho, FMOD y Wwise funcionan así. No tienen un despachador de mensajes central, pero efectivamente publica eventos en sus sistemas centrales y reaccionan al reproducir un efecto de sonido que fue diseñado previamente por un implementador de audio en una herramienta de autoría. Piense en ello como darle a su juego un DJ en vivo. Se sienta y observa lo que está sucediendo, y activa clips de sonido en los momentos correctos para mantener las cosas interesantes, mezclándolas para que encajen bien en el entorno de audio preexistente.
[EDITAR] Además, veo que has etiquetado este C #. ¿Es esto XNA, y si es así, estás usando XACT? Si está utilizando XNA, debería estar utilizando XACT.
fuente
EventManager->dispatch("Sound:PlayerJump")
ysoundSystem->playFMODEvent("/MyGame/Player/Jump")
.Estoy de acuerdo con Maik Semder, en que un sistema de paso de mensajes puede ser una ingeniería excesiva (de todos modos, por ahora).
Por lo que entiendo, su clase actualmente se parece a la "clase monolítica" de Bjorn como se puede ver en "Una clase monolítica" aquí .
Le sugiero que lea ese artículo y, aunque un sistema de componentes completos sería excesivo por ahora, si lee "Separar el resto", eso debería darle una buena forma de abstraer sus comportamientos y, finalmente, quizás pasar a un sistema más complejo solución. Le dará una buena base para comenzar de todos modos.
fuente