¿Separo, y cómo, las preocupaciones de los objetos de entrada y del juego?

20

Probablemente en cada juego un desarrollador tiene que lidiar de alguna manera con la entrada, ya sean simples eventos de teclado y mouse, eventos táctiles o algo así como entrada de acelerómetro. Esta entrada directamente de efectos indirectos objetos en el juego. A veces, la misma entrada puede afectar diferentes objetos. Ahora he estado pensando en cómo modelar esto. A mi modo de ver, hay dos enfoques diferentes.

  • Deje que el objeto del juego lo maneje, suscríbase a los eventos y llame a sus propios métodos. Esto tiene la ventaja de dejar que los objetos del juego decidan qué entradas causan qué acción. Una desventaja parece ser que el código de entrada se destruye con el código objeto del juego "central". Además, los objetos del juego desconocen el estado del resto del juego y, a veces, tal vez no deberían actuar sobre los eventos de entrada. Esto no parece correcto.

  • Haga que un controlador de entrada general se encargue de todas las entradas y tome decisiones sobre quién puede manejar qué evento. Esto parece separar mejor las preocupaciones, pero combina estrechamente la clase de controlador de entrada con los objetos del juego. De alguna manera necesita saber quién quiere recibir qué evento y en qué estado. Esto tampoco parece correcto.

¿Qué estrategias estás usando para manejar esto?

Robert Massa
fuente

Respuestas:

7

Recomiendo separar los eventos de entrada de los objetos del juego para que pueda cambiar / actualizar rápidamente las metodologías de entrada sin tener que editar y depurar 10 clases de objetos. Por ejemplo, cambiar de controles de solo teclado a mouse + teclado, o simplemente reasignar teclas.

En lugar de acoplar estrechamente la entrada a los objetos individuales del juego, llame solo un método por señal de entrada única en el objeto del juego, y deje que decida la forma de ejecutarlo.

Use un controlador de entrada para realizar un seguimiento del estado de entrada:

Up press event   -> dir = up
Down press event -> dir = down

Siempre que cambie el estado de entrada, evalúe si los objetos del juego están listos para ser modificados:

set dir  ->  if gamestate != paused && battlemode == false
             ->  character.changeDir(dir);

Implemente métodos generales en sus objetos de juego, que pueden ser llamados por el controlador de entrada u otros objetos de juego, según sea necesario:

changeDir (dir)
setSpeed (walk/run)
Eduardiana
fuente
7

Recomiendo el enfoque MVC. En MVC, los objetos del juego solo tienen que preocuparse por modelar el sistema del juego y proporcionar una interfaz de alto nivel como move_left. Luego, tenga un objeto controlador que se preocupe por asignar entradas a llamadas modelo. No solo permite un fácil cambio de controles, sino que proporciona una buena interfaz para AI, son solo otro controlador.

En su segunda opción, dividiría el controlador de entrada en dos partes, una que maneje el toque real del dispositivo, el teclado, la aceleración, cualquier otra cosa que pueda arrojarle, que se asigne a un conjunto genérico de entradas. Luego, tenga una segunda parte que asigne entradas genéricas a entradas específicas del juego. Digamos que la flecha hacia arriba del teclado se asigna a la entrada1 y luego tocar la parte superior de una pantalla táctil también se asigna a la entrada1 y ahora se escribe una segunda pieza que asigna la entrada 1 para saltar. Ahora puede asignar cualquier dispositivo IO, así como la reproducción almacenada o las entradas AI a este sistema de entrada genérico y tener una pequeña parte específica del juego que carga lo que la entrada1 significa para el modelo.

metal de piedra
fuente
55
Hay mucha discusión en otra parte de este sitio sobre por qué MVC generalmente no es un patrón apropiado para los juegos; Lo que Stonemetal describe ni siquiera es MVC, es solo abstracción; y "Usar MVC" no es una respuesta, ya que MVC es una descripción de toda una clase de arquitecturas y no una forma particular de separar las preocupaciones (ni la única forma de hacerlo).
2
MVC debería darle A) un artículo de Wikipedia para leer B) una serie de variaciones sobre cómo enfocar la solución que se ha demostrado que funcionan C) Menciono la forma en que la configuraría donde el modelo expone una interfaz de alto nivel que el El controlador asigna entradas de bajo nivel (reales o sintéticas) a acciones de alto nivel y manipula directamente el modelo en lugar de algún sistema de eventos.
stonemetal
1

Sugeriría hacer que su juego (el Modelo ) defina una lista de posibles eventos de entrada (implementados como enumeraciones u objetos con una interfaz base en común). Las cosas tales como MovingRightStarted, MovingRightStopped, FiredWeapon1, Escape, etc ...

El juego define una estructura de datos (por ejemplo a queue) que su código de entrada (el controlador ) puede llenar con eventos de entrada.

Luego, su juego puede sondear la estructura de datos para obtener los eventos de entrada.

De esta manera, puede conectar diferentes tipos de controladores para alimentar el modelo:

  • Solo teclado
  • Teclado + Ratón
  • Palanca de mando
  • Pantalla táctil
  • Inteligencia artificial

Solo tiene que enviar eventos de entrada al modelo.

Splo
fuente
Creo que entiendo lo que quieres decir, excepto por tu elección de un queuetipo de datos para almacenar esto. ¿Podrías explicar por qué?
Robert Massa
Bueno, entre 2 encuestas de eventos de entrada del modelo, el controlador puede haber empujado varios eventos de acción, y es importante mantener el orden de entrada del usuario. Es por eso que elegí una estructura de datos FIFO. En realidad, es posible que también deba especificar a qué hora exacta sucedió la entrada.
Splo