domingo, 11 de septiembre de 2016

Disponible versión V24 de la libreria 8BP con capacidad de scroll multidireccional

Hola amigos de 8BP

Ya está disponible en https://github.com/jjaranda13/8BP la version V24 de la libreria 8BP. Esta vez llega con la nueva funcionalidad de capacidad de scroll multidireccional. Esta nueva funcionalidad te va a permitir diseñar un “mapa del mundo” y hacer que tu personaje o tu nave se desplace por el, con tan solo una línea de código.
La documentación ha sido actualizada y tenéis la nueva versión del manual en github.


La nueva versión es retrocompatible, salvo por el comando MEMORY que hay que ejecutar al principio del juego, que esta vez es MEMORY 25999, es decir, que la nueva funcionalidad resta 1kB al programador, dejando 26KB libres para la lógica de tu programa BASIC (en esos 26KB no se incluyen los gráficos y música, eso se almacena en otro sitio, de modo que tu programa es mas grande realmente)

La idea para el scroll es sencilla: crearemos una lista de elementos que conforman el mapa del mundo (hasta 64 elementos a los que llamaremos “elementos de mapa” o “map ítems”). Cada elemento esta descrito por las coordenadas donde se ubica y la dirección de memoria donde se encuentra la imagen del elemento en cuestión (una casa, un árbol, etc). La imagen asociada a un elemento de mapa podrá tener el tamaño que quieras. Las coordenadas de cada elemento serán un numero entero positivo, desde 0 hasta 32000.
Una vez creado el mapa, invocaremos la función:

|MAP2SP, Yo, Xo


Esta función analiza la lista de los 64 elementos y determina cuales de ellos están siendo visualizados si el mundo se observa colocando la esquina inferior de la pantalla en las coordenadas (Yo, Xo). La función transforma en sprites los “map ítems”, ocupando las posiciones de la tabla de sprites de la cero en adelante. Esto puede consumir muchos o pocos sprites, dependiendo de la densidad de map ítems que tengas. En otra invocación posterior a la misma funcion, los map ítems que ya no estan presentes en la escena no consumiran sprites en la tabla, y otros map ítems tomarán el relevo. Esto significa que la funcion MAP2SP consume un número de sprites variable e indeterminado, que depende del número de map ítems visibles en pantalla en cada momento. En el ejemplo siguiente usaría 3 sprites al invocar a MAP2SP en las coordenadas señaladas

Si usas este mecanismo, tu personaje y los enemigos deben usar los sprites desde 31 hacia abajo, de ese modo evitaras posibles choques entre los sprites que usa el mecanismo de scroll y tus personajes.
Debes invocar MAP2SP en cada ciclo de juego o al menos cada vez que modifiques las coordenadas del punto de vista desde donde quieres visualizar el mundo.
Una vez aclarado el concepto vamos a revisar en detalle como se especifica el mapa del mundo y un ejemplo de uso de la funcion MAP2SP


La tabla donde daremos de alta todos los elementos del mapa se llama MAP_TABLE y se especifica en un fichero .asm llamado map_table_tujuego.asm
Esta tabla contiene las 64 entradas que definen las imágenes del mapa del mundo para tus juegos con scroll. La tabla se ensambla en la 26000 y contiene 3 parámetros globales (que ocupan 5 bytes en total) y una lista de "map items", los cuales están descritos por 3 parámetros cada uno (x, y, dirección de imagen)
La lista puede contener hasta 64 items pero se puede limitar con uno de los parámetros globales.
La lista ocupa los 5 bytes iniciales + 64 items x 6 bytes = 5+384=399 bytes

La tabla comienza con 3 parámetros:
- el alto máximo de cualquier map item
- ancho máximo de cualquier map ítem (debe expresarse como un número negativo)
- número de ítems
Los dos primeros parámetros son importantes para chequear cuando un sprite puede estar parcialmente apareciendo en pantalla, ya que la funcion MAP2SP no conoce ni averigua el ancho ni el alto de cada imagen. Tan solo conoce donde está situado el map ítem y suponiendo el alto y ancho máximos, averigua si ese ítem puede estar entrando en la pantalla. En caso de que asi sea, se crea un sprite a partir del map ítem. Si esos dos parámetros se ponen a cero, será necesario que la esquina superior izquierda del map ítem esté dentro de la pantalla para que dicho ítem sea transformado en un sprite.

Veamos un ejemplo del fichero llamado map_table_tujuego.asm

;MAP TABLE
;-----------------------
dw 50; maximo alto de un sprite por si se cuela por arriba y ya hay que pintar parte de el
dw -40; máximo ancho de un sprite por si se cuela por la izquierda (numero negativo)
db 64; numero de elementos del mapa.como mucho debe ser 64
; a partir de aqui comienzan los items
dw 100,10,CASA; 1
dw 50,-10,CACTUS;2
dw 210,0,CASA;3
dw 200,20,CACTUS;4
dw 100,40,CASA;5
dw 160,60,CASA;6
dw 70,70,CASA;7
dw 175,40,CACTUS;8
dw 10,50,CASA;9
dw 250,50,CASA;10
dw 260,70,CASA;11
dw 290,60,CACTUS;12
dw 180,90,CASA;13
dw 60,100,CASA;14


