Atualmente, estou criando um RPG 2D em C ++ 11 com Allegro 5 e boost.
Meu objetivo é atualizar de alguma forma as configurações do meu jogo quando uma opção é alterada no menu Opções. Não quero forçar o usuário a reiniciar meu jogo. Outros jogos não precisam ser reiniciados ao alterar a resolução ou passar da tela cheia para a janela, então meu jogo também não deveria. Por favor, veja uma visão simplificada do sistema abaixo.
Observe que não estou necessariamente querendo chamar diretamente meu objeto de jogo a partir do OptionsScreen. A linha pontilhada é meramente ilustrar o efeito que estou tentando alcançar; de alguma forma causar uma atualização do jogo quando uma opção é alterada em uma parte diferente do sistema.
Explicação detalhada
O ScreenManager contém uma lista de todos os GameScreen
objetos existentes no momento. Estas serão várias telas do jogo, incluindo pop-ups. Esse design adere mais ou menos à amostra Game State Management em C # / XNA .
O ScreenManager
contém uma referência ao meu Game
objeto. O Game
objeto inicializa e modifica as configurações do jogo. Se eu quiser alterar a resolução, ficar em tela cheia ou silenciar o volume, eu o faria na Game
aula.
No entanto, o OptionsScreen atualmente não pode acessar a classe Game. Veja o diagrama abaixo:
A GameScreen pode sinalizar três eventos, onFinished
, onTransitionStart
e onTransitionEnd
. Não existe onOptionsChanged
porque apenas uma tela faz isso. O ScreenManager não pode configurar a manipulação de eventos para isso porque lida com todas as telas como GameScreen
s.
Minha pergunta é: como posso alterar meu design para que uma alteração no OptionsMenu não exija reinicialização, mas que seja alterada imediatamente? Eu preferiria solicitar que meu Game
objeto fosse atualizado assim que o botão Aplicar fosse clicado.
Respostas:
Pelo que vi, a abordagem mais fácil é ler um arquivo de opções na inicialização para determinar as configurações atuais de exibição; depois, quando a tela de opções for exibida, carregue todas as opções atuais de um arquivo.
Quando as alterações são finalizadas através de um botão
apply
ouok
, elas são salvas novamente em um arquivo. Se alguma alteração afetar a exibição, notifique o usuário que o jogo deve ser reiniciado para que ele entre em vigor.Quando o jogo é reiniciado, as (agora novas) configurações de exibição são lidas novamente a partir do arquivo.
--EDITAR--
E ... teria ajudado se eu notasse a última frase. Você não quer ter que reiniciar. Torna as coisas um pouco mais difíceis, dependendo da sua implementação e da sua Biblioteca de gráficos de back-end.
IIRC, Allegro possui uma chamada de função que permite alterar as configurações de exibição em tempo real. Ainda não estou de acordo com o Allegro 5, mas sei que você poderia fazê-lo em 4.
fonte
Isto é o que eu faço para o meu jogo. Eu tenho 2 funções separadas para inicializar coisas, 'init' e 'reset'. O Init é chamado apenas uma vez na inicialização e faz coisas que não dependem de nenhuma configuração, como carregar os principais ativos. Redefinir faz o layout da interface do usuário com base na resolução da tela, assim é chamado sempre que as configurações são alteradas.
Não conheço Allegro, mas minha resposta é bastante geral, por isso espero que ajude você ou qualquer outra pessoa com um problema semelhante.
fonte
Sem mexer com sua arquitetura atual, vejo duas maneiras. Primeiro, você pode armazenar um ponteiro para a
Game
instância no diretórioOptionsScreen
classe. Segundo, você podeGame
buscar as configurações atuais em um determinado intervalo, digamos a cada segundo.Para realmente se adaptar às novas configurações, o
Game
classe precisa implementar algum tipo de função de redefinição que busca as configurações atuais e reinicializa com base nelas.Para uma solução limpa, você precisa de um gerente global de algum tipo, portanto, é mais esforço implementá-lo. Por exemplo, um sistema de eventos ou sistema de mensagens. É muito útil permitir que as classes se comuniquem sem vínculos fortes, como agregação ou composição, etc.
Com um gerente de eventos global, ele
OptionsScreen
poderia simplesmente disparar globalmente um evento de redesenho queGame
se registrou para ouvir antes.Geralmente, você pode implementar uma classe de gerente armazenando eventos e retornos de chamada ouvindo-os em um mapa de hash. Em seguida, você pode criar uma única instância desse gerenciador e passar ponteiros para seus componentes. Usar C ++ mais recente é bastante fácil, pois você pode usar
std::unordered_map
como mapa de hash estd::function
armazenar retornos de chamada. Existem diferentes abordagens que você pode usar como chave. Por exemplo, você pode tornar o gerenciador de eventos baseado em string, o que torna os componentes ainda mais independentes. Nesse caso, você usariastd::string
como chave no mapa de hash. Eu pessoalmente gosto disso e definitivamente não é um problema de desempenho, mas a maioria dos sistemas de eventos tradicionais trabalha com eventos como classes.fonte
Bem, este é um caso específico do padrão Observer.
Existe uma solução que envolve retornos de chamada. Essa é a melhor maneira de fazer isso, se você quiser um acoplamento solto, e acho que também é a mais limpa. Isso não envolverá gerentes ou singletons globais.
Basicamente, você precisará ter algum tipo de
SettingsStore
. Lá você armazena as configurações. Quando você cria uma nova tela, eles precisam de um ponteiro para a loja. No caso doOptionsScreen
ele modificará algumas das próprias configurações. No caso doGameScreen
, apenas os lerá. Portanto, no seu jogo, você criaria apenas uma instância, que será transmitida por todas as telas que requerem uma.Agora, essa
SettingsStore
classe terá uma lista denotifiables
. São classes que implementam uma certaISettingChanged
interface. A interface seria simples e contém o seguinte método:Em sua tela, você implementará a lógica de cada configuração de sua preferência. Em seguida, adicione-se à loja para ser notificado:
store->notifyOnChange(this);
. Quando uma configuração é alterada, o retorno de chamada é chamado com o nome da configuração. O novo valor de configuração pode ser recuperado doSettingsStore
.Agora, isso pode ser aumentado ainda mais com as seguintes idéias:
SettingsStore
(const strings) para impedir a cópia e colar as strings.fonte
Leia suas configurações de um arquivo em variáveis. Faça com que seu Gerenciador de telas rastreie se a tela de onde veio é a tela Opções e, se for, recarregue suas configurações a partir das variáveis. Quando o usuário estiver saindo do jogo, escreva as configurações nas variáveis novamente no arquivo.
fonte