lunes, 22 de marzo de 2021

¿Programación de juegos de 8 bits en 2020?

¿Alguna vez te has preguntado cómo se desarrollaban videojuegos en los años 80? Los ordenadores de la época eran muy diferentes a los que tenemos hoy en día, ¿cómo se harían juegos similares en la actualidad? Acompáñanos en este viaje a los 80 donde trataremos los ordenadores MSX y los lenguajes BASIC y ensamblador del Z-80, además de repasar las limitaciones técnicas de aquel entonces a la hora de desarrollar videojuegos. 

Charla impartida el 18 de diciembre de 2020, en la Facultad de Informática de Murcia y organizada por el Club GameDev. Si te la perdisteis ahora tienes la oportunidad de verla.




domingo, 7 de marzo de 2021

Archer10 (Apple II). Submission to the 2021 10-Liner Contest

Some weeks ago I had notice of a retro programming contest, yes through one of these wasap groups, the 10th Edition of BASIC 10 Liner Contest. The main idea is that you develop a game in BASIC with no more than 10 lines of code for 8 bit legacy computers. There are different categories depending on the maximum number of characters per line allowed. Simple, isn't it? I decided to go for a try, and made a MSX-1 program which I submitted to the contest. You can find a detailed description of the program in Archer 10 (MSX). Submission to the 2021 10-Liner Contest. After I finished, I asked myself: why not an Apple II port? Although I developed some programs in the 80s for Apple II, those were mostly CP/M with the Microsoft BASIC. You can find an example in Recuperación de código MBASIC para Apple II desde listados (it is in Spanish, but you can get the idea from the many pictures. Google translate might also be of some help). Anyway, it is never late for learning. And I had the appropriate material for getting into the job:

  • D. Finningan (2012) The New Apple II User's Guide. Mac GUI, Lincoln, IL (book)
  • M.L. Callerey, R. Schwarz (1984) Apple Graphics Tools and Techniques. Prentice-Hall (PDF)
I decided to mimic as much as possible the MSX-1 program mentioned above and develop an AppleSoft BASIC one. I had a gameplay and a sample 10-liner source code. That should be more than enough. I wanted to keep high resolution graphics, colors and sounds, even if those for the MSX were a little bit weird (disclaimer: I am very bad at gaming, coloring and music. The perfect combination :-).


The programming

The first thing I learned is that double high resolution graphics is not available to BASIC. And standard resolution graphics is crazy on coloring, not to mention the small available palette. Anyway, this did not prevented me to going ahead. Because of the small program size, complex sounds are also out of the game. Well, let's go for a simpler and less visually attractive version, but with the same gameplay I decided for the MSX-1 version.

I started to code right from the beginning thinking on a 10 lines program, with the experience of the MSX version. But because there were less graphical possibilities, I tried to enter the PUR-120 category. No way.  I had to reduce even more the visual aspects, and I wanted to support a minimum of them. Thus I ended up in the EXTREME-256 category. In addition to only ten lines of code, each line must not contain more than 256 characters. Overall, the code can not be larger than 2.5 Kb !!! To squeeze the code in this size you play the very old tricks. The BASIC interpreter uses a lexical analyzer that is based on keyword detection and not in delimiters. This basically means that you can write the code without white spaces. Who cares about readability !!! Then you use one-letter variables and single-digit line numbers (after all, remember, you can not use more than 10 :-). 

This was standard stuff in 10-liners. When you have to actually code the gameplay, all of a sudden, you get the headaches. First thing is AppleSoft BASIC does not have ELSE statements. The typical strategy is to leave conditionals at the end of lines, and use ELSEs to better manage decisions (in term of program space and lines usage). Soooo ... you have to decompose decisions and break them apart into different lines. Tricky, isn't it? Let's see.

The code

Lines 0 to 3 initialize the program and do all graphics background drawing and shapes definition. The order in which instructions are performed are related to the available line space. I tried different combinations. One interesting and important thing is that only line 3 is needed to replay, so you can GOTO 3 when the game is finished to start a new one.

