Razón Artificial

La ciencia y el arte de crear videojuegos

[RAGE] Sistema de Objetos

Escrito por adrigm el 25 de enero de 2013 en Proyectos, RAGE | 7 Comentarios.

En RAGE, a diferencia de otras muchas bibliotecas y engines 2D las escenas no contarán con un método Draw(), al menos no por defecto. Todo juego sigue principalmente el siguiente esquema:

bucle_simple

Es el llamado GameLoop, este esquema es solo un concepto con los componentes más básicos, hay en medio luego siempre hay controles de tiempo, vsync, gestión de pausas, etc. Pero todo se basa en lo mismo actualizar todos los componentes (física, IA, etc), dibujarlos en pantalla según los nuevos datos, procesar los eventos (pulsación de teclas, cierre de una ventana, etc) y vuelta a empezar el ciclo. Esto en muchas bibliotecas se implementa por el medio de escenas, como puedes leer en este artículo.

El programador se debe de encargar de mediante tres métodos que se suelen llamar Event(), Update() y Draw() de implementarlos según requiera la escena en cuestión.

Hay una problemática común en el método de dibujado. Qué se debe dibujar y que no y en que orden.

Qué se debe dibujar

En la programación de videojuegos hay una regla de oro:

Nunca dibujar nada que no se vaya a ver en pantalla.

Esto es debido a que el dibujado de gráficos en pantalla es una de las operaciones más lentas. Imaginemos el siguiente escenario como el mapa de un juego donde el rectángulo rojo es la pantalla.

tutoSDL44

Obviamente el jugador solo está viendo los cuadros azulados ya sea en su totalidad o en parte, los cuadros grises son parte del mapa que no están a la vista y por tanto nunca hay que dibujarlos.

En qué orden se debe dibujar

Esto es otra cosa importante tengo mi mapa que contiene una superficie de terreno, un árbol y un héroe.

prioridad

En la imagen de la izquierda está claro que primero se debe dibujar los tiles de terreno, luego el sprite que representa al árbol y por último a nuestro héroe. Sin embargo en la de la derecha las prioridades cambian ahora el árbol se debe “dibujar” después de nuestro héroe para que de la sensación de que está pasando por detrás.

Manejar todo esto manualmente es un engorro, tienes que montar todo un sistema para detectar si tal gráfico es visible o no y tener cuidado de en que orden dibujarlo. Lo ideal sería un sistema que detectara si un gráfico está o no en pantalla para saber si lo dibuja o no y también que a nuestros gráficos se les pudiera asignar un número Z que representara su “profundidad” para alterar fácilmente el orden de dibujado.

El problema: la estructura de clases de SFML

SFML tienes en principio 3 tipos de objetos dibujables en pantallas: Sprites, Textos y Figuras (Qué a su vez hay tres tipos Círculos, Rectángulos y figuras convexas). Estos tipos de objeto heredan de dos clases bases: Transformable y Drawable. La primera le da las propiedades de poderse transformar: escalarse, rotarse, moverse, etc. Y la segunda la capacidad de que sea un objeto dibujable en pantalla. Este es el esquema:

classsf_1_1Transformable classsf_1_1Drawable

Podemos ver como todas heredan de Transformable y Drawable. El problema viene al que los tres objetos comparten la misma base (heredan de Transformable y Drawable), pero si se les quisiera añadir una propiedad común a todos ellos habría que añadirla por separado ya que no existen entre ellos ninguna relación.

Ahora viene nuestro ejemplo de antes en el que queremos también comprobar que otras cosas dibujables como textos y figuras se deban dibujar y en que orden, pues si son objetos dibujables y transformables igual que los sprites también tenemos que tener en cuenta esto que analizamos antes.

El problema viene que la idea es crea un objeto común llamado ObjectScene del que heredan Sprite, Shape y Text. Esta clase abstracta  herada de Drawable y Transformable así quedaría una relación entre todos ellos a las que se les podría añadir funcionalidades como un orden y la posiblidad de tratarlos como un conjunto. Este sería el esquema resultante:

diagrama_objetos

Ahora cada vez que queramos añadir una propiedad común a todos los objetos que se dibujan basta con añadirla a la clase SceneObject y actomáticamente todos tendrán esa propiedad, además de tener una clase común que sirve para mediante métodos virtuales representar y dibujar como un todo a objetos de la escena.

7 Comentarios en "[RAGE] Sistema de Objetos"

  1. Carlos dice:

    Yo el problema de en que orden dibujo lo he solucionado creando un vector de punteros con las direcciones de las entidades y ordenandolas por Y.

    Para el mapa lo que hago es crear capas (Tiled ayuda mucho en esto). El orden de dibujado de la solución que he adoptado es este:

    Capa Fondo
    Capa Terreno (hierba)
    Capa Objeto (tronco de árbol)
    Vector de entidades ordenado por Y
    Capa Oculta (las hojas del árbol)

    El problema de esto es que primero se dibuja el mapa, luego las entidades ordenadas y finalmente las capas que van por encima de las entidades (caso de las hojas del árbol).

  2. adrigm dice:

    Exacto carlos, aparte del problema que tu ya has visto en el que las capas no son suficientes (ejemplo del árbol en el que a veces cambian las prioridades). Hay otro problema y es que tu estás ordenando los objetos por un Z, bien, esto lo puedes hacer porque todos los objetos son del mismo tipo, seguramente Sprites. Si tu quieres además que otro tipo de objetos también dibujables entren en ese juego necesitas un padre común que les de las propiedades Z. Ahí es donde entre la clase SceneObject.

  3. Antonio dice:

    Buen articulo.

  4. Barduck dice:

    Alguna novedad del RAGE? Está muy interesante el proyecto, fuerzas! :)