5 de Octubre, 2014

Programando juegos para Spectrum

La verdad es que The Legend of Traxtor (ZX) ha sido un poco accidente: no lo planee demasiado y ha sido más un proceso de descubrimiento que otra cosa en cuanto a que funciona, pero hay muchas partes que no están nada bien implementadas (incluso llegando a afectar la jugabilidad; por ejemplo las explosiones bloquean los controles durante demasiado tiempo).

Las herramientas básicas que he usado son las siguientes:

  • Z88DK: compilador de C para máquinas basadas en el procesador z80, lo que incluye el ZX Spectrum (y otros de la época como el Amstrad CPC). Incluye un ensamblador y es bastante sencillo escribir código asm en linea. El runtime no es muy grande, pero en general es más lento y ocupa más espacio que escribir ensamblador a mano (claro).
  • La librería SP1: el Spectrum no proporciona soporte para sprites vía hardware, así que no hay otra que implementar un motor basado en las funcionalidades que sí están disponibles. En realidad no usé sprites en el juego, pero la librería es cómoda para manejar tiles (sobretodo si no sabes qué estás haciendo :P).
  • png2c: una herramienta que he programado para convertir imágenes en código C (datos en realidad) listo para usar con SP1.
  • png2scr: permite convertir imágenes al formato SCR que podemos mostrar en pantalla durante la carga del juego

Aparte existen gran cantidad de programitas que nos pueden ayudar en el proceso, pero la mayoría son binarios para Windows y, aunque muchos de ellos funcionan con WINE, programar png2c y png2scr ha sido entretenido y un buen ejercicio para ayudarme a entender cómo funcionan algunas cosas.

En general Z88DK tiene de todo para empezar, pero si quieres investigar un poco (y para dar un toque final más profesional), recomiendo echar un ojo a otras herramientas que pueden ser úiles (como bas2tap, porque el cargador BASIC que usar Z88DK es bastante limitado). Muchas de las herramientas incluyen el código fuente en C y compilan en Linux sin problemas.

Ya en cuanto a documentación, para Traxtor no necesité mucha porque los ejemplos y el código fuente de SP1 son bastante claros, pero si alguien quiere hacer las cosas un poco mejor a la primera recomiendo ojear How to Write Spectrum Games (de Jonathan Cauldwell, al final de la página; es en ensamblador, pero muy bien explicado) y en general la documentación enlazada en WOS.

Además hay kits para desarrollar juegos, como La Churrera de Mojon Twins (sí, españoles y a estas alturas... ¡leyenda! :D), o el Arcade Game Designer de Cauldwell; que incluso si no nos interesa usarlos, siempre podemos ojear su código fuente cuando nos quedemos atascados ;).

Hay 0 comentarios, anotación clasificada en: programming, speccy.

27 de Septiembre, 2014

»The Legend of Traxtor (ZX) · Acabo de publicar The Legend of Traxtor (ZX), una conversión del juego del mismo nombre que presenté a la GBJam 3. Aunque no es un juego complicado de implementar, tener que aprender a programar para una nueva plataforma no es fácil (y menos para el ZX Spectrum). Pese a todo no me ha llevado demasiado tiempo (lo he programado a ratos en C, con Z88DK), y estoy muy contento con el resulado. Ya comentaré más en detalle, porque he aprendido muchas cosas nuevas ;).

Hay 0 comentarios, anotación clasificada en: programming, 1gam, speccy.

14 de Septiembre, 2014

»Programando para el ZX Spectrum · Lo pasé bastante bien imitando los juegos del ZX Spectrum, y me picó el gusanillo: ¿cómo sería programar un juego para el Spectrum de verdad? Pues estoy contestando a esa pregunta con un emulador (no tengo el hardware) y Z88DK; intentando una conversión de The Legend of Traxtor. Por ahora parece vialble (y ya he publicado una herramienta: png2c), así que es posible que mi juego de Octubre sea algo especial ;).

