Eu trabalhei no mesmo mecanismo que o coderanger. Eu tenho um ponto de vista diferente. :)
Primeiro, não tínhamos uma pilha de FSMs - tínhamos uma pilha de estados. Uma pilha de estados cria um único FSM. Não sei como seria uma pilha de FSMs. Provavelmente muito complicado para fazer algo prático.
Meu maior problema com nossa Máquina de Estado Global era que era uma pilha de estados, e não um conjunto de estados. Isso significa, por exemplo, ... / MainMenu / O carregamento foi diferente de ... / Loading / MainMenu, dependendo se você abriu o menu principal antes ou depois da tela de carregamento (o jogo é assíncrono e o carregamento é principalmente orientado pelo servidor )
Como dois exemplos de coisas isso ficou feio:
- Isso levou, por exemplo, ao estado LoadingGameplay, então você tinha Base / Loading e Base / Gameplay / LoadingGameplay para carregar no estado Gameplay, que precisou repetir grande parte do código no estado normal de carregamento (mas não todos, e adicionar um pouco mais )
- Tínhamos várias funções como "se no criador do personagem, vá para o jogo; se no jogo, vá para o personagem selecionado; se no personagem, selecione voltar para o login", porque queríamos mostrar as mesmas janelas de interface em diferentes estados, mas fazer o botão Voltar / Avançar botões ainda funcionam.
Apesar do nome, não era muito "global". A maioria dos sistemas de jogos internos não o utilizava para rastrear seus estados internos, porque eles não queriam que seus estados estivessem mexendo com outros sistemas. Outros, por exemplo, o sistema de interface do usuário, poderiam usá-lo, mas apenas para copiar o estado em seus próprios sistemas de estado locais. (Eu recomendaria especialmente ao sistema os estados da interface do usuário. O estado da interface do usuário não é uma pilha, é realmente um DAG, e tentar forçar qualquer outra estrutura nele só tornará as interfaces de usuário frustrantes de usar.)
O que era bom era isolar tarefas para integrar código de programadores de infraestrutura que não sabiam como o fluxo do jogo era realmente estruturado, para que você pudesse dizer ao cara que escreveu o patcher "coloque seu código no Client_Patch_Update" e o cara que escreveu os gráficos loading "coloque seu código em Client_MapTransfer_OnEnter", e poderíamos trocar certos fluxos lógicos sem muito problema.
Em um projeto paralelo, tive mais sorte com um conjunto de estados do que com uma pilha , sem medo de criar várias máquinas para sistemas não relacionados e me recusando a me deixar cair na armadilha de ter um "estado global", que é realmente apenas uma maneira complicada de sincronizar as coisas por meio de variáveis globais - claro, você vai acabar fazendo isso perto de um prazo, mas não crie esse objetivo como seu objetivo . Fundamentalmente, o estado em um jogo não é uma pilha e os estados em um jogo não são todos relacionados.
O GSM também, como indicadores de função e comportamento não local, dificultavam as coisas de depuração, embora a depuração desse tipo de transições de estado grandes não fosse muito divertida antes de tê-lo. Conjuntos de estados em vez de pilhas de estados realmente não ajudam nisso, mas você deve estar ciente disso. Funções virtuais em vez de ponteiros de função podem aliviar um pouco isso.