Eu sou bastante novo no desenvolvimento de jogos (mas não na programação) e estou tentando descobrir qual seria a melhor maneira de lidar com a comunicação entre os mundos. O que eu quero dizer é o seguinte:
Eu tenho lido sobre sistemas de componentes de entidades (ECS) e como as pessoas sugerem o uso de mundos / espaços diferentes ( http://gamedevelopment.tutsplus.com/tutorials/spaces-useful-game-object-containers--gamedev-14091 ) para uma subseção de um jogo. Por exemplo, um HUD, inventário ou combate / movimento têm um mundo / espaço separado (porque eles têm gráficos diferentes e lógica subjacente).
No entanto, eu queria saber como o inventário, ou o HUD, sabe sobre a saúde de um jogador quando a saúde é tratada por um espaço / mundo diferente, por exemplo, quando em combate?
Isso também se aplica à progressão do jogo em geral, por exemplo, diálogo com o NPC (um diálogo seria um espaço separado, pois é uma tela pop-up), mas como você transmitiria as escolhas feitas (ou no estado) do diálogo para outros espaços / mundos . Ou basicamente qualquer outro tipo de evento que influencie a progressão do jogo em diferentes espaços / mundos (saúde, mana, missões, diálogo, combate, inventário, hud, etc.)
Como alguém lidaria com esse tipo de design? Precisa de um objeto singleton (em implementação) que contenha todo esse tipo de informação? Isso seria estranho, porque, então, a components
necessidade de transmitir cada alteração a esse objeto singleton, que parece fazer as coisas duas vezes (indo contra o principal DRY da programação) ...
Estou meio que perdida aqui em termos de design, alguma dica?
---EDITAR---
Então, eu li alguns outros posts sugeridos por comentários e tive uma idéia geral sobre as possibilidades, no entanto, cada um deles parece ter uma grande desvantagem que os torna simplesmente não corretos. É muito possível que eu esteja supervisionando os detalhes que resolveriam essas desvantagens, então fique à vontade para me corrigir. Vou tentar dar uma visão geral, bem como algumas respostas para algumas perguntas.
Estou vendo três opções principais para 'compartilhar' dados entre espaços. Embora a maioria das postagens seja sobre o compartilhamento de dados entre sistemas, sinto que o mesmo pode ser aplicado ao compartilhamento de dados entre sistemas.
1. Consulta
Exemplo : Se o mundo do HUD precisar conhecer a saúde atual do jogador, ele poderá consultar outro mundo e solicitar a saúde atual.
Desvantagem : os mundos precisam saber um do outro, o que é um grande problema de dependência e vai contra a dissociação.
2: Mensagens diretas (sincronização e assíncrona)
Exemplo : se durante o combate a saúde de um jogador mudar, ele poderá enviar mensagens (sincronizadas e assíncronas, o que for necessário) para outros mundos que precisem saber sobre essa alteração.
Desvantagem : Ainda é a questão da dissociação: os mundos precisam saber um do outro.
3: Mensagens indiretas (sincronização e assíncrona) <- melhor opção
Exemplo : se durante o combate a saúde de um jogador mudar, ele poderá enviar mensagens (sincronização e assíncrona, o que for necessário) para o hub geral de mensagens. Outros mundos / sistemas que precisam saber sobre essa alteração são inscritos no canal de mensagens específico e lêem as mensagens.
De cabeça para baixo : completamente desacoplado, facilmente gerenciável e extensível.
Desvantagem / incerto : quando o canal de mensagens sabe que as mensagens precisam ser excluídas? Ou talvez o sistema que está inscrito marque (apenas para si) a mensagem como lida e aguarde novas mensagens -> messagebox se torne enorme depois de um tempo. Como os mundos / sistemas lidam com a ordem? Por exemplo, durante um quadro: se o HUD já pesquisou a mensagem de integridade e depois disso a saúde muda, o próximo quadro é atualizado. Para alguns aplicativos, esse pode não ser o caminho certo.
P: Um único objeto de jogo pode existir em vários espaços
Estou usando a estrutura Artemis ECS, que vem com espaços internos (chamados mundos). Cada entidade (e com ela, os dados na forma de componentes) é criada em um mundo e, portanto, não pode ser compartilhada entre mundos.
Respostas:
Uma maneira de ver isso é que você possivelmente está colocando muito em seus objetos de jogo.
Não há razão para que o código que conecte o HUD ao seu jogo no mundo precise estar em um componente / sistema que mora em algum espaço específico. Talvez seja melhor viver com esse código em um gerente central ou script global que tenha acesso a todos os espaços e objetos e, em seguida, interagir com o código que sabe quando realmente criar um espaço e o que colocar neles (por exemplo, o código que gera o jogador, salva seu estado entre níveis, etc.).
Você também pode ter apenas um "espaço mestre" que contém objetos de jogo com lógica ou dados que precisam persistir ou manipular os espaços usados para níveis e interface do usuário. Essa abordagem é comum em mecanismos que forçam os desenvolvedores a colocar todos os scripts / lógicas em componentes / objetos (por exemplo, no Unity, você cria um objeto Main global e o configura para persistir durante o descarregamento da cena; se o Unity realmente tiver espaços, você ' d use aqueles em vez da bandeira).
Lembre-se de abusar do seu ECS é o mesmo que abusar dos padrões de design; Só porque você tem uma ferramenta nova e bacana, não significa que você deve usá-la para resolver todos os problemas que encontrar. Avalie o espaço do seu problema e selecione a solução mais adequada, mesmo que seja a coisa mais antiga que seus ancestrais usavam na idade das trevas dos anos 90. : p
fonte
Eu criei alguns protótipos, mas nada muito grande, e a maneira como lidava com vários espaços era simplesmente criar um objeto de jogo que contenha mundo, jogador, etc. , no objeto do jogo
Sempre que chamado, ele obtém a saúde do jogador. Dessa forma, eu poderia enviá-lo ao HUD e exibir a barra de integridade.
Não é o mais limpo, mas faz o trabalho, fiz alguns testes de desempenho em 2013 e tudo parecia funcionar sem problemas. para evitar essas dependências, você sempre pode soltar a barra de saúde quando a saúde do jogador for nula.
Normalmente, quando o jogador não existe, significa que o usuário está em um menu ou em uma cena.
Exemplo de código:
Espero que isto seja o que você estava procurando.
fonte
isso é algo em que estou trabalhando nas últimas semanas. Estou trabalhando em minha própria biblioteca de ECS (queria fazer isso por experiência e apenas para experimentá-lo, porque queria fazê-lo por algum tempo).
Este é o link do github: https://github.com/gioragutt/xna-ecs
Para o seu problema, eu sempre escrevi uma pequena biblioteca pubsub, que você pode ver aqui
Basicamente, eu tenho uma
EmsClient
classe, da qual as coisas podem derivar. Atualmente, meus componentes não fazem isso, mas as classes de nível mais alto, embora não haja motivo para não fazê-lo. Eu subscrevo a Nomes de mensagens, e proporcionar um retorno de chamada com a seguinte assinatura:Action<JObject>
. Como você já entendeu, estou usando o Json Objects como meio para transferir mensagens. Fiz isso depois de usar apenasbyte[]
as anteriores e descobri que precisava de algo mais geral, e como estou acostumado a algo assim no meu local de trabalho (temos um IPCD que funciona da mesma forma, exceto o retorno de chamada) O método é sempre o mesmo, pois geralmente separamos a responsabilidade de diferentes manipuladores).Há um
EmsServer
(um no servidor e um em cada cliente) responsável por mover as mensagens entreEmsClient
o seu domínio (EmsServer
no lado do servidor move as mensagens entreEmsClients
o lado do servidor, vice-versa para o lado do cliente).Para mensagens entre o Cliente e o Servidor, criei um
EmsServerEndpoint
que éEmsClient
ele mesmo, ele apenas executa a lógica de armazenar em buffer as mensagens enviadas em seu domínio e liberá-las para outros domínios (por exemplo, o cliente envia a mensagem para o servidor, enquanto quando o servidor transfere cada mensagem para todos os clientes conectados.Você pode ver o uso em muitos lugares, fe:
ClientGameManager
,ServerGameManager
.Considerando que, por exemplo, se eu quiser adicionar um componente GUI para um jogador, você pode consultar AQUI , os métodos
BeginAllocateLocal
eBeginAllocateRemote
, que são responsáveis pela criaçãoGameObjects
dos jogadores. CadaGameObject
um contém umEntity
(da lib ECS) e umIComponentContainer
(que também é, da lib ECS). CadaGameObject
um recebe automaticamente uma transformação (como emUnity
, da qual me inspirei).Meu código praticamente fala por si, e se você conseguir, estou procurando críticas, então gostaria de receber críticas construtivas :)
Espero que meu código o ajude com algumas idéias!
fonte
Considere os componentes do padrão observador / assunto para os componentes do jogo e da interface do usuário. Você os une na criação / carregamento e depois os esquece. Se a saúde do personagem mudar, ele notifica todos os observadores, que podem fazer o que quiserem com as informações.
fonte