Hay 2 comentarios, anotación clasificada en: programming, speccy.

8 de Septiembre, 2014

The Accolade

Ayer acabé y entregué The Accolade, un juego que he hecho en una semana para la SpeccyJam.

La idea era hacer un juego dentro de unas restricciones técnicas para que el resultado evocara el estilo de los juegos para ZX Spectrum, incluyendo la resolución máxima (256×192), el número de colores a usar y limitaciones más complicadas como la del attribute clash (no pueden haber más de dos colores en un celda de 8x8 pixeles). Se pueden leer las reglas en la página de la jam.

Al final he conseguido entregar un juego en isométrica, en el estilo de clásicos como Hero Quest, Alien 8, Batman and Knight Lore, con una mecánica tipo rogue (aunque los niveles no son aleatórios).

El juego no es muy largo, pero dado que es primeros de mes, aún tengo tiempo para añadir más contenido antes de considerarlo mi juego de Septiembre (la publicada es versión 0.9).

Estoy muy contento con el resultado, pese a las dificultades técnicas de la jam. El juego es bastante Spectrum, aunque funcione en una máquina de escritorio moderna. Además es oficialmente mi primer RPG, que casualmente se parece bastante a aquel juego en isométrica que hice en gwbasic cuando era un crío ;).

Hay 0 comentarios, anotación clasificada en: sfml, cpp, programming, rpg, speccy.

5 de Septiembre, 2014

»The Accolade está en camino · Aunque no correrá en un Spectrum de verdad, las reglas son bastante interesantes. Debería de estar acabado este fin de semana ;).

WIP

Es una especie de RPG (bastante sencillo), centrado en exploración y combate, con tintes de rogue-like. Veremos en qué queda ;).

Hay 0 comentarios, anotación clasificada en: 1gam, programming, sfml, rpg, speccy.

24 de Agosto, 2014

»DUAL Adventure · No he podido acabar lo que quería hacer (que la verdad era demasiado ambicioso), pero he subido DUAL Adventure como mi entrada para LD30. Lo de las 48h sigue sin encajarme, especialmente cuando se lía el fin de semana y no puedo dedicar todo el tiempo que me gustaría. Además es mi juego de Agosto para mi reto de un juego al mes, aunque no está completo (he aprendido muchas cosas sobre cómo funcionan los juegos de plataformas, con lo que lo considero un éxito pese a todo).

Hay 0 comentarios, anotación clasificada en: 1gam, javascript, programming.

20 de Agosto, 2014

»Resultados de gbjam 3 · The Legend of Traxtor, mi juego de Julio, ha quedado en puesto #21 de un total de 248 juegos. Se pueden ver los resultados de la votación en la página de la jam. Nada mal para un juego hecho en un par de días ;).

Hay 1 comentario, anotación clasificada en: 1gam, programming.

18 de Agosto, 2014

»¡Demasiadas Jams! · La verdad es que las game jams tienen mucnas cosas positivas. A mi me han ayudado a acabar juegos, que de otra forma nunca hubiera acabado. Además he aprendido muchas cosas y he mejorado mis habilidades en poco tiempo. Pero es que ahora están en todas partes, ¡hay demasiadas! Por ejemplo, las que lista CompoHub. Hoy esa web registra 6 en marcha, y eso que no están todas las que hay :o.

Hay 0 comentarios

12 de Agosto, 2014

»The matasano crypto challenges · Hice este reto vía email hace un tiempo, y es muy interesante. Me quedé atascado (perdí el interés) en el tercer bloque, pero puedo asegurar que es una de esas cosas que cuando las haces te da super-poderes ;). Yo utilicé Python y creo que fue buena idea (por el batteries included), pero en teoría cualquier lenguaje de programación puede valer.

Hay 0 comentarios, anotación clasificada en: programming.

10 de Agosto, 2014

Reproduciendo música en bucle en SFML

