TileMaps por Hardware – Tutorial 3
Este es un extracto del artículo originariamente publicado en mi web lacavernainformatica.com
Una vez entendido el funcionamiento de los Sprites, vamos a abordar el uso de TileMaps, pero empecemos por el principio.
Un TileMap no es mas que un conjunto de datos que nos permite posicionar de una manera predeterminada nuestros gráficos, (Tiles o baldosas), en nuestra pantalla.
Como veis, el enfoque es parecido al de los Sprites, pero un poco distinto. Para empezar los gráficos usados para configurar nuestro TileMap no disponen de métodos para calcular colisiones, ni movimientos automáticos como en el caso de los Sprites, ya que no tiene sentido.
Entonces para resumir, un TileMap no es mas que una forma de pintar gráficos en posiciones ya predefinidas de antemano. Pero claro ahora viene la pregunta del millón, ¿Y cómo hago yo un TileMap?
Pues aquí vamos a introducir una herramienta externa al Zx Spectrum Next, que no es otra que la fantástica página de herramientas para el Spectrum de Remy Sharp.
Desde la misma vamos a poder diseñar nuestros Sprites y utilizarlos para conformar nuestros TileMaps.
Ojo, como veis se designa Sprite al gráfico en si mismo, sea utilizado posteriormente como Sprite propiamente dicho o como un Tile.
Como podemos ver en la pantalla de arriba el editor nos permite de una forma parecida al editor del Zx Spectrum Next editar los gráficos de nuestros Sprites, aunque de una forma mas cómoda y con algunas funcionalidades más.
Una vez que tengamos nuestros gráficos podremos posicionarlos a nuestro gusto con el editor de Tile Map, definiendo las dimensiones del mismo y la posición de cada uno de los gráficos definidos anteriormente.
De todas formas y como siempre me gusta hacer, tenéis aquí un vídeo donde explico de manera interactiva el funcionamiento de las herramientas de Remy Sharp del siguiente juego donde pondremos en práctica el uso de Tile Maps
Bueno daremos por hecho que ya tenemos nuestros Tile Maps listos, con nuestros Sprites y todo necesario para poder empezar a incluirlo en nuestro código.
Por su puesto, como en todos los tutoriales, nos apoyaremos para las explicaciones en un juego, en este caso el Snake in Basic 😉
En Snape in Basic, hemos usado tres Tile Maps.
Uno para el menú de inicio, otro para decorar el escenario de nuestro juego y el último para la pantalla de finalización de partida.
Al igual que en la definición de bancos de Sprites, tendremos que definir nuestro banco de memoria para almacenar nuestro TileMap.
870 REM Aqui el meollo del asunto de los tiles. Cargamos el conjunto de sprites que usamos en el Mapa de Sprites/Tiles.
880 LOAD "TILES.SPR" BANK 17: LOAD "TILES.MAP" BANK 18: TILE BANK 17
Como veis realizamos dos cargas. Una de los Sprites que van a estar vinculados a nuestro TileMap y por otro lado el TileMap propiamente dicho.
Ahora definimos las dimensiones que vamos a usar en nuestro TileMap.
890 REM Aqui le indicamos las dimensiones de Mapa de Tiles. En este caso la pantalla completa
900 TILE DIM 18,0,16,16
910 REM posicionamos x elementos en la posicion de filas y columnas definidas
920 TILE 16,12
Si analizamos el comando.
TILE DIM n,offset,w,tilesize
Define bank n as containing the tilemap, starting at offset offset in the bank.
The tilemap is width w (1-2048) and uses 8x8 (tilesize=8) or 16x16 (tilesize=16)
tiles.
Luego simplemente le decimos que pinte la pantalla completa, nada de una porción.
TILE w,h <- TILE 16,12
TILE w,h AT x,y
TILE w,h TO x2,y2
TILE w,h AT x,y TO x2,y2
Draw section of screen from tilemap.
Number of tiles to draw is width w, height h.
Draw from tile offset x,y in the tilemap (or 0,0 if not specified).
Draw to tile offset x2,y2 on the screen (or 0,0 if not specified).
Aquí tenéis otro ejemplo de la carga para el fondo del juego en si mismo.
980 REM Cargamos los Tiles del fondo del juego en si mismo para cuando volvamos iniciar el juego correctamente
990 LOAD "TILESG.MAP" BANK 19
1000 TILE DIM 19,0,16,16
1010 TILE 16,12
Como veis es bastante sencillo de usar, aunque por su puesto se le pueden dar otros usos aparte de aplicarlo a la construción de un fondo estático.
Como es máxima en mis tutoriales, no nos quedaremos solo en el uso general de comandos, sino que ya de camino, analizaremos el código completo para poder avanzar también en otras cuestiones mas enfocadas en como pensar las cosas y resolver lo problemas que nos vamos encontrando.
¡Ojo, que seguro que existe una mejor implementación que la mía! 🙂
Como siempre, tenéis el código completo a vuestra disposición en:
https://github.com/Nextric/Snake-in-Basic
Pues entrado en detalles, como habéis podido ver, estamos hablando del clásico juego de la serpiente que tan popular se hizo con su inclusión en los Nokia 6110 y posteriores.
Aquí hemos tenido que abordar principalmente el algoritmo para calcular los movimientos de la cola conforme nos vamos haciendo mas grandes.
Si bien, inicialmente intenté realizar dichos cálculos con animación automática, resultaba muy complicado, por lo que opté por controlar manualmente los desplazamiento de las distintas partes de la serpiente.
En resumen, la idea es que cada vez que movemos el bicho, la cola de la serpiente revise en que posición ha estado su predecesor. Si solo tenemos un elemento en la cola, pues le preguntaríamos a la la cabeza de la misma y sino fuera así al elemento de la cola que viene delante.
630 REM Aqui tenemos el nucleo gordo del programa, tenemos que recorrer la cola para recoger la posicion del elemento anterior a el y actualizar su posicion
640 FOR v=longserp TO 0 STEP -1
650 IF longserp > v THEN LET %p=v+10: LET x=% SPRITE AT (p,0): LET y=% SPRITE AT (p,1): SPRITE v+11,x,y,5,1
660 NEXT v
Como vemos, no nos queda otra que desplazarnos por todos los elementos que tenga la serpiente, de ahí la ralentización que se produce en cierto niveles del juego y que hemos paliado aumentado la frecuencia del reloj del Next y haciéndolo pasar por una especie de bonus.
550 REM Aqui cambiamos la velocidad del procesador en funcion de la longitud de la serpiente, para evitar que se ralentice y darle un poco mas de vidilla. Ademas ponemos sonido de bonus especial
560 IF longserp=6 THEN DRIVER 49,2,10: RUN AT 2
570 IF longserp=30 THEN DRIVER 49,2,10: RUN AT 3
También veis el uso de un Driver de Sonido (ayfx.drv), que hemos usado para dotar de efectos de una forma sencilla a nuestro juego y que podéis ver también en la página de Remy Sharp.
El tema del uso del PEEK 64000 es solo para poder ejecutar numerosas veces el juego mientras que se estaba realizando su desarrollo y que no fallara indicando que el driver ya estaba instalado.
40 REM leemos de la posicion memoria 64000 para ver si yatenemos intalado el driver
50 driverok= PEEK 64000
60 REM Si ya lo hemos cargado lo desinstalamos para volvelo a instalar.De esta forma estamos seguros de que no lo llamados estando instalado y salimos en error al realizar varias ejecuciones
70 IF driverok=1 THEN .uninstall "ayfx.drv": REM PRINT "uninstall driver"
80 .install "ayfx.drv"
90 REM Si hemos llegado aqui marcamos driver como instalado
100 POKE 64000,1
110 REM Cargamos el banco de sonidos
120 LOAD "sounds.afb" BANK 20
Vamos a comentar dos cosas más antes de dejaros con el vídeo explicativo.
Una de ellas es la variación del Sprite de la serpiente en base a la dirección que llevemos.
670 REM En funcion de la direccion cambiamos el desplazamiento del sprite asi como la imagen de cada uno para girar la cabeza acorde al cambio de direccion
680 IF dirserp=1 THEN SPRITE 10,posx+vel,,0
690 IF dirserp=2 THEN SPRITE 10,posx-vel,,1
700 IF dirserp=4 THEN SPRITE 10, ,posy+vel,3
710 IF dirserp=3 THEN SPRITE 10, ,posy-vel,2
También usamos esto para no dejar moverse a nuestra serpiente en dirección contraria al avance en la subrutina de entrada de teclado.
Y por otro lado el cálculo que hay que aplicar a la puntuación para poder representarla mediante el uso de Sprites numéricos. Esto también ha sido debido al uso del borde como espacio de juego, ya que en el mismo no podemos imprimir texto, solo Sprites.
1040 REM gestion de los puntos
1050 REM tenemos que usar un bank de sprites para los numeros en la zona del border no valen los Tiles
1060 REM simplement ajustamos la operacion resto sumando 6 para que coincida con el valor relativo del sprite
1070 %s=score
1080 SPRITE 3,180,16,%s MOD 10+6,1: %s=%s/10: SPRITE 2,164,16,%s MOD 10+6,1:%s=%s/10: SPRITE 1,148,16,%s MOD 10+6,1:%s=%s/10: SPRITE 0,132,16,%s MOD 10+6,1
Simplemente vamos quedándonos con las cifras del número al aplicar el MOD 10, y luego para no tratar de nuevo ese dígito lo dividimos por 10. El sumar 6 elementos, es simplemente para que coincida con la posición donde se encuentran los Sprites de los números.
Y aunque sea solo por nombrarlas, también se ha tenido que gestionar la creación aleatoria de las manzanas teniendo en cuenta que no puede aparecer en un lugar ocupado por la serpiente, os aseguro que cundo crece suele coincidir bastante, jajaja.
Así que ya con ciertas nociones claras y como una imagen vale mas que mil palabras, aquí os dejo el vídeo analizando el código del juego en su totalidad.
¡Espero que con esta aproximación quede claro como usar los TileMaps en vuestros desarrollos!
¡Para la próxima entrada veremos otro uso molón de los TileMaps en un nuevo juego!