Tenho andado a pensar nos fundamentos de um mecanismo de jogo Java e cheguei ao ponto em que estou pronto para adicionar um sistema do Event Manager.
Eu sei, em teoria , o que um gerente de eventos deve fazer: permitir que objetos sejam "registrados" para determinados eventos e, sempre que o gerente de eventos for notificado de um evento, transmita o evento para os ouvintes "registrados". O que me surpreende é como começar a implementá-lo.
Não consegui encontrar nada, on-line, sobre a implementação de um sistema de eventos do zero, por isso estou procurando informações sobre quais são as melhores práticas neste caso - o que devo ou não fazer.
Por exemplo, é realmente necessário que cada um dos meus objetos de jogo tenha um EventManager
campo? Como todos os meus objetos de jogo são herdados de uma única classe-mãe abstrata, acho que devo usar uma referência estática para que haja apenas uma instância do Gerenciador de Eventos, compartilhada entre todos os objetos de jogo. Faço algo semelhante, com o Applet, que já uso para renderizar cada objeto.
Suponho que eu teria que manter uma coleção de algum tipo para cada possível evento inscrito - adicionando e removendo objetos de jogo da lista, conforme necessário. Eu acho que deveria ser possível criar uma fila de eventos que precisam ser transmitidos; nesse caso, eu poderia simplesmente adicionar "EventManager.Update ()" ao loop principal do jogo e fazer com que o Update()
método transmitisse os eventos que ocorreram no final de cada quadro. Por fim, cada objeto teria um HandleEvent(Event e)
método, ao qual eles poderiam analisar e responder adequadamente.
Isso soa como a direção apropriada para a implementação de um sistema desse tipo, ou estou fora do caminho e / ou estou perdendo algo bastante óbvio?
Respostas:
Isso pode ser tão simples quanto você quiser.
Não tente descobrir o que um gerente de eventos deve fazer - calcule o que você precisa fazer. O resto deve seguir a partir daí, ou pelo menos, deve sugerir algumas perguntas mais específicas.
fonte
Os três métodos essenciais de que um sistema de eventos precisa são os métodos addListener (), removeListener () e um método para dispatchEvent (). Ou seja, os objetos de método usam para registrar um evento, os objetos de método usam para cancelar o registro e um método para realmente transmitir um evento para todos os ouvintes. Tudo o resto é molho.
Como você observa, certamente precisará de algum tipo de estrutura de dados para acompanhar os ouvintes registrados. A abordagem mais simples seria uma matriz associativa (dicionário ou um objeto em JavaScript) que associa um vetor (ou simplesmente uma matriz, dependendo do idioma) a um evento. Esse vetor é uma lista de todos os ouvintes registrados; adicione ouvintes à lista ou remova-os nos métodos add / removeListener ().
Para transmitir um evento em dispatchEvent (), pode ser tão simples quanto percorrer o vetor. Você pode adicionar mais complexidade ao envio, classificando a prioridade dos eventos ou o que quer que seja, mas não se preocupe com isso até precisar. Em muitos casos, você não precisará disso.
Há um pouco de nuance para dispatchEvent () quando você considera quais dados passar junto com o evento. No nível mais básico, você pode não transmitir dados adicionais; tudo o que o ouvinte precisa saber é que ocorreu um evento. No entanto, a maioria dos eventos possui dados adicionais que os acompanham (por exemplo, onde o evento aconteceu), para que o dispatchEvent () aceite e repasse alguns parâmetros.
Existem várias maneiras de fornecer uma referência a todos os objetos do jogo na classe EventManager. Uma referência estática é certamente uma maneira; outro é com um Singleton. No entanto, essas duas abordagens são bastante inflexíveis; portanto, a maioria das pessoas por aqui recomenda um localizador de serviço ou uma injeção de dependência. Eu tenho feito injeção de dependência; isso significa um campo separado do EventManager para cada objeto, o que você parece querer evitar, mas não sei ao certo por que isso é um problema. Não é como se houvesse muita sobrecarga ao armazenar vários ponteiros.
fonte
Os princípios básicos da manipulação de eventos são bastante simples.
Sabendo disso (mas não sabendo como implementá-lo em Java), é fácil entender que você precisa de alguns manipuladores (funções para manipular os eventos) e adicioná-los a uma matriz (com ponteiros, em C) emparelhada com um nome de evento. Depois de acionar um evento, você armazena o nome do evento acionado e seus argumentos em uma pilha, isso é chamado de pool de eventos.
Então você tem um resumo do evento (um loop simples), que exibe o primeiro evento nessa pilha, tenta encontrar um manipulador para ele e, se houver algum, o executa com os parâmetros.
Obviamente, esse resumo de eventos pode ser acionado sempre que você desejar, por exemplo, uma vez por quadro depois de chamar sua
Update()
função.fonte
Para o campo EventManager, use uma variável estática. Um Singleton para o EventManager também seria uma ótima idéia.
Sua abordagem parece boa, mas não se esqueça de torná-la segura para threads.
É bom executar eventos de IO antes ou depois dos "GameEvent" s, portanto, em um quadro, cada "GameEvent" lida com os mesmos dados.
fonte