Tutorial de Piston, programa juegos en Rust

Ya he hablado de Rust varias veces en este blog. La última vez fue en el tutorial de Iron, que os recomiendo ver si os interesa el tema del desarrollo web backend.

Hoy vamos a hablar de Piston. Piston es una de las librerías más antiguas del ecosistema Rust. Surgida cuando todavía no existía Cargo, esta librería está pensada para el desarrollo de juegos. No es la única que existe en Rust pero sí la más conocida. Piston es una librería que te enseñará Rust de la mejor forma. Y ahora quiero disculparme, porque Piston no es una librería, son un montón, pero eso lo veremos enseguida. En primer lugar creamos un proyecto nuevo con Cargo.

Ahora abrimos el archivo Cargo.toml, vamos a añadir las dependencias necesarias. Las dependencias en Piston son un poco complicadas, veamos:

  • Existen las dependencias core, implementan la API fundamental pero no pueden usarse por separado, son window, input y event_loop. Se usan a través de piston.
  • Los backends de window, existen actualmente 3 backends: glutin, glfw, sdl2. Se importan manualmente.
  • Graphics, una API 2D, no presente en core, pero al igual que las dependencias core necesita un backend.
  • Los backends de graphics son varios: opengl, gfx y glium.
  • Existe una dependencia que nos deja todo montado, piston_window. Esta trae por defecto el core de Piston, glutin, graphics y gfx.
  • Luego existen dependencias extra, como por ejemplo para cargar texturas, estas las podremos ir añadiendo según las necesite el proyecto.

Para simplificar añadimos piston_window únicamente:

 

 

Ahora abrimos el archivo main.rs. Añadimos la crate de piston_window y los módulos que vamos a usar.

 

Así mismo definimos un par de cosas para el resto del programa, la versión de OpenGL que usará Piston internamente y una estructura para guardar los movimientos de teclado.

 

En la función main podemos crear la ventana, especificando título y tamaño. Más opciones como V-Sync, pantalla completa y demás también están disponibles.

 

Ahora cargamos la tipografía Sinkin Sans, que vamos a usar para dibujar texto en pantalla. Como hay dos posibles localizaciones comprobamos esos dos lugares antes de salir del programa si no se consigue cargar la fuente.

 

Inicializamos la estructura de movimientos, generamos las dimensiones iniciales del rectángulo (que será un cuadrado en este caso), su color y la posición del ratón.

 

Ahora viene la parte importante, el bucle de eventos. El bucle va a funcionar infinitamente generando eventos por el camino (pueden ser eventos de inactividad también). Usamos la función draw_2d para dibujar en 2D. Hay dos maneras de dibujar un rectángulo, en primer lugar tenemos la forma abreviada y en segundo lugar una más completa que permite más opciones. Por último dibujamos el texto usando la fuente y realizando una transformación para que no quede el texto en la posición 0,0.

 

A continuación vamos a tratar cada evento de forma independiente, como todos los métodos devuelven Option, hemos de usar esta sintaxis con Some. En primer lugar tenemos un UpdateEvent, que básicamente nos informa del tiempo delta transcurrido. Recomiendo usar este evento para realizar los cambios en las geometrías, en este caso para mover el rectángulo.

Los siguientes dos eventos son opuestos, uno se activa cuando pulsamos una tecla y el otro cuando la soltamos. Comprobamos la tecla y modificamos la estructura movement en consecuencia.

Por último, si queremos comprobar clicks del ratón hacemos algo similar. He añadido código para que cambio el color del rectángulo si pulsamos sobre él.

A continuación un pequeño evento que guarda la última posición del ratón.

 

Y con esto ya tenemos hecho un ejemplo en Piston.

Si quieres tener un ejecutable para Windows sin que se muestre primero la consola debes compilar la versión que vas a distribuir con unos parámetros especiales. Si usas Rust con GCC usarás:

Si por el contrario usas Visual C++:

 

Piston todavía se encuentra en fuerte desarrollo, en la API estan documentados todos los métodos pero aun así muchas veces no se sabe como hacer ciertas cosas. Piston soporta además 3D, contando con una librería especializada en vóxels. Veremos como evoluciona esta librería.