Line 9 performs the text updating. It is coded in the form of a subroutine which is called at game initialization and whenever there is a hit or a fail.

Lines 4 to 8 implement the gameplay. They manage arrow and target movement, user input and scoring. The hit or fail of the arrow is checked in lines 6 (hit) and 7 (fail). Line 8 just closes the game loop. Should ELSE statements are available, this single-statement line would not be needed. Line 7 plays a nice trick. When the game is over, the game loop continues but arrow throwing is disabled. Until you press the space key and the game is re-initialized.

Lines 8 to 9 contain DATA definitions for the graphic shapes coded in decimal. These statements are put at the end of actual code, so we can make benefit of characters available in those lines. I tried to get rid of any character which is not ASCII standard. As I develop both on my Mac and on my Apple IIe, doing otherwise would produce me many headaches trying to preserve character coding.

The state of the game is coded using the following variables:
  • Y (Float): vertical position of the target in pixels. Varies in the 34 .. 125 range
  • S (Float): amount in pixels which is added/substracted to Y at each time step. It controls the velocity of the target. Its initial value is 1.0. Each time a hit occurs it is increased by 0.25 
  • X (Integer): horizontal position of the arrow in pixels. Varies in the 200 .. 32 range
  • D (Integer): linear distance between the arrow y position and the target y position
  • G (Integer): total score achieved
  • F (Integer): number of fails
  • H (Integer): score of the last hit, derived from D
  • B (Integer): state variable representing whether the arrow is moving (B=1) or not (B=0)
  • Q (Integer): state variable representing whether the game is active (Q=0) or not (Q=1)
I finally had a code of 1.7 Kb, in 10 lines of BASIC, with standard ASCII character coding. Nice. Goal achieved. You can find the code, a simulator disk file (DSK) and some multimedia materials here:


Instructions

You are a top-notch archer in the "Outdoor Archery World Series. Moving Target". You throw an arrow by pressing the space bar, and cannot throw a new one until it either makes a hit or a fail. The target moves so you have to carefully synchronize the arrow throwing with the target movement. The target speed gets increasing with each hit. You get points for each hit depending of how close the arrow gets to the target center. You are allowed a maximum of 3 failures, in which case the competition finishes and you get your final score. To start a new game press the space bar.



Are you ready? Can you make more than one hundred points? Let's try it.

Download the file archer10.dsk from GitHub and drag&drop it on the Drive 1 icon on the Virtual II emulator (a fantastic application by Gerard Putter, which is worth the price of the paid version). Once the disk is loaded, type the following command in the console and then press INTRO:

RUN ARCHER10.BAS

The game has sound, so remember to enable audio in your computer.

Enjoy playing!!



miércoles, 3 de marzo de 2021

Archer 10. Participación en el 2021 10-liner Contest


Hace algunas semanas tuve noticia de un concurso de programación retro, si, a través de uno de esos grupos de wasap, el 10th Edition of BASIC 10 Liner Contest. La idea principal es que tienes que desarrollar un juego en BASIC que no ocupe más de 10 líneas de código para cualquier ordenador original de 8 bits. Hay diferentes categorías dependiendo del número máximo de caracteres por línea permitidos. Sencillo, ¿verdad?. Decidí darle un tiento. Pensé "vamos, si son sólo 10 líneas de código, esto no puede ser muy complicado". No podía estar más equivocado. En este artículo explicaré qué y cómo he desarrollado mi participación en la edición de este año (2021), que he llamado Archer10.

El juego

Puesto que era la máquina con la que aprendí, decidí ir a por un programa MSX-1. Llamémosle nostalgia. Claro que, además, es la máquina que mejor conozco. Una vez decidido el equipo, la siguiente cuestión es pensar en un juego. Como no soy bueno en los juegos, decidí plagiarme yo mismo. Comencé con algunas ideas prestadas de Barcelona 92, un programa en BASIC que desarrollé cuando tenía 15 años y fue publicado en la revista MSX Club de Programas nº 3-4 (1985).

