Então, eu estava pensando em quão monolíticas minhas aulas ficam a maior parte do tempo. Por exemplo, no método Character
da classe Jump
, pode-se ter uma referência a um objeto de efeito sonoro e tocá-lo. Por si só, isso é bom, mas quando a física, a animação, a colisão etc. são levadas em consideração, o método Jump se torna imenso e a Character
classe tem muitas dependências para muitas coisas diferentes. Ainda assim, isso pode ser bom. No entanto, e se não quisermos mais tocar um som quando o personagem pular? Agora, temos que encontrar essa linha específica de código na bagunça confusa do Jump
código e comentar ou algo assim.
Então .. eu estava pensando ..
E se, em vez disso, houvesse algum tipo de AudioSystem
classe e tudo o que ele fizesse fosse se inscrever em eventos aleatórios nos quais ela se interessa por outras classes. Por exemplo, a Character
classe pode ter um Jumped
evento (também estático, suponho) que é gerado dentro da Character
classe no método Então, a Character
classe não saberia nada sobre o pequeno efeito sonoro que é reproduzido quando o personagem pula. A AudioSystem
seria apenas uma enorme classe que o programador poderia retirar-se para ligar efeitos sonoros com certos eventos que acontecem no jogo através do uso de eventos estáticos. Então, se ele ficou muito grande que poderia ser separados em subclasses, como EffectsAudioSystem
, BackgroundAudioSystem
, AmbientAudioSystem
, et cetera.
Então, nas opções do jogo, pode-se ter uma caixa de seleção para ativar ou desativar esse tipo de som e tudo o que precisa ser feito é apenas desativar esse sistema com uma bandeira booleana simples e única. Essa idéia de sistemas também pode ser estendida a coisas como física, animações etc. até o ponto em que a maioria das respostas ao jogo resultantes das ações dos jogadores são conectadas por esses sistemas elaborados e dissociados.
Ok, então minha pergunta pode ser um pouco vaga, mas como isso soa? Eu realmente nunca ouvi falar de muito tipo de conversa sobre esse tipo de sistema. Isso está na minha cabeça agora, sem qualquer codificação feita até agora, talvez seja um daqueles acordos "bons em teoria, mas não na prática". Esse tipo de sistema funcionaria com um jogo maior ou acabaria quebrando e se tornando ainda mais uma bagunça de espaguete do que o sistema original?
fonte
Respostas:
As mensagens são um inferno para depurar e manter. Parece bom em teoria, mas, uma vez colocado em prática, fica confuso com o envio de muitos dados duplicados. O efeito de salto-som precisará de muito mais dados no final, por exemplo, a posição, velocidade, material em que o personagem está, você escolhe, a lista será longa no final.
Portanto, você precisará coletar esses dados e enviá-los ao AudioManager por meio de um evento / mensagem muito específico com os dados nele copiados ou enviar uma referência ao caractere na mensagem, para que o AudioManager possa acessar os dados, ambos as maneiras acabam bagunçadas, e agora o gerenciador de áudio precisa escolher um som para o material underground, etc.
Portanto, no final, o evento específico (que é uma classe muito específica apenas para esta mensagem) reunirá essas classes muito profundamente novamente. Não ganhou muito e, no final, você terá uma grande lista bagunçada de eventos / classes muito específicos que servem apenas ao propósito de enviar dados, que já existem e podem estar desatualizados e sofrerão com todos os outros problemas de dados duplicados. .
Portanto, haverá uma enorme lista de classes desnecessárias a serem mantidas, que introduzem um profundo acoplamento entre o personagem e o AudioManager, mas agora ele está espalhado por todo o código-fonte. Não apenas nas classes Character e AudioManager.
Ainda é uma boa idéia desacoplar seu código, mas as Mensagens são realmente apenas uma outra maneira de acoplamentos profundos. Alguns códigos precisam ser acoplados, use a maneira mais direta de combiná-los, não exagere na engenharia.
fonte
Eu não acho que um sistema de transmissão de mensagens tenha acabado com a engenharia. De fato, pode tornar muito mais fácil fazer as coisas na fase de polimento. Você está fazendo isso certo!
O que você descreveu é exatamente o que reuni para o nosso jogo Global Game Jam no ano passado. Eu era responsável por criar e editar o SFX, e integrar a música que eu e outro compositor escrevemos no jogo de uma maneira que não era ruim.
O que é ótimo nessa abordagem do ponto de vista de áudio é que ela permite fazer muitas coisas mais interessantes com o seu som. Se você acha que um efeito sonoro em um jogo é apenas um arquivo de som, volume e movimento panorâmico, está fazendo errado.
Exemplo
Para o nosso jogo, você era um dinossauro pilotando uma nave espacial correndo em planetas para marcar pontos. Como estávamos trabalhando no Flash, não era necessária uma infraestrutura orientada a dados. O AudioManager era uma classe que consistia em vários métodos estáticos cujo único objetivo era controlar quais sons aconteciam em resposta a um evento do jogo.
Se eu escrevesse em C ++, levaria um pouco mais de tempo para abstrair todos os comportamentos possíveis que os sons poderiam ter. Os requisitos para uma mensagem notificando o sistema em que uma ação ocorreu não seriam muito complicados. Seria necessário apenas o tipo de mensagem, o objeto de origem ou o objeto afetado, o acesso a algum tipo de contexto do estado do jogo e não muito mais. O protocolo pode crescer conforme as necessidades do jogo. Naturalmente, se você fizer tudo isso na implementação em código (como nosso código GGJ de má qualidade), terá um problema de classe monolítica pior. Mas isso é facilmente mitigado ao criar um sistema orientado a dados.
De qualquer forma, veja como nosso sistema de áudio do jogo reagiu a várias mensagens:
O jogador colide com o planeta: Isso provocaria um som de explosão do planeta, bastante básico. imediatamente após consultar o contador de combinação em execução. Se fosse alto o suficiente, agendaria um efeito sonoro para ser tocado meio segundo depois do dinossauro fazer um rugido de vitória. Também em segundo plano, foi calculado um valor aleatório da população do planeta (algo como 600 a 3000 - não sei por que esse intervalo foi escolhido, era uma mecânica de jogo abandonada e ainda estava por aí para eu usar para tornar o áudio interessante), e então eu usei isso para dimensionar o volume do som distante dos gritos (cidadãos planetários encontrando um destino prematuro).
O jogador mantém a barra de espaço para aceleração: ao receber isso, um pequeno som de propulsor foi tocado, mas também simultaneamente um rugido baixo do motor em loop aumentou 1,5 segundos. O sistema de partículas também usou isso para disparar um emissor IIRC
O player solta a barra de espaço para desacelerar: Agora que o player soltou a barra de espaço, o sistema de áudio sabia que tinha que acelerar o ciclo do motor. Se eu tivesse mais tempo, teria gostado de colocar outro som sobre ele, que era uma espécie de som lamentável.
O jogador colide com a mina espacial do mal: as minas espaciais são ruins, então não apenas existe um som de impacto metálico combinado com uma explosão (que é apenas um som), mas também há um som de desânimo de dinossauro selecionado aleatoriamente. É mais provável que escolha mais sons de "choro" à medida que a saúde do jogador diminui.
Um jogo já divertido se torna uma delícia de jogar quando sua trilha sonora é ativa e dinâmica, mesmo com apenas alguns comportamentos simples, como eu descrevi acima. Sim, há alguma logística para resolver, garantindo que os dados corretos sejam transmitidos. Mas ei, BFD. Isso está longe de ser a coisa mais complicada que você precisa escrever no escopo maior do código do jogo.
De fato, FMOD e Wwise funcionam assim. Eles não têm um distribuidor de mensagens central, mas você efetivamente publica eventos em seus sistemas centrais e eles reagem tocando um efeito sonoro que foi pré-projetado por um implementador de áudio em uma ferramenta de autoria. Pense nisso como dar ao seu jogo um DJ ao vivo. Ele senta e assiste o que está acontecendo, e aciona clipes de som nos momentos certos para manter as coisas interessantes, misturando-as para que se encaixem bem no ambiente de áudio preexistente.
[EDIT] Além disso, vejo que você marcou este C #. É este XNA e, em caso afirmativo, você está usando o XACT? Se você estiver usando o XNA, deverá usar o XACT.
fonte
EventManager->dispatch("Sound:PlayerJump")
esoundSystem->playFMODEvent("/MyGame/Player/Jump")
.Concordo com Maik Semder, que um sistema de transmissão de mensagens pode estar com excesso de engenharia (por enquanto, pelo menos).
Pelo que entendi, sua classe atualmente se parece com a "classe monolítica" de Bjorn, como pode ser visto em "Uma classe monolítica" aqui .
Sugiro que você leia esse artigo e, embora um sistema de componentes completos seja um exagero por enquanto, se você ler "Dividir o resto", isso deve lhe dar uma boa maneira de abstrair seus comportamentos e, eventualmente, talvez mudar para um mais complexo solução. Isso lhe dará uma boa base para começar de qualquer maneira.
fonte