9 opiniones en “Tutorial de Piston, programa juegos en Rust”

    1. Interesante pregunta. Una ejecución eficiente suele implicar no tener recolector de basura, por lo que C#, Java, Nim, Go y D se van fuera. C++ y Rust son la respuesta pero cada uno tiene sus pros y sus contras. Ambos son lenguajes complejos, más de lo que me gustaría a mí, cada uno por sus propios méritos. Hay gente que en este debate han visto con buenos ojos el intento de sustituir a C++ por parte de Rust pero les ha aterrorizado la complejidad que añade en otros lugares. Jonathan Blow defiende esta postura y se encuentra desarrollando Jai, pero como todavía no tenemos compilador disponible todavía es pronto para juzgarlo.

  1. como se compila esto en gnu? en mi sistema lanzo esta

    = note: /usr/bin/ld: unrecognized option ‘–subsystem’
    /usr/bin/ld: use the –help option for usage information
    collect2: error: ld returned 1 exit status

    1. Si estas en Linux no hace falta hacer nada, con cargo build se construye todo correctamente. Lo que he puesto es para Windows ya que en Windows las aplicaciones gráficas van en otro subsistema y hay que decírselo al linker (que puede ser GCC o MSVC).

  2. que es lo atractivo de rust?

    ha tardado bastante bajando y compilando dependencias, se parece a c++ con los incomodos let de lisp encima la carpeta del proyecto pesa la friolera de 68 MB

    tambien es necesaria la gestion de memoria a pelo como en C?

    digo, me gusta c, pero me gustaria que el comite añadiera tipos decentes al core del nucleo y no parches mediante librerias adicionales, el estandar dejase de ser poco especifico y se revisaran y añadieran nuevas librerias estandar, de momento estoy probando con go, parece un lenguje descente, pero hacer cast continuamente no es agradable, tampoco sus punteros de jugete.

    1. Lo atractivo de Rust es precisamente que no hay gestión de memoria a pelo como en C o C++ sin sacrificar rendimiento por ello. Muchos lenguajes son seguros pero dependen de un recolector de basura o máquina virtual y los hace lentos e impredecibles. Rust mantiene el rendimiento de C pero gestionando la memoria de forma más segura. En Rust se te garantiza que NUNCA se cerrará el programa por un crasheo, salvo que hayas llamado manualmente a panic!, hayas hecho un unwrap sin seguridad o uses bloques de código unsafe.

      Por otro lado las dependencias en Rust sí que ocupan bastante porque por defecto todas se compilan con símbolos de depuración y pesa bastante. Pero si compilas en modo release no ocupa tanto. En realidad el código final de los ejecutables no lo genera Rust sino LLVM, igual que pasa en el compilador de C++ Clang.

      Otra de las ventajas de Rust es su concurrencia pero eso es algo más complejo para usarlo en muchos casos.

      Rust no es el lenguaje idóneo para prototipos pero es robusto para aplicaciones finales, el compilador de Rust es muy estricto y a la mínima no va a compilar si haces algo mal con la memoria.

  3. la compilacion termino con exito, pero la ejecucion falla, parace un problema con alguna libreria

    thread ‘main’ panicked at ‘called Result::unwrap() on an Err value: DescriptorInit(PixelExport(0, None))’, src/libcore/result.rs:799
    note: Run with RUST_BACKTRACE=1 for a backtrace.

    solo era una prueba de concepto, rust es muy raro…

    1. Debe de ser un error de la gráfica, a mi también me pasó. Tuve bastantes problemas con una gráfica integrada de Intel para hacer funcionar el código. Luego probé en un ordenador con gráfica AMD moderna y todo fue bien. Puedes cambiar la versión de OpenGL que se usa (desde 2.0 hasta 4.5 creo), así lo solucioné yo.

  4. va, gracias por la explicacion. Seguire esperando el dia que los compiladores generen codigo eficiente, con una compilacion inmediata, que gestionen las dependencias automagicamente, eso, o esperar a un sucesor digno de C…

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *