martes, 20 de octubre de 2015

Se apaga el semáforo...

Hoy toca otra actualización del estado de MotoGT2 (video incluido!). Está avanzando relativamente rápido. El tiempo inicial invertido en el diseño del motor está pagando y con creces. La base ya está sólida, todo lo que tenga que ver con gestión de recursos, despliegue de gráficos, gestión de escenas, lógica interna del juego, y entradas ya está modelado y tiene al menos una primer implementación funcional. El único sistema grande en el cual aún no avancé nada es el de sonido, pero habiendo resuelto los otros, no es algo que me preocupe.

Teniendo que lidiar a diario con mis otros proyectos, libres o no, que arrastran códigos de varios años atrás, trabajar de vez en cuando sobre MotoGT 2 es comparativamente un deleite. No es que sea el mejor código del mundo ni mucho menos, pero sí es la primera vez que desarrollo un proyecto con todas las especificaciones predefinidas desde el día cero, un proyecto que ya desarrollé una vez (por lo tanto tengo un modelo a no seguir), y además un proyecto desarrollado en un lenguaje mucho más moderno que los otros (como dijo Bjarne, C++11 no parece una simple extensión de C++03, sino que "se siente como un lenguaje nuevo").

Volviendo al estado del juego en sí, ya está avanzada la escena principal del juego, que es la de la carrera. Esta escena, por ser la de mayor complejidad y por ser la que requiere mayor eficiencia, tiene un tratamiento especial respecto a las otras, pero igual encaja bien en el sistema y no requiere de casos especiales en el motor.

Primer vuelta en Water Lane con MotoGT 2. Yo soy el de la izquierda, a la derecha está
la AI. Ahora hay dos modos de cámara. Faltan el OSD, las colisiones, algunas reglas
más de la IA, y la lluvia (que todavía no se lleva bien con multiplayer) entre otros.

A grandes rasgos, esto es más o menos así. Hay un struct que recopila toda la información necesaria para lanzar la escena (sea carrera de campeonato, carrera rápida, clasificación, práctica o lo que toque, todo está ahí). Cualquier menú que deba lanzar una carrera solo debe llenar este struct y pasárselo a Race, la clase que maneja la carrera durante su ejecución. Esta clase Race contiene al vector de motos (cada una es una RacingBike), al vector de vistas (RaceView, hay varias porque MotoGT ahora soportará multiplayer!!! con pantalla dividida), al mapa (información geométrica y topológica) de la pista, y otros auxiliares como los necesarios para el rendering.

Entre estos objetos para el rendering están el TrackRenderer y el BikesRenderer, encargados de consultar los estados del circuito y de las motos y dibujar lo que corresponda. Entonces estas clases solo se dedican a dibujar y nada más. Por otro lado, la lógica de cada cámara y su viewport está en RaceView, que también es observadora de alguna RacingBike en particular, y que delega a una clase adicional la parte específica del OSD (información en pantalla como el velocímetro, los indicadores de posición, el mini-mapa, etc). Y finalmente hay una RaceController que decide cuando empieza, cuando termina, cual es el objetivo, quien gana, como se calculan las posiciones, y todo eso. Es decir, mediante esta clase enchufo las "reglas" de la carrera, práctica, clasificación, o la sesión que sea.

Otros objetos importantes para el rendering son los sistemas de partículas. Con estos modelo la lluvia, el humo, la marcas en el pasto/barro/asfalto, la tierra, las chispas, etc. Funcionan de forma similar al BikeRenderer. Es decir, los contiene la clase Race, pero trabajan solos consultando los estados de las RacingBike para saber cuando y dónde emitir nuevas partículas.

Entonces cada RaceBike solo aplica la física, cuenta sus vueltas, y publica con mucho detalle sus resultados. El rendering ya está delegado a BikesRenderer. De forma similar el sonido se delegará a otra clase en el futuro. La determinación del estado de un corredor dentro del conjunto de la carrera lo hace el RaceController. Y las entradas (controles) a las cuales RaceBike responde, se delegan a una clase especial RBInput, que por polimorfismo puede especializarse para dar soporte a las entradas del usuario (teclado y/o joystick), o a la inteligencia artificial que controla a las motos restantes.

Bonito diagrama resúmen generado con graphviz mostrando 
las clases que intervienen durante la escena de la carrera.

Así las cosas, todo está separado: gráficos (XxxRenderer y PSysXxx), sonido (to-do), física (RacingBike), reglas de carrera (RaceController), vistas (RaceView), OSD (OSD) y entradas e IA (RBInputXxx). La clase Race primero instancia a las demás, y luego se dedica a gestionar su bucle de eventos interno, determinando el orden en que las otras realizan sus respectivos trabajos. Y todo esto, según los subsistemas que había comentado tiempo atrás, está del lado del Game. Es decir sin necesidad de tocar ni el Engine ni el Bridge. Dejo para el próximo post los comentarios sobre otros cambios que sí atañen a esos dos subsistemas.

1 comentario:

  1. ... e inicia la carrera

    va por buen camino el juego, pero el código es para codificadores con cierto y aun con grado avanzando en programación =(

    Se crearon varios juegos en QBASIC con instrucciones simples, si PSEINT agregara una salida para manejar gráficos, nos daría la oportunidad de iniciarnos también el la lógica primordial de creación de imágenes para luego migrar a los video juegos

    en el foro voy a crear un nuevo hilo de como seria esta implementación

    ResponderEliminar