En SFML 2.1 tenemos una clase específica para reproducir música de fondo: sf::Music.

Su principal característica es que permite reproducir grandes ficheros haciendo streaming desde disco, con lo que no es necesario tener todo el fichero en memoria. Esto contrasta con sf::Sound, que se utiliza para sonidos en los que no puede haber latencia (se reproducen inmediatamente), y por lo tanto se almacenan en memoria.

Esta distinción está prensente en la mayoría de las librerías que he usado, aunque no siempre se utliza un interfaz diferente (por ejemplo, en pyglet es solo un parámetro en las funciones que cargan los ficheros de audio).

La clase sf::Music es bastante útil, pero le falta una funcionalidad que tampoco está disponible en muchas librerías, pero que en SFML me ha costado bastante implementar :(.

Un requerimiento frecuente cuando se reproduce música de fondo es que el fichero de audio tenga dos partes: la introducción y el cuerpo del bucle que se repite una vez la introducción ha terminado.

Hay distintas formas de implementar esto. A veces es más sencillo partir la música en dos ficheros y reproducir la segunda parte en bucle una vez la primera ha terminado, otras veces es mejor especificar el punto desde el cual el audio debe repetirse.

Para el primer caso normalmente es necesario que la librería nos permita usar un callback cuando un fichero de audio termina de reproducirse (este sistema lo uso en Javascript y Python), el segundo se puede implementar de diferentes formas, pero básicamente se trata de empezar la reproducción en un punto x en lugar de 0.

SFML utiliza un thread para reproducir el audio de forma que nuestro programa nunca se bloquee esperando operaciones con el audio. Esto en general es una buena idea, pero el sf::Music no proporciona opciones para comunicar los dos hilos de ejecución: el que corre nuestra aplicación y el que reproduce el audio. Lo mejor que tenemos en sf::Music es onGetData y onSeek; ambos ejecutados en el hilo que reproduce el audio.

La solución que he implementado en The Legend of Traxtor es la siguiente:

#include <SFML/System/Time.hpp>
#include <SFML/System/Mutex.hpp>
#include <SFML/System/Lock.hpp>
#include <SFML/Audio/Music.hpp>

class ExtMusic : public sf::Music
{
public:
    ExtMusic() : m_ext_loop(false) { }

    void setLoopOffset(float offs) {
        sf::Lock lock(m_ext_mutex);

        m_offs = sf::seconds(offs);
        m_ext_loop = true;
    }

protected:
    bool onGetData(SoundStream::Chunk &data) {
        sf::Lock lock(m_ext_mutex);

        bool result = sf::Music::onGetData(data);
        if (!result && m_ext_loop)
        {
            onSeek(m_offs);
            if (!data.sampleCount)
                sf::Music::onGetData(data);
            return true;
        }

        return result;
    }

private:
    sf::Mutex m_ext_mutex;
    sf::Time m_offs;
    bool m_ext_loop;
};

La idea de la clase ExtMusic (que extiende la clase sf::Music) es indicar desde qué segundo queremos que se repita el audio, y la reprodución saltará a ese punto en el fichero una vez nos quedemos sin datos para reproducir.

Además hay que usar un Mutex para garantizar el acceso exclusivo a los datos porque setLoopOffset se llamará desde un hilo que es distinto al que llamará a onGetData.

Se supone que SFML proporciona sf::SoudSource para que implementemos nuestras propias historias para reproducir audio, pero en mi caso era mucho más sencillo aumentar la funcionalidad de sf::Music que liarme con un interfaz de más bajo nivel como el que proporciona sf::SoundSource.

Al final el resultado es algo hacky (e incompatible con los bucles normales), pero bastante simple. La buena noticia es que alguien ha contribuido una implementación de bucles con punto de inicio, con lo que futuras versiones de SFML ya no tendrán esta limitación ;).

Hay 0 comentarios, anotación clasificada en: cpp, sfml, programming.

Entradas antiguas