He diseñado un sistema de entidad para un FPS. Básicamente funciona así:
Tenemos un objeto "mundial", llamado GameWorld. Esto contiene una matriz de GameObject, así como una matriz de ComponentManager.
GameObject contiene una matriz de componentes. También proporciona un mecanismo de eventos que es realmente simple. Los componentes mismos pueden enviar un evento a la entidad, que se transmite a todos los componentes.
El componente es básicamente algo que le da a GameObject ciertas propiedades, y dado que GameObject es en realidad solo un contenedor de ellos, todo lo que tiene que ver con un objeto de juego ocurre en los Componentes. Los ejemplos incluyen ViewComponent, PhysicsComponent y LogicComponent. Si se necesita la comunicación entre ellos, eso se puede hacer mediante el uso de eventos.
ComponentManager solo una interfaz como Component, y para cada clase de Componente, generalmente debería haber una clase de ComponentManager. Estos administradores de componentes son responsables de crear los componentes e inicializarlos con propiedades leídas de algo así como un archivo XML.
ComponentManager también se encarga de las actualizaciones masivas de componentes, como el PhysicsComponent, donde utilizaré una biblioteca externa (que hace todo en el mundo a la vez).
Para la configurabilidad, utilizaré una fábrica para las entidades que leerán un archivo XML o un script, crearán los componentes especificados en el archivo (que también agrega una referencia en el administrador de componentes adecuado para actualizaciones masivas) y luego inyectarlos en un objeto GameObject.
Ahora viene mi problema: voy a tratar de usar esto para juegos multijugador. No tengo idea de cómo abordar esto.
Primero: ¿Qué entidades deberían tener los clientes desde el principio? Debo comenzar explicando cómo un motor para un solo jugador determinaría qué entidades crear.
En el editor de niveles puede crear "pinceles" y "entidades". Los pinceles son para paredes, pisos y techos, básicamente formas simples. Las entidades son el GameObject del que te hablé. Al crear entidades en el editor de niveles, puede especificar propiedades para cada uno de sus componentes. Estas propiedades se pasan directamente a algo como un constructor en el script de la entidad.
Cuando guarda el nivel para que se cargue el motor, se descompone en una lista de entidades y sus propiedades asociadas. Los pinceles se convierten en una entidad "engendro del mundo".
Cuando carga ese nivel, solo instancia todas las entidades. Suena simple, ¿eh?
Ahora, para las redes de las entidades me encuentro con numerosos problemas. Primero, ¿qué entidades deberían existir en el cliente desde el principio? Suponiendo que tanto el servidor como el cliente tienen el archivo de nivel, el cliente también podría instanciar todas las entidades en el nivel, incluso si están allí solo a los fines de las reglas del juego en el servidor.
Otra posibilidad es que el cliente instancia una entidad tan pronto como el servidor envía información al respecto, y eso significa que el cliente solo tendrá entidades que necesita.
Otro problema es cómo enviar la información. Creo que el servidor podría usar la compresión delta, lo que significa que solo envía nueva información cuando algo cambia, en lugar de enviar una instantánea al cliente en cada cuadro. Aunque eso significa que el servidor debe realizar un seguimiento de lo que cada cliente sabe en este momento.
Y finalmente, ¿cómo deberían inyectarse las redes en el motor? Estoy pensando en un componente, NetworkComponent, que se inyecta en cada entidad que se supone que está conectada en red. Pero, ¿cómo debe saber el componente de red qué variables red y cómo? conectar acceder a ellas, y finalmente cómo el componente de red correspondiente en el cliente debe saber cómo cambiar las variables en red?
Estoy teniendo grandes problemas para abordar esto. Realmente agradecería que me ayudaras en el camino. También estoy abierto a consejos sobre cómo mejorar el diseño del sistema de componentes, así que no tenga miedo de sugerir eso.
fuente
Iba a escribir un comentario, pero decidió que podría ser suficiente información para una respuesta.
Primero, +1 para una pregunta tan bien escrita con toneladas de detalles para juzgar la respuesta.
Para la carga de datos, el cliente debería cargar el mundo desde el archivo mundial. Si sus entidades tienen identificadores que provienen del archivo de datos, también los cargaría de forma predeterminada para que su sistema de red pueda referirse a ellos para saber de qué objetos está hablando. Todos los que carguen los mismos datos iniciales deberían significar que todos tienen los mismos ID para esos objetos.
En segundo lugar, no cree un componente NetworkComponent ya que esto no haría nada más que replicar datos en otros componentes existentes (la física, la animación y similares son algunas cosas comunes para enviar). Para usar su propio nombre, es posible que desee crear un NetworkComponentManager. Esto estaría un poco alejado de la otra relación Component to ComponentManager que tenga, pero esto podría ser instanciado cuando inicie un juego en red y tenga cualquier tipo de componentes que tengan un aspecto de red para que entregue sus datos al administrador para que pueda empaquetarlo y enviarlo Aquí es donde su funcionalidad de Guardar / Cargar podría usarse si tiene algún tipo de mecanismo de serialización / deserialización que también podría usar para empaquetar datos para, como se mencionó,
Dada su pregunta y nivel de información, no creo que necesite entrar en más detalles, pero si algo no está claro, publique un comentario y actualizaré la respuesta para abordarlo.
Espero que esto ayude.
fuente