¿Existe una técnica común para manejar el estado (en general) en un lenguaje de programación funcional? Hay soluciones en cada lenguaje de programación (funcional) para manejar el estado global, pero quiero evitar esto en la medida de lo posible.
Todos los estados de manera puramente funcional son parámetros de función. Así que necesito poner todo el estado del juego (un gigantesco hashmap con el mundo, jugadores, posiciones, puntaje, activos, enemigos, ...) como un parámetro para todas las funciones que desean manipular el mundo en una entrada o disparador dado . La función en sí recoge la información relevante del blob del estado del juego, hace algo con él, manipula el estado del juego y devuelve el estado del juego. Pero esto parece una solución pobre para el problema. Si pongo todo el estado del juego en todas las funciones, no hay ningún beneficio para mí en contraste con las variables globales o el enfoque imperativo.
Podría poner solo la información relevante en las funciones y devolver las acciones que se tomarán para la entrada dada. Y una sola función aplica todas las acciones al estado del juego. Pero la mayoría de las funciones necesitan mucha información "relevante". move()
necesita la posición del objeto, la velocidad, el mapa de colisión, la posición de todos los enemigos, la salud actual, ... Así que este enfoque tampoco parece funcionar.
Entonces, mi pregunta es ¿cómo manejo la gran cantidad de estado en un lenguaje de programación funcional, especialmente para el desarrollo de juegos?
EDITAR: Hay algunos marcos de juego para construir juegos en Clojure. El enfoque para resolver este problema parcialmente es enhebrar todos los objetos en el juego como "entidades" y ponerlo en una bolsa enorme. Una función principal Gigant es la celebración de la pantalla y las entidades y eventos mango ( :on-key-down
, :on-init
, ...) para esta entidades y ejecutar el bucle principal de la pantalla. Pero esta no es la solución limpia que estoy buscando.
fuente
move()
, probablemente deberías estar pasando el objeto 'actual' (o un identificador para él), más el mundo por el que se está moviendo, y simplemente derivar la posición y velocidad actuales ... la salida es entonces todo el mundo de la física, o al menos Una lista de objetos modificados.Respuestas:
Los efectos secundarios y el estado en los lenguajes de programación funcional son un problema más amplio en informática. En caso de que no los haya encontrado antes, tal vez eche un vistazo a las mónadas . Sin embargo, tenga cuidado: son un concepto bastante avanzado y la mayoría de las personas que conozco (incluido yo) luchan por comprenderlos. Hay muchos, muchos tutoriales en línea, con diferentes enfoques y requisitos de conocimiento. Personalmente, me gustó lo mejor de Eric Lippert.
Eric Lippert sobre mónadas
Algunas cosas a considerar, sin embargo:
Algunas reflexiones finales:
En general, creo que incluso si pudiera ser interesante académicamente, dudo que este enfoque sea práctico y valga la pena.
fuente
He escrito algunos juegos usando F # (multi-paradigma, impuro, lenguaje funcional primero), con enfoques que van desde OOP hasta FRP . Esta es una pregunta amplia, pero haré lo mejor que pueda.
Mi forma preferida es tener un tipo inmutable que represente todo el juego
State
. Luego tengo una referencia mutable a la corrienteState
que se actualiza cada tic. Esto no es estrictamente puro, pero mantiene la mutabilidad limitada a un solo lugar.No es verdad. Debido a que el
State
tipo es inmutable, no puede tener ningún componente antiguo que mute el mundo de manera mal definida. Esto soluciona el mayor problema con elGameObject
enfoque (popularizado por Unity): es difícil controlar el orden de lasUpdate
llamadas.Y a diferencia del uso de globals, es fácilmente comprobable por unidades y paralelo,
También debe escribir funciones auxiliares que reciban subpropiedades del estado para desglosar el problema.
Por ejemplo:
Aquí
update
actúa en todo el estado, peroupdateSpaceShip
solo actúa en un individuoSpaceShip
aislado.Mi sugerencia sería crear un
Input
tipo que contenga los estados de teclado, mouse, gamepad, etc. A continuación, puede escribir una función que tome unState
yInput
devuelva el siguienteState
:Para darle una idea de cómo encaja esto, el juego en general podría verse así:
Para juegos simples, puede usar el enfoque anterior (funciones auxiliares). Para algo más complicado, es posible que desee probar " lentes ".
Al contrario de algunos de los comentarios aquí, sugeriría encarecidamente escribir juegos en un lenguaje de programación funcional (impuro), ¡o al menos intentarlo! He descubierto que hace que la iteración sea más rápida, que las bases de código sean más pequeñas y que los errores sean menos comunes.
Yo también no creo que hay que aprender a mónadas juegos de escritura en un (impuro) Idioma FP. Esto se debe a que su código probablemente estará bloqueando y con un solo subproceso.
Esto es particularmente cierto si estás escribiendo un juego multijugador. Entonces las cosas se volverán mucho más fáciles con este enfoque porque te permite serializar trivialmente el estado del juego y enviarlo a través de la red.
En cuanto a por qué no se escriben más juegos de esta manera ... No puedo decir. Sin embargo, esto es cierto en todos los dominios de programación (excepto quizás en finanzas), por lo que no usaría esto como argumento de que los lenguajes funcionales no son adecuados para la programación de juegos.
También vale la pena leer es Retrogames puramente funcionales .
fuente
Lo que estás buscando es el desarrollo de juegos FRP.
Algunas introducciones de video:
"Control de tiempo y espacio: comprender las muchas formulaciones de FRP" por Evan Czaplicki
Bodil Stokke: Desarrollo de juegos reactivos para el inconformista exigente [JSConf2014]
Me encanta esta charla con Carmack, describe sus experiencias con la programación puramente funcional en el desarrollo de juegos. La nota clave de John Carmack en Quakecon 2013, parte 4
Es 100% posible y preferible hacer que la lógica central del juego sea puramente funcional, la industria en su conjunto simplemente está detrás, atrapada en un paradigma de pensamiento.
También es posible hacerlo en Unity.
Para responder a la pregunta, se actualizará / creará un nuevo estado del juego cada vez que algo se mueva, como dice Carmack en su charla, no es un problema. La reducción drástica en la sobrecarga cognitiva que proviene de una arquitectura puramente funcional, altamente mantenible y flexible, supera en gran medida el rendimiento, si es que existe.
fuente