Separar la física y la lógica del juego del código de la interfaz de usuario

12

Estoy trabajando en un simple juego de rompecabezas basado en bloques.

El juego consiste básicamente en mover bloques alrededor del área de juego, por lo que es una simulación de física trivial. Sin embargo, mi implementación, en mi opinión, está lejos de ser ideal y me pregunto si puede darme algunos consejos sobre cómo hacerlo mejor.

He dividido el código en dos áreas: lógica de juego e interfaz de usuario, como lo hice con muchos juegos de rompecabezas:

  • La lógica del juego es responsable de las reglas generales del juego (por ejemplo, el sistema de reglas formales en el ajedrez)
  • La interfaz de usuario muestra el área de juego y las piezas (por ejemplo, tablero de ajedrez y piezas) y es responsable de las animaciones (por ejemplo, movimiento animado de piezas de ajedrez)

La lógica del juego representa el estado del juego como una cuadrícula lógica, donde cada unidad es el ancho / alto de una celda en la cuadrícula. Entonces, para una cuadrícula de ancho 6, puede mover un bloque de ancho 2 cuatro veces hasta que colisione con el límite.

La interfaz de usuario toma esta cuadrícula y la dibuja convirtiendo tamaños lógicos en tamaños de píxeles (es decir, la multiplica por una constante). Sin embargo, dado que el juego apenas tiene lógica de juego, mi capa de lógica de juego [1] no tiene mucho que hacer, excepto la detección de colisiones. Así es como funciona:

  1. El jugador comienza a arrastrar una pieza.
  2. La interfaz de usuario solicita la lógica del juego para el área de movimiento legal de esa pieza y permite que el jugador la arrastre dentro de esa área
  3. El jugador suelta una pieza
  4. La interfaz de usuario ajusta la pieza a la cuadrícula (para que esté en una posición lógica válida)
  5. La interfaz de usuario le dice a la lógica del juego la nueva posición lógica (a través de métodos mutantes, que prefiero evitar)

No estoy muy contento con eso:

  • Estoy escribiendo pruebas unitarias para mi capa de lógica de juego, pero no para la interfaz de usuario, y resultó que todo el código complicado está en la interfaz de usuario: evitar que la pieza colisione con otros o el límite y encajarlo en la cuadrícula.
  • No me gusta el hecho de que la interfaz de usuario le dice a la lógica del juego sobre el nuevo estado, prefiero que llame a un movePieceLeft()método o algo así, como en mis otros juegos, pero no llegué lejos con ese enfoque, porque la lógica del juego no sabe nada sobre el arrastre y el ajuste que es posible en la interfaz de usuario.

Creo que lo mejor sería deshacerme de mi capa de lógica de juego e implementar una capa de física. Tengo algunas preguntas al respecto:

  1. ¿Es común esta capa de física o es más típico que la capa de lógica del juego haga esto?
  2. ¿El ajuste a la cuadrícula y al código de arrastre de piezas pertenecerían a la interfaz de usuario o la capa de física?
  3. ¿Una capa física de este tipo normalmente funcionaría con tamaños de píxel o con algún tipo de unidad lógica, como la capa lógica de mi juego?
  4. Una vez vi una detección de colisión basada en eventos en la base de código de un juego, es decir, el jugador simplemente arrastraba la pieza, la interfaz de usuario lo mostraba obedientemente y notificaba al sistema físico, y el sistema físico llamaba a un método onCollision () en la pieza una vez que se detecta una colisión. ¿Qué es más común? Este enfoque o preguntando por el área de movimiento legal primero?

[1] capa probablemente no sea la palabra correcta para lo que quiero decir, pero el subsistema suena exagerado y la clase es errónea, porque cada capa puede consistir en varias clases.


fuente
¿Mi respuesta ayudó? ¿Necesita más información?
Will Marcouiller
Por favor, vote a favor y acepte la respuesta si esto ha ayudado o cuente sus problemas para implementar dicha arquitectura o algo así, pero manténganos informados sobre su situación para que podamos ser de mayor ayuda. =)
Will Marcouiller

Respuestas:

3

Intentaré intentar responder esta pregunta, ya que puedo entender lo que estás preguntando, aunque no tengo mucha experiencia en el desarrollo de juegos, ya que todavía solo estoy aprendiendo.

