Existe uma técnica comum para lidar com o estado (em geral) em uma linguagem de programação funcional? Existem soluções em todas as linguagens de programação (funcionais) para lidar com o estado global, mas quero evitar isso o máximo possível.
Todos os estados de uma maneira funcional pura são parâmetros de função. Então, preciso colocar todo o estado do jogo (um gigantesco mapa de hash com o mundo, jogadores, posições, pontuação, ativos, inimigos, ...)) como um parâmetro para todas as funções que desejam manipular o mundo em uma determinada entrada ou gatilho . A própria função seleciona as informações relevantes do blob gamestate, faz algo com ele, manipula o gamestate e retorna o gamestate. Mas isso parece uma solução pobre para o problema. Se eu colocar todo o estado do jogo em todas as funções, não há benefício para mim em contraste com as variáveis globais ou a abordagem imperativa.
Eu poderia colocar apenas as informações relevantes nas funções e retornar as ações que serão tomadas para a entrada fornecida. E uma única função aplica todas as ações ao estado do jogo. Mas a maioria das funções precisa de muitas informações "relevantes". move()
precisa da posição do objeto, da velocidade, do mapa para colisão, da posição de todos os inimigos, da saúde atual, ... Portanto, essa abordagem também não parece funcionar.
Então, minha pergunta é: como eu manejo a enorme quantidade de estado em uma linguagem de programação funcional - especialmente para o desenvolvimento de jogos?
EDIT: Existem algumas estruturas de jogos para a criação de jogos no Clojure. Uma abordagem para resolver esse problema parcialmente é enfiar todos os objetos no jogo como "entidades" e colocá-lo em um saco enorme. A função principal gigant está segurando a tela e as entidades e eventos alça ( :on-key-down
, :on-init
...) para esse entidades e executar o loop principal do display. Mas esta não é a solução limpa que estou procurando.
fonte
move()
, você provavelmente deveria estar passando o objeto 'atual' (ou um identificador para ele), mais o mundo pelo qual ele está se movendo e apenas derivando a posição e a velocidade atuais ... a saída é então o mundo inteiro da física, ou pelo menos uma lista de objetos alterados.Respostas:
Efeitos colaterais e estado em linguagens de programação funcionais são um problema mais amplo na ciência da computação. Caso você não os tenha encontrado antes, talvez dê uma olhada nas mônadas . Porém, esteja avisado: eles são um conceito bastante avançado e a maioria das pessoas que conheço (inclusive eu) luta para entendê-los. Existem muitos tutoriais on-line, com diferentes abordagens e requisitos de conhecimento. Pessoalmente, gostei do melhor de Eric Lippert.
Eric Lippert em Monads
Algumas coisas a considerar, no entanto:
Algumas considerações finais:
Em suma, acho que, mesmo que possa ser interessante academicamente, duvido que essa abordagem seja prática e valha o esforço.
fonte
Escrevi alguns jogos usando F # (linguagem multiparadigma, impura, funcional primeiro), com abordagens que variam de OOP a FRP . Essa é uma pergunta ampla, mas farei o meu melhor.
Minha maneira preferida é ter um tipo imutável que represente o jogo inteiro
State
. Em seguida, tenho uma referência mutável à correnteState
que é atualizada a cada marca. Isso não é estritamente puro, mas mantém a mutabilidade limitada a um lugar.Não é verdade. Como o
State
tipo é imutável, você não pode ter nenhum componente antigo mutando o mundo de maneiras mal definidas. Isso corrige o maior problema daGameObject
abordagem (popularizada pelo Unity): é difícil controlar a ordem dasUpdate
chamadas.E, ao contrário do uso de globais, é facilmente testável por unidade e paralelamente,
Você também deve escrever funções auxiliares que recebem subpropriedades do estado para quebrar o problema.
Por exemplo:
Aqui
update
atua em todo o estado, masupdateSpaceShip
somente em um indivíduoSpaceShip
isoladamente.Minha sugestão seria criar um
Input
tipo que contenha os estados de teclado, mouse, gamepad etc. Em seguida, você pode escrever uma função que recebe umState
e umInput
retorno no próximoState
:Para lhe dar uma idéia de como isso se encaixa, o jogo geral pode ser algo como isto:
Para jogos simples, você pode usar a abordagem acima (funções auxiliares). Para algo mais complicado, você pode tentar " lentes ".
Ao contrário de alguns dos comentários aqui, eu sugiro escrever jogos em uma linguagem de programação funcional (impura), ou pelo menos tentar! Eu descobri que torna a iteração mais rápida, as bases de código menores e os bugs menos comuns.
Também não acho que você precise aprender mônadas para escrever jogos em uma linguagem FP (impura). Isso ocorre porque seu código provavelmente estará bloqueando e com thread único.
Isto é particularmente verdade se você estiver escrevendo um jogo multiplayer. Então, as coisas ficarão muito mais fáceis com essa abordagem, pois permite serializar trivialmente o estado do jogo e enviá-lo pela rede.
Quanto ao porquê de mais jogos não serem escritos dessa maneira ... não sei dizer. No entanto, isso é verdade em todos os domínios de programação (exceto talvez finanças), então eu não usaria isso como argumento de que linguagens funcionais são inadequadas para a programação de jogos.
Também vale a pena ler os Retrogames Puramente Funcionais .
fonte
O que você está procurando é o desenvolvimento de jogos de FRP.
Algumas introduções em vídeo:
"Controlando o tempo e o espaço: entendendo as muitas formulações de FRP" de Evan Czaplicki
Bodil Stokke: desenvolvimento reativo de jogos para os mais exigentes hipster [JSConf2014]
Adoro essa palestra com Carmack, descreve suas experiências com programação puramente funcional no desenvolvimento de jogos A palestra de John Carmack no Quakecon 2013 parte 4
É 100% possível e preferível tornar a lógica do jogo principal de uma maneira puramente funcional, a indústria como um todo está simplesmente atrasada, presa em um paradigma de pensamento.
É possível fazê-lo também no Unity.
Para responder à pergunta, um novo estado do jogo será atualizado / criado toda vez que algo se mover, como carmack diz em sua palestra, não é um problema. A redução drástica na sobrecarga cognitiva resultante de uma arquitetura puramente funcional, altamente sustentável e muito distante do desempenho atingido, se é que existe.
fonte