Eu projetei um sistema de entidades para um FPS. Basicamente, funciona assim:
Temos um objeto "mundo", chamado GameWorld. Isso contém uma matriz de GameObject, bem como uma matriz do ComponentManager.
GameObject contém uma matriz de Component. Ele também fornece um mecanismo de evento que é realmente simples. Os próprios componentes podem enviar um evento para a entidade, que é transmitido para todos os componentes.
Component é basicamente algo que dá ao GameObject certas propriedades e, como o GameObject é na verdade apenas um contêiner, tudo o que tem a ver com um objeto do jogo acontece nos componentes. Exemplos incluem ViewComponent, PhysicsComponent e LogicComponent. Se a comunicação entre eles for necessária, isso poderá ser feito através do uso de eventos.
ComponentManager apenas uma interface como Component e, para cada classe Component, geralmente deve haver uma classe ComponentManager. Esses gerenciadores de componentes são responsáveis por criar os componentes e inicializá-los com propriedades lidas a partir de algo como um arquivo XML.
O ComponentManager também cuida de atualizações em massa de componentes, como o PhysicsComponent, onde usarei uma biblioteca externa (que faz tudo no mundo de uma só vez).
Para configurabilidade, usarei uma fábrica para as entidades que lerão um arquivo XML ou um script, criarão os componentes especificados no arquivo (que também adiciona uma referência a ele no gerenciador de componentes certo para atualizações em massa) e injete-os em um objeto GameObject.
Agora vem o meu problema: vou tentar usar isso para jogos multiplayer. Não tenho ideia de como abordar isso.
Primeiro: quais entidades os clientes devem ter desde o início? Eu deveria começar explicando como um mecanismo para um jogador determinaria quais entidades criar.
No editor de níveis, você pode criar "pincéis" e "entidades". Escovas são para coisas como paredes, pisos e tetos, formas basicamente simples. As entidades são o GameObject de que falei. Ao criar entidades no editor de níveis, você pode especificar propriedades para cada um de seus componentes. Essas propriedades são passadas diretamente para algo como um construtor no script da entidade.
Quando você salva o nível para o mecanismo carregar, ele é decomposto em uma lista de entidades e suas propriedades associadas. Os pincéis são convertidos em uma entidade "worldspawn".
Quando você carrega esse nível, apenas instancia todas as entidades. Parece simples, não é?
Agora, para conectar em rede as entidades, encontro vários problemas. Primeiro, quais entidades devem existir no cliente desde o início? Supondo que o servidor e o cliente possuam o arquivo de nível, o cliente também pode instanciar todas as entidades no nível, mesmo se elas existirem apenas para fins de regras do jogo no servidor.
Outra possibilidade é que o cliente instancia uma entidade assim que o servidor envia informações sobre ela, e isso significa que o cliente terá apenas entidades de que precisa.
Outra questão é como enviar as informações. Eu acho que o servidor poderia usar a compactação delta, o que significa que ele só envia novas informações quando algo muda, em vez de enviar um instantâneo para o cliente em cada quadro. Embora isso signifique que o servidor deve acompanhar o que cada cliente sabe no momento.
E, finalmente, como a rede deve ser injetada no mecanismo? Estou pensando em um componente, NetworkComponent, que é injetado em todas as entidades que deveriam estar em rede. Mas como o componente de rede deve saber quais variáveis devem ser acessadas e como acessá-las e, finalmente, como o componente de rede correspondente no cliente deve saber como alterar as variáveis de rede?
Estou tendo um grande problema para abordar isso. Eu realmente aprecio se você me ajudou no caminho. Estou aberto a dicas sobre como melhorar o design do sistema de componentes, portanto, não tenha medo de sugerir isso.
fonte
Iria escrever um comentário, mas decidiu que isso poderia ser informação suficiente para uma resposta.
Primeiro, marque +1 em uma pergunta tão bem escrita, com muitos detalhes para julgar a resposta.
Para o carregamento de dados, o cliente carregaria o mundo a partir do arquivo mundial. Se suas entidades tiverem IDs provenientes do arquivo de dados, eu também os carregaria por padrão, para que seu sistema de rede possa se referir a eles para saber de quais objetos ele está falando. Todos que carregam os mesmos dados iniciais devem significar que todos têm os mesmos IDs para esses objetos.
Em segundo lugar, não crie um componente NetworkComponent, pois isso não faria nada além de replicar dados em outros componentes existentes (física, animação e similares são algumas coisas comuns a serem enviadas). Para usar sua própria nomeação, convém criar um NetworkComponentManager. Isso seria um pouco diferente do outro relacionamento Component para ComponentManager que você tem, mas isso pode ser instanciado quando você inicia um jogo em rede e tem qualquer tipo de componente que possua um aspecto de rede que forneça seus dados ao gerente para que possam ser empacotados e enviá-lo. É aqui que sua funcionalidade Salvar / Carregar pode ser usada se você tiver algum tipo de mecanismo de serialização / desserialização que também possa ser usado para empacotar dados para, conforme mencionado,
Dada a sua pergunta e o nível de informações, acho que não preciso entrar em muito mais detalhes, mas se algo não estiver claro, poste um comentário e atualizarei a resposta para resolver isso.
Espero que isto ajude.
fonte