Estoy haciendo un juego simple y he decidido intentar implementar un sistema de mensajería.
El sistema básicamente se ve así:
La entidad genera el mensaje -> el mensaje se publica en la cola de mensajes global -> messageManager notifica a cada objeto del nuevo mensaje a través de onMessageReceived (Message msg) -> si el objeto lo desea, actúa sobre el mensaje.
La forma en que estoy creando objetos de mensaje es así:
//base message class, never actually instantiated
abstract class Message{
Entity sender;
}
PlayerDiedMessage extends Message{
int livesLeft;
}
Ahora mi SoundManagerEntity puede hacer algo como esto en su método onMessageReceived ()
public void messageReceived(Message msg){
if(msg instanceof PlayerDiedMessage){
PlayerDiedMessage diedMessage = (PlayerDiedMessage) msg;
if(diedMessage.livesLeft == 0)
playSound(SOUND_DEATH);
}
}
Los pros de este enfoque:
- Muy simple y fácil de implementar.
- El mensaje puede contener tanta información como desee, ya que puede crear una nueva subclase de mensaje que tenga la información necesaria.
Los contras:
- No puedo entender cómo puedo reciclar los objetos de mensaje a un grupo de objetos , a menos que tenga un grupo diferente para cada subclase de mensaje. Así que tengo mucha, mucha creación de objetos / asignación de memoria con el tiempo.
- No puedo enviar un mensaje a un destinatario específico, pero aún no lo he necesitado en mi juego, así que no me importa demasiado.
¿Que me estoy perdiendo aqui? Debe haber una mejor implementación o alguna idea que me falta.
architecture
messaging
object-pools
you786
fuente
fuente
Respuestas:
La respuesta simple es que no desea reciclar mensajes. Uno recicla objetos que son creados (y eliminados) por miles cada cuadro, como partículas, o que son muy pesados (decenas de propiedades, largo proceso de inicialización).
Si tiene una partícula de nieve con algún mapa de bits, velocidades, atributos físicos asociados que se ubicaron debajo de su vista, es posible que desee reciclarla en lugar de crear una nueva partícula e inicializar el mapa de bits y aleatorizar nuevamente los atributos. En su ejemplo, no hay nada útil en el Mensaje para mantenerlo, y desperdiciará más recursos para eliminar sus propiedades específicas de la instancia, de lo que gastaría en crear un nuevo objeto Mensaje.
fuente
En mi juego basado en Java, se me ocurrió una solución muy similar, excepto que mi código de manejo de mensajes se ve así:
Utilizo anotaciones para marcar un método como controlador de eventos. Luego, al inicio del juego, utilizo la reflexión para calcular un mapeo (o, como lo llamo, "tubería") de mensajes, qué método invocar sobre qué objeto cuando se envía un evento de una clase específica. Esto funciona ... genial.
El cálculo de la tubería puede ser un poco complicado si desea agregar interfaces y subclases a la mezcla, pero de todos modos es bastante sencillo. Hay una ligera desaceleración durante la carga del juego cuando todas las clases necesitan ser escaneadas, pero se hace solo una vez (y probablemente se puede mover a un hilo separado). En cambio, lo que se gana es que el envío real de mensajes es más barato: no tengo que invocar todos los métodos "messageReceived" en la base de código solo para que compruebe si el evento es de buena clase.
fuente
EDITAR La respuesta de Liosan es más sexy. Mirar dentro.
Como dijo Markus, los mensajes no son un candidato común para los grupos de objetos. No te molestes por las razones que mencionó. Si tu juego envía toneladas de mensajes de tipos específicos, entonces quizás valga la pena. Pero luego, en ese punto, te sugiero que cambies a llamadas de método directo.
Hablando de que,
Si conoce a un destinatario específico al que desea enviarlo, ¿no sería bastante fácil obtener una referencia a ese objeto y hacer una llamada directa al método? También puede ocultar objetos específicos detrás de las clases de administrador para facilitar el acceso a través de los sistemas.
Hay una desventaja en su implementación, y es que existe la posibilidad de que muchos objetos reciban mensajes que realmente no les interesan. Idealmente, sus clases solo recibirían mensajes que realmente les interesen.
Puede usar a
HashMap<Class, LinkedList<Messagable>>
para asociar tipos de mensajes con una lista de objetos que desean recibir ese tipo de mensaje.Suscribirse a un tipo de mensaje se vería así:
Podrías implementar
subscribe
así (perdóname algunos errores, no he escrito Java en un par de años):Y luego podrías transmitir un mensaje como este:
Y
broadcastMessage
podría implementarse así:También puede suscribirse al mensaje de tal manera que pueda dividir el manejo de su mensaje en diferentes funciones anónimas:
Es un poco detallado, pero ayuda con la organización. También podría implementar una segunda función,
subscribeAll
que mantendrá una lista separada de mensajes deMessagable
correo electrónico que quieran escuchar sobre todo.fuente
1 . No lo hagas
Los mensajes son de bajo costo. Estoy de acuerdo con Markus von Broady. GC los recogerá rápido. Intenta no adjuntar mucha información adicional para los mensajes. Son solo mensajes. Encontrar instancia de es una información en sí misma. Úselo (como lo hizo en su ejemplo).
2 . Podría intentar usar MessageDispatcher .
A diferencia de la primera solución, podría tener un despachador de mensajes centralizado que procesa los mensajes y los pasa a los objetos deseados.
fuente