Minha pergunta é:
Como posso lidar com estados de jogos no meu sistema de entidades, sem recorrer a manter uma pilha de objetos de estado de jogos?
Portanto, o design do meu sistema de entidades significa que, quando uma entidade precisa se registrar para eventos de entrada, por exemplo, o componente de entrada chama o sistema de entrada e diz "registrar esta entidade para esta entrada". Está tudo bem, mas se você adicionar a isso o conceito de estados do jogo (digamos, uma tela de pausa), torna-se um problema descobrir se uma entidade está no estado atual e deve receber a entrada.
Eu poderia aumentar o componente / sistema de entrada para que ele diga "registre essa entidade para esta entrada enquanto estiver nesses estados de jogo", mas isso exige que toda entidade saiba em quais estados será usada e isso pode não ser óbvio. Além disso, manter uma lista de estados de jogos por entrada registrada (e outros sistemas que usam retornos de chamada) não parece muito eficiente.
Outra idéia que tive foi que haverá uma entidade que representa o estado do jogo, marque-a como desativada e, ao gerar o evento de entrada, verifique se a entidade não é descendente de uma entidade do estado do jogo desativada. Parece caro determinar o pai para cada retorno de chamada.
Outra idéia é fazer com que todos os sistemas armazenem seus dados digitados no estado atual; dessa forma, ao gerar a entrada, a entidade de destino nem será candidata. No entanto, isso realmente prejudica a capacidade de permitir a comunicação entre entidades em diferentes estados (não é um problema para as telas de pausa, mas acho que a trava no Oblivion / Skyrim).
A única outra idéia que tive é que todos os componentes lidem com eventos de mudança de estado e se comuniquem com seu sistema relevante para desativar qualquer coisa que eles tenham registrado e reativá-lo ao voltar para esse estado.
A segunda (marcar um objeto como desativado) e a seguir (cada componente lida com mudanças de estado) parecem ser as melhores de minhas idéias, mas nenhuma delas me impressiona por ser particularmente boa.
Alguém mais tem alguma outra idéia de como fazer isso?
editar Enquanto falo sobre entradas especificamente nesta pergunta, pode significar qualquer sistema capaz de enviar mensagens / eventos para entidades, como colisões, eventos de timer, etc.
fonte
Respostas:
O que é frequentemente usado é um intermediário
Intent System
que abstrai a entrada e mantém o controle do contexto e dos estados relevantes dos jogos.O sistema Intent irá parar de transmitir entradas quando a simulação for pausada, por exemplo. Ele também lida com o mapeamento entre eventos e intenções do controlador (mover na direção, correr, disparar, recarregar ...).
Dessa forma, seus outros adversários não dependem de controles / entradas de jogos específicos (BUTTON_A, BUTTON_B vs BUTTON_X, BUTTON_O ...), mas todos reagem com as mesmas intenções (IntentRun, IntentReload ...).
Outra vantagem é que o sistema de intenções pode estar ciente de que os controladores disponíveis estão sendo adicionados / removidos, pois pode enviar intenções para qualquer assinante, mesmo fora da simulação com a qual você pode manipular intenções
AddPlayer(controllerID)
.Você decide quantas informações sobre o estado do jogo você fornece ao sistema por meio de eventos / mensagem ou diretamente. Mas o tempo investido no sistema Intent geralmente vale a pena.
Você pode gerenciar os Contextos de Intenção, que gerarão intenções quando eles estiverem anexados ao sistema.
O contexto pode ser priorizado, ou seja:
Dessa forma, você pode adicionar e remover os contextos relevantes atualmente.
E uma coisa sobre todo o sistema de intenções é que ele deve ser executado enquanto a simulação está em pausa.
Uma maneira geralmente usada para reproduzir / pausar a simulação do jogo sem interromper as atualizações não relacionadas à simulação é usar diferentes conjuntos de tempos. ie
GenericSystem::onTime(Long time, Long deltaTime, Long simTime, Long simDeltaTime)
.Com essa abordagem, seu mecanismo pode simplesmente bloquear os incrementos no simTime dos jogos, o que, por sua vez, bloqueia as atualizações nos mecanismos relevantes de animação e física que são utilizados
simTime and simDeltaTime
, permitindo atualizações contínuas do efeito de mola da câmera, se ele tiver que se mover mesmo durante a pausa, a animação de o efeito de carregamento em um outdoor virtual do jogo enquanto os dados estão sendo baixados ...fonte
Que tal criar um sistema de eventos global e, em seguida, ter um componente de ouvinte de eventos para cada entidade? Após um evento "Game State Change", você poderia mexer nos componentes individualmente para cada entidade específica.
Digamos que você tenha um componente de entrada. Depois que o componente ouvinte de evento recebe o evento de alteração do estado do jogo, ele altera valores muito específicos para esse componente de entrada específico, para que não receba chamadas de entrada ou faça chamadas de movimento ou resposta para o sistema ou seu proprietário.
Isso funciona para mim, pois a maioria dos meus componentes está em script (via Lua). Ou seja, eu tenho um componente de entrada, que é acionado uma vez quando uma tecla é pressionada e dispara de uma direção de movimento + e, em seguida, é acionado quando a tecla é liberada e de uma direção de parada +. Há também um componente de ouvinte de evento que entra em contato com o componente de entrada (se o jogo estiver em pausa) para parar de executar qualquer função e interromper, se necessário. Eu poderia facilmente adicionar outra entidade com uma reação diferente aos mesmos eventos e pressionar teclas usando outro script. Dessa forma, você salvaria a interação entre diferentes entidades em diferentes estados e até a tornaria muito mais personalizável. Além disso, algumas entidades podem nem ter o componente ouvinte de eventos.
O que acabei de explicar é basicamente um exemplo prático da sua quarta solução.
fonte