Para diseñar tu mundo te recomiendo que cojas un cuaderno a cuadros y vayas dibujando sobre el los elementos que quieres que tenga tu mundo. Cada cuadradito del cuaderno puede representar una cantidad fija como 8 pixeles o 25 pixeles. El caso es que debes tomarte tu tiempo en dibujar el mundo que deseas y el modo en que se va a recorrer. Por ejemplo hay juegos tipo gaunlet multidireccionales y otros de scroll vertical como el comando. Tú eliges pero en cualquier caso hazlo con tiempo y paciencia y el resultado valdrá la pena. Cada mapa seria como una fase del juego. En 8BP puedes cambiar el mapa cuando quieras usando funciones POKE, o bien tener mapas grabados en archivos de 400 bytes que cargas en la dirección 26000, etc. Hay muchas soluciones para hacer diferentes fases sin necesidad de recurrir a ficheros en disco, ya que cada mapa ocupa 400 bytes como mucho y puedes tener varias fases en memoria RAM

Ahora vamos a ver un ejemplo de uso de la función MAP2SP. Básicamente hay que invocarla una vez en cada ciclo de juego con las nuevas coordenadas del origen desde donde se observa el mundo.
La función creará un numero de sprites variable desde el sprite 0 en adelante y al crearlos lo va a hacer con sus coordenadas de pantalla adaptadas. Es decir, aunque un map ítem tenga una coordenada x=100, si el origen móvil lo ubicamos en la posición x=90 entonces ese sprite será creado con la coordenada de pantalla x’=x-90=10. La coordenada en el eje Y tendrá en cuenta que el eje Y en el amstrad crece hacia abajo, mientras que el mapa del mundo crece hacia arriba. Por ello la coordenada Y es adaptada usando la ecuación Y'= 200-(Y-Yorig). Pero no te preocupes, esta adaptación ya la hace la funcion MAP2SP. Tu solo tienes que ir cambiando el origen móvil desde donde se debe visualizar el mapa del mundo.


En este minijuego se ha realizado un mundo compuesto de casas y cactus y nuestro personaje camina entre los elementos. En este ejemplo, en caso de colisión (detectado con COLSPALL), el personaje no podrá continuar. En un juego de aviones en el que los map ítems sean “sobrevolables”, podríamos parametrizar la colisión para que solo se detecten colisiones con enemigos y disparos y no con elementos de fondo, usando COLSP, 32, <sprite inicial>, <sprite_final>.

Ahora veamos el listado, como ves, es muy pequeño, pero lo tiene todo: scroll multidireccional, lectura de teclado, cambio de secuencias de animación del personaje, detección de colision, música…

10 MEMORY 25999
20 MODE 0
30 ON BREAK GOSUB 280
40 CALL &6B78
50 DEFINT a-z
60 INK 0,12
70 FOR y=0 TO 400 STEP 2
80 PLOT 0,y,10:DRAW 78,y
90 PLOT 640-80,y,10:DRAW 640,y
100 NEXT
110 x=0:y=0
120 |SETUPSP,31,0,&X100001
130 |SETUPSP,31,7,1:dir=1:' direccion inicial hacia arriba
140 |locatesp,31,100,36
150 |MUSIC,1,5
160 |SETLIMITS,10,70,0,199: |PRINTSPALL,0,1,0
170 col%=32:sp%=32:|COLSPALL,@sp%,@col%
180 |COLSP, 34, 0, 0: REM colision en cuanto hay un mnimo solape
190 'comienza ciclo de juego
200 IF INKEY(27)=0 THEN x=x+1:IF dir<>3 THEN dir=3:|SETUPSP,31,7,3: GOTO 220
210 IF INKEY(34)=0 THEN x=x-1:IF x<0 THEN x=0:ELSE IF dir<>4 THEN dir=4:|SETUPSP,31,7,4
220 IF INKEY(67)=0 THEN y=y+2:IF x=xa AND dir <> 1 THEN dir=1:|SETUPSP,31,7,1: GOTO 240
230 IF INKEY(69)=0 THEN y=y-2:IF y<0 THEN y=0:ELSE IF x=xa AND dir <>2 THEN dir=2:|SETUPSP,31,7,2:
240 IF xa=x AND ya=y THEN dir=0 ELSE |ANIMA,31
250 |MAP2SP,y,x:|COLSPALL: IF col<32 THEN x=xa:y=ya:|MAP2SP,y,x ELSE xa=x:ya=y
260 |PRINTSPALL
270 GOTO 200
280 |MUSICOFF:MODE 1: INK 0,0:PEN 1


Y esto es todo, ahora solo queda empezar a hacer juegos con scroll tipo nemesis, commando, 1943, rambo, gaunlet y todo que se nos pase por nuestra imaginación. Eso si, usando nuestro querido BASIC de amstrad


hasta pronto!


2 comentarios:

  1. Muy bueno. En pocas líneas poder conseguir un juego con scroll. Sencillamente genial. Si en los ochenta hubiera tenido esta librería... buen trabajo!

    ResponderEliminar