Programación de videojuegos indie en Vala con SDL2.
Imagen derivada de Wikimedia Commons

Programación de videojuegos indie en Vala con SDL2.

Vamos a ver en una serie de post como utilizar la librería SDL2 para programar videojuegos. La programación de videojuegos es actualmente un campo muy amplio y especializado. En las grandes producciones de juegos, los llamados "AAA" o triple-A, los equipos de trabajo se componen no solo de programadores, también artistas, diseñadores, productores, compositores, probadores, guionistas, etc. siendo estos equipos de trabajo similares a los de las grandes producciones de cine.

Existen un campo dentro de la programación de videojuegos llamado indie games, o desarrollo de videojuegos independiente, en el que los juegos son desarrollados por una persona o un equipo pequeño de varias personas. Creo que es un campo muy interesante ya que para poder competir en un mercado tan duro como el de los videojuegos estos equipos indie tienen que exprimir al máximo la creatividad.

Desde el punto de vista técnico, en el desarrollo de videojuegos actualmente se utilizan mucho los "game engine", o motores de juegos. Estos motores van un paso más allá de las librerías, aportando todo un entorno de trabajo que automatiza las tareas de desarrollo usando normalmente un entorno gráfico.

La diferencia entre un "engine" y una "librería" está en el manejo del "Game Loop" (el bucle principal del juego). Con librerías, eres dueño del bucle principal del juego y llamas a las librerías. Un "engine" es dueño del bucle principal y llama desde éste a tu código (Game Programming Patterns - Robert Nystrom).

Entre los "engines" más usados podemos destacar Unity y Unreal, y entre las opciones de código abierto tenemos OGRE y MonoGame, aunque en ambos casos existen muchas más opciones.

De cualquier forma, lo que voy a usar en estos ejemplos es SDL2 que es una librería que nos proporcionar acceso de bajo nivel al hardware de audio, teclado, mouse, joystick y gráficos a través de OpenGL y Direct3D, lo que nos va a facilitar enormemente el desarrollo de juegos 2D, pero manejando nosotros mismos el bucle principal "Game Loop".

En cuanto a los lenguajes de programación, en el mundo de los videojuegos hay que decir que el líder indiscutible es C++. Este es un lenguaje de bajo nivel pero con las características de los lenguajes Orientados a Objetos, lo que permite estructurar el código con las facilidades que ofrece este paradigma. Otro de los lenguajes que se usan mucho (sobre todo por que es el usado en el "engine" Unity) es C#. Ambos lenguajes son de paradigma orientado a objetos, aunque en el primero somos los encargados de manejar la memoria y en el segundo la memoria se gestiona de forma automática (utilizando un garbaje collector).

Yo voy a utilizar el lenguaje Vala, lenguaje con una sintaxis parecida a C#, con gestión de memoria automática (en este caso usando un conteo de referencias) y usando un paradigma orientado a objetos lo que nos permite aprovechar todos los patrones de diseño y técnicas de desarrollo ampliamente probadas durante las últimas décadas usando la OOP. Por otro lado este lenguaje permite un acceso a bajo nivel y produce unos ejecutables de rendimiento cercano no solo al lenguaje C++ sino al rendimiento del lenguaje C. Pero sobre todo, es un lenguaje muy gratificante de usar y que permite disfrutar de la programación, que en mi caso es mi principal aliciente.

Ejemplo de uso de SDL2 en Vala

Vamos a ver un ejemplo básico del uso de la librería SDL. El código es básico pero sigue la estructura que utilizaremos cuando diseñemos un juego: Iniciar SDL y crear un bucle desde donde vamos actualizando y dibujando las escenas. En el bucle comprobamos también las entradas del usuario (teclado, mouse o joystick), en este ejemplo solo comprobamos la pulsación de alguno de los botones del mouse para finalizar.

Instalación de dependencias

Lo primero instalamos la librería desde los repositorios. En distros Debian/Ubuntu/Elementary :

$ sudo apt install libsdl2-dev

Instalamos también la librería SDL2_gfx que nos facilita dibujar figuras geométricas (lineas, círculos, rectángulos, etc.) muy útil para los ejemplos:

$ sudo apt install libsdl2-gfx-dev

Código

basicsdl.vala
/* 
 * basicsdl.vala 
 * 
 * (c) Author: David Quiroga 
 * e-mail: david [at] clibre [dot] io 
 * 
 **************************************************************** 
 * Description: 
 * 
 * Basic SDL2 demo with Vala 
 * 
 * SPDX-License-Identifier: GPL-3.0 
 */ 
 
using SDL; 
using SDLGraphics; 
 