Después de algunas reflexiones-no-muy-profundas acabé con una idea sencilla de mecánica de juego: un blanco a la izquierda se mueve hacia arriba y hacia abajo. Controlas un arquero en la derecha que lanza flechas que se mueven de derecha a izquierda. Si impactas el blanco consigues puntos dependiendo de cómo cerca del centro lo haga. Tienes permitido un número máximo de fallos, tras los cuales el programa finaliza. Cuanto mayor sea la puntuación, mejor. Bien, bastante sencillo, pero un juego al fin y al cabo. Y presenta varias posibilidades que puedo explotar. Algo que no me gusta de muchos juegos es que son difíciles desde el principio. Como soy muy malo en los juegos, esto no facilita el que los pruebe. Así que decidí que el juego fuera sencillo al principio (el blanco se mueve muy despacio). Pero según se progresa, la dificultad se va incrementando poco a poco (al principio no se aprecia) de forma que tras algunos aciertos se torna realmente difícil. Y la restricción en el número de fallos hace que quieras repetir de nuevo e intentar superarte.

Estupendo. Ya tengo una idea de juego. Ahora a por la parte visual. Quería mostrar algunas de la estupendas características de los ordenadores MSX-1, por lo que decidí incluir gráficos en alta resolución (lo que se conoce como SCREEN 2 en el mundillo MSX), sprites por hardware, y sonido. Con profusión de colores, por supuesto (descargo de responsabilidad: no soy daltónico, pero definitivamente no soy bueno coloreando). Y, cómo no, también sonidos (descargo de responsabilidad: soy tan bueno con la música como con los colores).

La programación

Comencé programando una maqueta del programa sin restricciones, con un montón de líneas, para tenerlo funcionando. Quería asegurarme de que se pudiera jugar como yo quería. Después trabajé los gráficos para evitar la colisión de atributos de color (típico del procesador de vídeo de los MSX) y a la vez mostrar la mayor parte de la paleta de colores disponible. Básicamente tenía unas cien líneas de código y unas 3 Kb de espacio de programa. Definitivamente demasiado para un 10-liner.

Debido a los gráficos tenía claro que requeriría bastante espacio de programa. Además, mostrar texto en una pantalla gráfica requiere de muchas instrucciones que ocupan bastante espacio de programa. Y definitivamente quería texto. Sin compromisos.

De esta forma decidí participar en la categoría EXTREME-256. Además de sólo diez líneas de código, cada línea no debe de contener mas de 256 caracteres. De forma global ¡¡ el programa no puede ocupar más de 2.5 Kb !!. Para encajar el código en este tamaño hay que utilizar todos los viejos trucos. El intérprete BASIC utiliza un analizador léxico que está basado en la detección de palabras clave y no en los delimitadores. Esto significa que puedes escribir todo el código sin espacios. ¡¡¡ A quien le importa la legibilidad !!! Además, hay que usar variables con una sola letra y números de línea de un sólo dígito (después de todo, recordad, no puedes usar mas de diez :-).

Con esto consigues un código BASIC muy compacto, con la menor cantidad de espacio de almacenamiento posible. Esta es la parte fácil. Pero aún hay más, ya que hay que implementar la mecánica del juego que involucra acciones y decisiones. Cuando se programa tendemos a pensar en secuencias lógicas (o al menos eso deberíamos hacer) que acaban plasmándose en el uso de sentencias GOTO, y con el objetivo de mejorar la claridad, también GOSUB. El problema aquí es que debido al reducido número de líneas el uso de GOTOs y GOSUBs es muy limitado. Así que, en lugar de pensar en secuencias lógicas, donde tienes decisiones y acciones claramente aisladas, tienes que intercalar estas en el poco espacio disponible, incluyendo la mayor cantidad posible en una línea de código. Es un ejercicio de programación muy interesante que habitualmente no se practica.

El juego

Si digo que al final acabé con diez líneas de código, esto no debería ser una sorpresa. No hay spoiler. Las líneas 0 a 3 inicializan el programa y hacen todo el pintado del fondo gráfico y la definición de los sprites hardware. El orden en el que se realizan las instrucciones esta relacionado con el espacio disponible en las distintas líneas de código, paro lo que probé distintas combinaciones. Una cuestión interesante es que sólo se necesita la línea 3 para reiniciar el juego, de forma que se puede hacer un GOTO 3 cuando se acaba la partida.

