¿Alternativa al sistema de estado del juego?

30

Por lo que puedo decir, la mayoría de los juegos tienen algún tipo de "sistema de estado del juego" que cambia entre los diferentes estados del juego; Estos pueden ser cosas como "Introducción", "Menú principal", "Selección de personaje", "Cargando" y "Juego".

Por un lado, tiene mucho sentido separarlos en un sistema de estado. Después de todo, son dispares y de lo contrario tendrían que estar en una declaración de cambio grande, lo que obviamente es desordenado; y ciertamente están bien representados por un sistema estatal. Pero al mismo tiempo, miro el estado del "Juego" y me pregunto si hay algo malo en este enfoque del sistema de estados. Porque es como el elefante en la habitación; es ENORME y obvio, pero nadie cuestiona el enfoque del sistema de estado del juego.

Me parece una tontería que "Juego" esté en el mismo nivel que "Menú principal". Sin embargo, no hay una manera de romper el estado del "Juego".

¿Es un sistema de estado del juego la mejor manera de hacerlo? ¿Existe alguna técnica diferente y mejor para administrar, bueno, el "estado del juego"? ¿Está bien tener un estado de introducción que dibuje una película y escuche la entrada, y luego un estado de carga que se repita en el administrador de recursos, y luego el estado del juego que hace prácticamente todo ? ¿No te parece un poco desequilibrado también? ¿Me estoy perdiendo de algo?

Ricket
fuente

Respuestas:

30

Creo que solo estás discutiendo semántica aquí. Se llama Game State porque se comporta como una máquina de estados finitos, con un número finito de estados y transiciones entre ellos. El 'Juego' en 'Sistema de estado del juego' se refiere al sistema general, con 'Cargando', 'MainMenu', etc., que son estados del juego. Estos podrían fácilmente llamarse 'escenas' o 'pantallas' o 'niveles'. Es solo semántica.

Ya no estoy seguro de que se aplique un FSM estricto. En mis implementaciones, llamo a los estados 'Pantallas' y dejo que sean apilables, es decir. Las pantallas se pueden dibujar encima de otras pantallas, controlando si las pantallas debajo de ellas se actualizan o dibujan. De esta manera, puedo tener varias pantallas activas al mismo tiempo con lógica y código autónomos específicos de esa pantalla, sin tener que preocuparme por ninguna otra pantalla.

Una pantalla de Pausa, por ejemplo, podría abrirse en la parte superior de mi pantalla de juego principal que no permite actualizaciones, pero permite dibujar debajo de sí misma. Una pantalla de inventario de personajes podría permitir tanto el dibujo como las actualizaciones, por lo que el juego sigue jugando mientras trabajas en tu inventario.

DrDeth
fuente
Así es exactamente como debe hacerse. Las pantallas deberían poder contener varias otras pantallas en una arquitectura similar a un árbol. Por lo tanto, su programa contiene una pantalla de juego, que contiene una pantalla de menú de pausa, que contiene una pantalla de configuración de audio y una pantalla de configuración del juego. etc
Iain el
1
¡Me encantaría ver un código fuente de ejemplo para esto! (Preferiblemente en C ++ / C # / Java)
Zolomon
1
Por desgracia, sólo tengo el código de producción en el momento, pero hay un concepto similar en la muestra de XNA Game Estado: creators.xna.com/en-GB/samples/gamestatemanagement
DrDeth
7

Claro, el estado del juego sería enorme, pero no hay razón para que el estado del juego en sí no pueda contener una máquina de estado para administrar sus datos. Las máquinas de estado jerárquicas son útiles.

Tétrada
fuente
4

Siempre me gusta pensar en cada "estado" como una "escena". Entonces, el video de apertura es una escena, solo estática. Los créditos son una escena. El menú es una escena. La única diferencia entre todos ellos es el nivel de interactividad y la lógica del juego.

Antonio
fuente
3

Tengo problemas con eso también, en realidad.

Digamos que tienes un juego.

En lugar de hacer que 'Juego' sea un estado como 'Cargando', 'Menú principal', etc. - En mi opinión, es mejor dejar que el Juego tenga varios estados:

"Cargando" - "mostrando el menú" - "en pausa" , etc.

El juego todavía se está ejecutando, pero cuando muestra el menú principal estaría en modo 'mostrar menú'.

Y cuando el juego no está en ningún estado en particular, simplemente se está ejecutando.

Tiene mucho más sentido, al menos para mí. :)

jacmoe
fuente
Estoy de acuerdo. Nadie quiere salir del Estado del juego solo para entrar en el Estado de pausa . Por otro lado: sigue siendo un sistema de estado ... simplemente anidado :)
bummzack
2

Un programa en línea (en el sentido tradicional de en línea, es decir, que se ejecuta y responde continuamente a la entrada, en lugar del significado conectado a Internet) generalmente consta de 3 cosas:

  • recolección y manejo de insumos
  • actualización de la lógica
  • salida

En términos generales, estos 3 están relacionados y cambian al mismo tiempo. Por ejemplo, al mostrar una pantalla de inicio, puede asignar todas sus teclas a un comando de 'cerrar pantalla' y la actualización puede estar desvaneciendo lentamente un gráfico con la salida solo mostrando ese gráfico. Pero cuando se juega un juego, todas las teclas se pueden asignar a diferentes comandos y la actualización está cambiando las propiedades de muchos objetos del juego.

Cuando lo ves de esta manera, tiene sentido separar una introducción de la creación de personajes y del juego propiamente dicho: cada uno tiene su propio conjunto de reglas de entrada, actualización y salida. Son casi como programas independientes que comparten datos y código de la biblioteca. Y, con esto en mente, generalmente tiene sentido tener un solo estado de Juego, ya que la jugabilidad es bastante homogénea en todo momento.