public class BasicSDL : GLib.Object 
{ 
    private const string window_name = "Basic SDL - Click mouse button to finish"; 
    private const int DEFAULT_SCREEN_WIDTH = 1280; 
    private const int DEFAULT_SCREEN_HEIGHT = 720; 
    private const int DELAY = 60; 
 
    private Video.Window window; 
    private Video.Renderer renderer; 
    private GLib.Rand rand; 
    private bool done = false; 
    private int16 size = 10; 
    private int16 step_size = 10; 
    private uint32 color = 0x6495ed00; 
 
    public BasicSDL () { 
        init_SDL (); 
        this.rand = new GLib.Rand (); 
    } 
 
    private void init_SDL () { 
        if (SDL.init (SDL.InitFlag.VIDEO) != 0) { 
            critical ("Couldn't initialize SDL: %s\n", SDL.get_error()); 
        } 
 
        SDL.Hint.set_hint_enabled (SDL.Hint.VIDEO_HIGHDPI_DISABLED, false); 
 
        window = new Video.Window (window_name, 
                                    (int) Video.Window.POS_CENTERED, 
                                    (int) Video.Window.POS_CENTERED, 
                                    DEFAULT_SCREEN_WIDTH, 
                                    DEFAULT_SCREEN_HEIGHT, 
                                    0); 
 
        renderer = Video.Renderer.create (window, -1, 
                                            Video.RendererFlags.ACCELERATED | 
                                            Video.RendererFlags.PRESENTVSYNC); 
 
        SDL.Input.Cursor.set_relative_mode (false); 
        SDL.Input.Cursor.show (1); 
 
        assert (renderer != null); 
    } 
 
    ~BasicSDL () { 
        print ("Closing SDL...\n"); 
        SDL.quit (); 
    } 
 
    public void run () { 
        while (!this.done) { 
            prepare_scene (); 
            draw (); 
            present_scene (); 
            process_events (); 
            SDL.Timer.delay (DELAY); 
        } 
    } 
 
    private void prepare_scene () { 
        renderer.set_draw_color (32, 32, 32, 255); 
        renderer.clear(); 
    } 
 
    private void present_scene () { 
        renderer.present (); 
    } 
 
    private void draw () { 
        int16 x = (int16) DEFAULT_SCREEN_WIDTH / 2; 
        int16 y = (int16) DEFAULT_SCREEN_HEIGHT / 2; 
        Circle.fill_color (renderer, x, y, this.size, color); 
        this.size += step_size; 
        if (this.size >= (y - 40) || this.size <= 10) { 
            step_size *= -1; 
            color = (step_size < 0)? color: rand.next_int (); 
        } 
    } 
 
    private void process_events () { 
        Event event; 
 
        while (Event.poll (out event) != 0) { 
            switch (event.type) { 
            case EventType.MOUSEBUTTONDOWN: 
                this.done = true; 
                break; 
            default: 
                break; 
            } 
        } 
    } 
 
    public static int main (string[] args) 
    { 
        print ("Loading SDL...\n"); 
        var gameloop = new BasicSDL (); 
        gameloop.run (); 
        return 0; 
    } 
} 

Para construir la aplicación:

$ valac --pkg sdl2 --pkg SDL2_gfx basicsdl.vala

Voy a poner los ejemplos de código en un repositorio git, por lo que también podemos usar éste para descargar los ejemplos:

$ git clone https://git.clibre.io/gaming/basicsdl.git

En los ejemplos del repositorio utilizaré meson para construir los ejecutables (también incluye los vapi necesarios). En caso sería:

$ cd basicsdl
$ meson build
$ cd build
$ ninja

Podemos instalar la aplicación con ninja install aunque no es necesario.

También podemos abrir la aplicación con gnome-builder y ejecutarla desde ahí.

Si tenemos problemas con alguna dependencia es que nos falta alguna de las herramientas de compilación. Podemos instalarlas con:
sudo apt install build-essential valac meson git

Uso básico de SDL2 

En cuanto al código, en el constructor iniciamos la ventana y el render de SDL que utilizaremos a lo largo de la aplicación. Luego llamamos al método run () que contienen nuestro Game Loop desde donde se van ejecutando las escenas que queremos mostrar. Al final del bucle tenemos un retardo que nos permite ejecutar las escenas a una velocidad concreta. Iremos viendo todo esto con más detalle en posteriores entradas.

Modificado por última vez enMartes, 14 Septiembre 2021 16:10
(1 Voto)
Etiquetado como :

Deja un comentario

Asegúrese de introducir toda la información requerida, indicada por un asterisco (*). No se permite código HTML.