Tal como lo veo, debes separar el código GUI de la lógica del juego y los objetos de dominio, es decir, las piezas del rompecabezas. Estas son de hecho tres capas separadas, y sí, layeres un término apropiado en mi opinión. A menudo se usa para explicar los conceptos de separar cada nivel de objetos de un sistema en subsistemas que son independientes entre sí.

En lo que respecta a la programación orientada a objetos, cada objeto será una clase. Por lo tanto, cada pieza de tu rompecabezas consistirá en una clase en sí misma y, por lo tanto, en el tablero de juego. El tablero de juego debe contener X piezas de rompecabezas dependiendo de su tamaño y capacidad de movimiento que desee darle al jugador.

Entonces, aquí están mis pensamientos sobre el tema: espero que ayude:

  1. La capa GUI: Esta capa contendrá métodos solo para mostrar las piezas en el tablero de juego para permitir la interacción entre el juego en sí y el jugador;
  2. La capa del controlador de juego: es responsable de las entradas del jugador. Esa es la capa que debería indicarle a una pieza que se mueva en las diferentes direcciones, y preguntar al tablero si habrá colisiones al moverse, etc.
  3. La capa Business: esta capa debe contener todas tus clases de negocios, es decir, las piezas de tu juego y el objeto del tablero que contiene las piezas del rompecabezas.

En esta arquitectura, la capa de la GUI le mostrará al jugador el estado del juego, la ubicación de cada pieza del rompecabezas. La capa GUI sería responsable de obtener las entradas del jugador y pasarla a una capa subyacente de Game Controller, que luego sería responsable de la detección de colisiones. Si no hay ninguno, entonces se puede ordenar que la pieza se mueva en esa dirección de entrada. Para hacerlo, simplemente deberías llamar a esta pieza MoveLeft,MoveRight, etc. métodos para hacer que la pieza se mueva. También puedes dejar que el tablero sepa qué pieza quieres mover, y luego ordena por sí sola el movimiento de la pieza, y la pieza luego se mueve en la dirección solicitada. Esta arquitectura facilita la prueba de cada fragmento de código en las diferentes capas, y luego le permite realizar pruebas unitarias, pruebas de integración y pruebas funcionales.

Sé que esto puede parecer un poco confuso a la vista, ¡y gracias a Dios si no lo es! Si necesita más información y ayuda, no dude en preguntar, estaré encantado de ayudarlo lo mejor que pueda, aunque soy un principiante en el desarrollo de juegos.

¡Gracias por leer! =)

Will Marcouiller
fuente
2
Lo que suena muy similar a Model View Controller.
Tenpn
Para ser sincero, cualquier descripción de la interfaz de abstracción de la implementación subyacente va a sonar como Model View Controller. Pero eso se debe a que la terminología y las técnicas utilizadas son las mismas (abstraerse de los detalles de implementación y separar la interfaz de usuario de la implementación). Pero supone un entorno muy simple. Aquí hay varias capas y hay controladores en cada capa. Separar la vista del modelo no es suficiente aquí, también debe separar el control de interacción del usuario del control del juego.
MrCranky
Me pregunto qué es tan complejo aquí, ya que estamos moviendo piezas de un rompecabezas a un tablero de juego delimitado. Los controles se obtienen de la GUI, que es una buena manera, y pasan a una capa de abstracción, es decir, el controlador del juego. El controlador del juego verifica las colisiones al moverse, luego le dice a la pieza que se mueva si no se detecta una colisión. La pieza del rompecabezas se mueve correctamente hacia la dirección solicitada y revela su nueva posición a través de su Positionfunción de obtención de propiedades, de modo que el controlador del juego ahora requiere que la GUI muestre esta pieza movida a esa nueva posición.
Will Marcouiller
heh, escribí en un blog sobre "MVC" en el desarrollo de juegos hace unos meses. Sí, es un buen concepto de puerta de enlace para aquellos no iniciados con el desarrollo del juego: codecube.net/2010/08/xna-for-the-everyday-developer
Joel Martinez
1
Perdón por la aceptación tardía, desafortunadamente me distraje del proyecto por un tiempo. Realmente me gusta el enfoque del controlador, ¡lo adoptaré!