Por supuesto, si realmente tiene tipos de juego separados (por ejemplo, un ejemplo de RPG: Mapa del mundo, Mapa de la ciudad, Cutscene, Combate), con diferentes entradas, actualizaciones y salidas, no hay razón para que no pueda tener múltiples estados allí también en lugar de solo 1 estado de juego. Pero depende de tu juego.

Kylotan
fuente
1

Lo miro al otro lado. 'Menú', 'HighScores', "créditos" o lo que sea, podría considerarse como otro nivel, y ese estado no es necesariamente más ligero que su estado de "juego" (el estado del juego tiene más entidades en general, y diferentes, pero al final es solo otro nivel en el que las entidades muestran un comportamiento más predecible y los 'mapas' son generalmente menos intrincados).
Hacer ese cambio en su pensamiento definitivamente lo saca del síndrome del "menú aburrido".

Kaj
fuente
Iba a decir lo mismo ... Todos mis menús, pantallas, lo que sea, son solo otro nivel.
Speeder
1

En mi juego, tengo:

Execution Manager , que inicializa la aplicación (juego), carga recursos, libera recursos al salir de la aplicación, etc. Inicializa Application Engine, GameViewEngine, GameLogicEngine.

Game State Manager , que reside en GameLogicEngine, y es responsable de controlar las cosas relacionadas con el bucle principal del juego: detección de colisiones, cálculo de física, lectura de teclado, operaciones matemáticas, etc.

Inicialmente, tendía a tener solo un Game State Manager que era parte de mi GameLogicEngine. Sin embargo, tuve algunas dificultades para controlar la inicialización de los subsistemas principales (GameLogic, ApplicationEngine, ...). Podría haberse hecho, pero era más desordenado, en mi opinión.

Ahora las cosas me parecen más transparentes y estoy contento con el diseño.

Bunkai.Satori
fuente
0

Cambie el nombre del estado 'Juego' a algo como 'Gameplay'. Entonces tu lógica parece mejor; Dejas de jugar para ir al menú: sales del estado de Juego para ir al estado MainMenu.

Además, creo que cosas como la pausa, que requerirían que el juego esté en el mismo estado que cuando detuviste el juego, no deberían ser estados separados. ¿Estado infantil y anidación, tal vez? El juego tiene un menú de pausa.

El pato comunista
fuente
0

Creo que hay un buen método llamado pila de estado del juego. No he visto ningún documento o artículo al respecto, pero se ha extendido un poco por voz. Esencialmente, el estado de juego más alto en la pila se llama primero y puede hacer lo que quiera con entrada / representación, etc. El estado de juego más alto es el único que se permite empujar o reventar estados.

En mi motor, los estados de juego son en realidad solo listas de entidades de juego. Entonces tengo entidades que funcionan como menús. Mis estados de menú pausan el juego (al no actualizar el siguiente elemento en la pila) pero dejan que los otros estados empujen sus modelos al renderizador para que mi menú de pausa (que no cubre toda la pantalla) todavía tiene la representación del juego en la parte posterior.

Espero que eso dé una idea de un sistema un poco diferente que no se base en una máquina de estado.

Simon
fuente
0

¿Está bien tener un estado de introducción que dibuje una película y escuche intro, y luego un estado de carga que se repita en el administrador de recursos, y luego el estado del juego que hace prácticamente todo? ¿No te parece un poco desequilibrado también? ¿Me estoy perdiendo de algo?

Esto está perfectamente bien. O al menos, es una mejora sobre "tener un gran cambio feo dependiendo del estado del juego".

Me gustaría señalar que en la mayoría de los juegos ya necesitarás una especie de máquina de estados finitos para tratar con una entidad AI simple. El ejemplo típico son los enemigos que están en estado inactivo, atacando o muriendo.

Si tienes una máquina de estado finito suficientemente abstraída, puedes reutilizarla tanto para el objeto del juego como para tu IA; de repente no estás "invirtiendo" mucho esfuerzo en el estado del Juego, sino que estás reutilizando el código que usaste de todos modos.

Se produce un autoenchufe desvergonzado: he implementado una máquina de estado finito en mi biblioteca de juegos Lua, MiddleClass (concretamente, el complemento llamado MindState). Así es como haces algo con Game State .

egarcia
fuente
0

Un enfoque diferente para esto es utilizar un concepto del mundo de la programación funcional llamado Unión Discriminada . Si bien estos se encuentran típicamente en lenguajes FP, puede emularlos usando clases .

Básicamente, una Unión Discriminada es un tipo que siempre es uno de los ncasos, y los datos almacenados pueden variar con cada caso.

Por ejemplo:

type GameState =
  | Menu of MenuState
  | Playing of SimulationState

Aquí, nuestro GameStatetipo puede ser Menuo Playing. Si es Menuasí, contendrá un MenuStateobjeto. Si es Playingasí, contendrá un SimulationStateobjeto.

Para actualizar, haríamos matchen el estado y llamaremos a una función diferente en consecuencia:

let update gameTime = 
  let nextState = 
    match gameState with
    | Menu menuState -> updateMenu gameTime menuState
    | Playing simulationState -> updateSimulation gameTime simulationState

  // Mutate the current state
  gameState <- nextState

Y de manera similar para renderizar:

let render gameTime = 
  let nextState = 
    match gameState with
    | Menu menuState -> renderMenu menuState
    | Playing simulationState -> renderSimulation simulationState

Una ventaja de este enfoque es que puede manejar las cosas a través de los estados (como los recursos) con mayor facilidad sin globales o pasando objetos de "servicio".

sdgfsdh
fuente