Estou fazendo um jogo simples e decidi tentar implementar um sistema de mensagens.
O sistema basicamente se parece com isso:
A entidade gera a mensagem -> a mensagem é postada na fila de mensagens global -> messageManager notifica todos os objetos da nova mensagem através de onMessageReceived (Message msg) -> se o objeto desejar, ele atua na mensagem.
A maneira como estou criando objetos de mensagem é assim:
//base message class, never actually instantiated
abstract class Message{
Entity sender;
}
PlayerDiedMessage extends Message{
int livesLeft;
}
Agora meu SoundManagerEntity pode fazer algo assim no método onMessageReceived ()
public void messageReceived(Message msg){
if(msg instanceof PlayerDiedMessage){
PlayerDiedMessage diedMessage = (PlayerDiedMessage) msg;
if(diedMessage.livesLeft == 0)
playSound(SOUND_DEATH);
}
}
Os profissionais dessa abordagem:
- Muito simples e fácil de implementar
- A mensagem pode conter as informações que você desejar, porque você pode apenas criar uma nova subclasse de Mensagens com as informações necessárias.
Os contras:
- Não consigo descobrir como reciclar objetos Message para um pool de objetos , a menos que eu tenha um pool diferente para cada subclasse de Message. Portanto, tenho imensas criações de objetos / alocação de memória ao longo do tempo.
- Não consigo enviar uma mensagem para um destinatário específico, mas ainda não precisei disso no meu jogo, por isso não me importo muito.
O que estou perdendo aqui? Deve haver uma implementação melhor ou alguma idéia que estou perdendo.
architecture
messaging
object-pools
you786
fonte
fonte
Respostas:
Resposta simples é que você não deseja reciclar mensagens. Recicla-se objetos que são criados (e removidos) por milhares a cada quadro, como partículas, ou são muito pesados (dezenas de propriedades, longo processo de inicialização).
Se você tiver uma partícula de neve com alguns bitmap, velocidades e atributos físicos associados que ficaram abaixo da sua visualização, convém reciclá-la em vez de criar uma nova partícula e inicializar novamente o bitmap e os atributos aleatórios. No seu exemplo, não há nada útil na Mensagem para mantê-lo, e você desperdiçará mais recursos removendo suas propriedades específicas da instância do que apenas criando um novo objeto Message.
fonte
No meu jogo baseado em Java, eu vim com uma solução muito semelhante, exceto que meu código de manipulação de mensagens se parece com o seguinte:
Uso anotações para marcar um método como manipulador de eventos. Então, no início do jogo, uso a reflexão para calcular um mapeamento (ou, como chamo, "canalização") de mensagens - qual método chamar em qual objeto quando um evento de uma classe específica é enviado. Isso funciona ... incrível.
O cálculo da tubulação pode ficar um pouco complicado se você quiser adicionar interfaces e subclasses à mistura, mas é bastante simples, no entanto. Há uma ligeira desaceleração durante o carregamento do jogo, quando todas as classes precisam ser verificadas, mas isso é feito apenas uma vez (e provavelmente pode ser movido para um thread separado). O que se ganhou é que o envio real de mensagens é mais barato - não preciso invocar todos os métodos "messageReceived" na base de código apenas para verificar se o evento é de boa classe.
fonte
EDIT A resposta da Liosan é mais sexy. Olhe para isso.
Como Markus disse, as mensagens não são um candidato comum para pools de objetos. Não se preocupe com isso pelas razões que ele mencionou. Se o seu jogo enviar toneladas de mensagens de tipos específicos, talvez valha a pena. Mas, nesse momento, sugiro que você mude para chamadas de método diretas.
Falando nisso,
Se você conhece um destinatário específico para o qual deseja enviá-lo, não seria muito fácil obter uma referência a esse objeto e fazer uma chamada direta de método? Você também pode ocultar objetos específicos por trás das classes de gerenciador para facilitar o acesso entre os sistemas.
Há um problema na sua implementação, e é que existe o potencial de muitos objetos receberem mensagens com as quais eles realmente não se importam. Idealmente, suas aulas receberiam apenas mensagens com as quais realmente se importam.
Você pode usar um
HashMap<Class, LinkedList<Messagable>>
para associar tipos de mensagens a uma lista de objetos que desejam receber esse tipo de mensagem.A inscrição em um tipo de mensagem seria algo como isto:
Você pode implementar
subscribe
dessa maneira (perdoe-me alguns erros, não escrevo java há alguns anos):E então você pode transmitir uma mensagem como esta:
E
broadcastMessage
poderia ser implementado assim:Você também pode assinar a mensagem de maneira que possa dividir seu tratamento de mensagens em diferentes funções anônimas:
É um pouco detalhado, mas ajuda na organização. Você também pode implementar uma segunda função,
subscribeAll
que manterá uma lista separada deMessagable
s que desejam ouvir sobre tudo.fonte
1 . Não.
As mensagens são de baixo custo. Eu concordo com Markus von Broady. O GC os coletará rapidamente. Tente não anexar muitas informações adicionais às mensagens. São apenas mensagens. Encontrar instância de é uma informação por si só. Use-o (como você fez no seu exemplo).
2 . Você pode tentar usar o MessageDispatcher .
Ao contrário da primeira solução, você poderia ter o despachante centralizado de mensagens que processa as mensagens e as passa para os objetos pretendidos.
fonte