Las líneas 4 a 7 implementan la mecánica del juego. Gestionan el movimiento del blanco y de la flecha, la interacción con el usuario y el puntaje. Tuve bastante suerte y pude implementar una subrutina en la línea 7, que se llama mediante un GOSUB 7 cada vez que la flecha llega a la parte izquierda de la pantalla (ya sea un acierto o un fallo). La línea 6 utiliza un truco muy interesante. Comprueba tanto el final de la partida como la reinicalización del juego (después de pulsar la barra espaciadora). Lo último mediante una llamada a GOTO 6. Esto produce una corrupción del estado del juego, pero como ya ha finalizado, ¡a quien le importa!. Cuando posteriormente se hace un GOTO 3 el estado del juego se inicia correctamente.

Las líneas 8 a 9 contienen las definiciones DATA para los sprites hardware codificados en hexadecimal. Debo señalar que esta NO es la forma más eficiente de almacenar esta información. Se pueden utilizar cadenas de caracteres, pero he sacrificado un poco de almacenamiento de programa (que al final no necesité) por la codificación de caracteres. Puesto que habitualmente desarrollo tanto en mi Mac como en mi Sony HB-F700S la copia entre estos preservando la codificación de caracteres es muchísimo mas simple así.

El estado del juego se codifica por medio de las siguientes variables:
  • Y (Float): posición vertical del blanco en pixeles. Varía en el rango 30 .. 135
  • S (Float): cantidad de pixeles que se le añaden/sustraen en pixeles a la Y en cada instante de tiempo. El valor uncial es 1,0. Cada vez que s produce un acierto se incrementa en 0,25.
  • X (Integer): posición horizontal de la flecha en pixeles. Varía en el rango 200 .. 22
  • G (Integer): puntuación total conseguida
  • F (Integer): número de fallos
  • H (Integer): puntuación del último acierto. Calculada como la distancia lineal entre la posición y de la flecha y la posición y del blanco. 
  • B (Integer): variable de estado que representa si la flecha está en movimiento (B=1) o no (B=0)
Finalmente conseguí un código de 2.1 Kb, en 10 líneas de código BASIC, y codificación de caracteres en ASCII estándar. ¡¡ Estupendo!!. Objetivo conseguido. Puedes descargar el código, un archivo de disco para simulador (DSK) y diverso material multimedia desde:


Instrucciones

Eres un arquero de alto nivel en la "Liga Mundial de Tiro con Arco al Aire Libre. Blanco Móvil". Lanzas flechas pulsando la barra espaciadora, y no puedes volver a lanzar hasta que aciertas el blanco o fallas. El blanco se mueve por lo que tines que sincronizar con cuidado el lanzamiento de la flecha con el movimiento del blanco. La velocidad del blanco se va incrementando con cada acierto. Consigues puntos según lo cerca que queda la flecha con respecto al centro del blanco. Tienes permitido un máximo de 3 fallos, en cuyo caso la competición finaliza y obtines tu puntuación final. Para iniciar un nuevo juego pulsa la barra espaciadora durante más de un segundo.

Estás listo? Puedes conseguir más de cien puntos? Vamos a ello.

Descarga el archivo archer10.dsk de GitHub y arrástralo a la consola azul de WebMSX (una aplicación estupenda de Paulo Augusto Peccin). Aparece una ventana emergente y entonces selecciona Drive A. A partir de ahí el simulador carga la imagen de disco y se queda a la espera de recibir comandos. Teclea el siguiente comando y después pulsa INTRO:

RUN "ARCHER10.BAS"

¿Demasiado complejo?

He preparado una página web que automáticamente carga y ejecuta el programa en WebMSX. Sigue este enlace para jugar en línea.

El juego tiene sonido, así que recuerda habilitar el audio en el ordenador.

¡¡¡ Disfruta jugándolo !!!