Skip to content

Sesion: Video Juegos 1

Juan Gonzalez-Gomez edited this page Oct 16, 2021 · 59 revisions

Contenidos

Sesión CPCRetroDev: Planificación

Click to see the youtube video

Sesión: Revisión del proceso de ensamblado y ficheros

Click to see the youtube video

Sesión: Convertir y dibujar sprites en ensamblador con CPCtelera

Click to see the youtube video

Cambio del modo de video

Vamos a cambiar el modo de vídeo a 0. Este modo tiene una resolución de 160x200 pixeles, con 16 colores. Ahora se usan 4 bits por pixel, por lo que en cada byte hay 2 pixeles. Los bits 7,5,3 y 1 (impares) contienen el color del pixel izquierdo, y los bits 6,4,2 y 0 (pares) los del pixel derecho

Lo primero que hay que hacer es deshabilitar el firmware, y luego cambiar el modo

El main.s queda así

;;===============================
;;  Main program entry
;;===============================
_main::

  call cpct_disableFirmware_asm

  ld c,#0
  call cpct_setVideoMode_asm

  ;;-- Draw the Ground
  ld a, #0xA0     ;;-- yellow pattern
  call drawGround

  main_loop:

    call hero_erase     ;; Erase the hero
    call obstacle_erase ;; Erase the bullet

    call hero_update     ;; Update the Hero
    call obstacle_update ;; Update the bullet

    ;;-- Check colision
    call hero_getPtrHL
    call obstacle_checkCollision
    ld (0xC000),a        ;;-- Draw collision
    ld (0xC001),a 
    ld (0xC002),a
    ld (0xC003),a

    call hero_draw      ;;-- Draw the hero
    call obstacle_draw  ;;-- Draw the bullet
  
    ;;-- Wait for the raster to finish
    call cpct_waitVSYNC_asm
    
    jr main_loop
  • Resultado:

Vemos como los colores han cambiado

Diseñando sprites

Vamos a pintar un sprite de 8x12 pixeles usando gimp. Abrimos gimp, creamos una imagen nueva (File/New) y le indicamos que tiene un tamaño de 8x12 píxeles. Como la imagen muy pequeña, hacemos zoom:

Activamos el grid (Vies/Show Grid)

Para que el grid se vea como en la imagen hay que configurar para que la distancia entre líneas verticales y horizontales sea de 1 pixel. Esto lo hacemos desde el menú Edit/preferences/Default Image/Default grid

Tambien podemos cambiar el color del grid. Una vez hecho esto, reiniciamos (y volvemos a crear una imagen nueva para que aparezca el grid con los cambios)

Ahora dibujamos nuestro sprite utilizando la brocha. Ponemos un tamaño de 1, y la dureza y fuerza al 100%

Este sprite de prueba lo he exportado a png y está en el fichero smily.png

También es posible dibujar los sprites vectorialmente con inkscape. Desde el menú View/Page grid se activa la rejilla. Es importante activar las opciones de ajuste a la rejilla, en la parte de la derecha

Luego se exporta, indicando que el tamaño de la imagen es (en este caso) de 8x8. Este es el fichero resultante: chess.png

La paleta de colores

El amstrad CPC puede mostrar un total de 27 colores, pero solo se pueden utilizar los que están disponibles en la paleta. En el modo 1 tenemos una paleta de 4 colores, que por defecto son: azul(0), cyan(1), amarillo(2) y rojo(3). Estos cuatro colores se pueden cambiar por otros 4 diferentes, dentro de la gama de colores disponibles

En el modo 0 se tienen un total de 16 colores en la paleta por defecto (0-15), donde el 0 es el negro y el 15 el blanco brillante

En este enlace: Amstrad CPC palette está la información sobre las paletas de colores

Conversión de sprites

En la carpeta cfg de nuestro proyecto se encuentran los ficheros de configuración. Uno de ellos es el image_conversion.mk. Es una macro para convertir automáticamente las imágenes en datos.En este archivo se define la paleta. Es una lista con los valores firmware asignados a cada color de la paleta

PALETTE={0 1 3 4 7 9 10 12 13 16 19 20 21 24 25 26}

Los colores asinados son los siguientes:

Numero Numero firmware Color
0 0 Negro
1 1 Azul
2 3 Rojo
3 4 Magenta
4 7 Purple
5 9 Verde
6 10 Cyan
7 12 Amarillo
8 13 Blanco
9 16 Rosa
10 19 Verde marino
11 20 Cyan claro
12 21 Lima
13 24 Amarillo brillante
14 25 Amarillo pastel
15 26 Blanco brillante

Así, el color 4 de la paleta es el purpura (por defecto) Esto lo podemos cambiar y definir los 16 colores que nosotros queramos

A continuación se encuentra la llamada a la macro IMG2SPRITES para realizar automáticamente la conversión de la imagen a datos:

PALETTE={0 1 3 4 7 9 10 12 13 16 19 20 21 24 25 26}
$(eval $(call IMG2SPRITES,assets/smily.png,0,sprite,8,12,$(PALETTE),,src/sprites/,hwpalette))

Esta macro toma el fichero smily.png con nuestro sprite. La conversión la queremos para el modo 0. El prefijo asignado es sprite. El tamaño es de 8x12 y se le indica que use la paleta definida PALETTE. El resultado (los datos) los generará en el directorio src/sprites. Este directorio lo tenemos que crear a mano (si no está ya creado)

Los ficheros fuente con los sprites los metemos en la carpeta assets (que hay que crear). Este es el arbol de proyectos tal cual lo tenemos inicialmente:

$ tree
.
├── assets
│   ├── chess.png
│   ├── chess.svg
│   ├── smily.png
│   └── smily.xcf
├── cfg
│   ├── build_config.mk
│   ├── image_conversion.mk
│   ├── music_conversion.mk
│   └── tilemap_conversion.mk
├── Makefile
└── src
    ├── bullet.h.s
    ├── bullet.s
    ├── cpctelera.h.s
    ├── hero.h.s
    ├── hero.s
    ├── main.s
    ├── obstacle.h.s
    ├── obstacle.s
    └── sprites

Ahora ejecutamos make. Suceden muchas cosas. Las vemos poco a poco:

Se invoca a la herramienta cpct_img2tileset para convertir el fichero assets/smily.png. Se generan los ficheros src/sprite/smily.c y src/sprite/smily.h

  • src/sprite/smily.h: Se definen las constantes globales sprite_palette y sprite_smily
// Data created with Img2CPC - (c) Retroworks - 2007-2015
#ifndef _ASSETS_SMILY_H_
#define _ASSETS_SMILY_H_

#include <types.h>
extern const u8 sprite_palette[16];

#define SPRITE_SMILY_W 4
#define SPRITE_SMILY_H 12
extern const u8 sprite_smily[4 * 12];

#endif
  • src/sprite/smily.c: Y aquí sus contenidos (En C)
#include "smily.h"
// Data created with Img2CPC - (c) Retroworks - 2007-2015
// Palette uses hardware values.
const u8 sprite_palette[16] = { 0x54, 0x44, 0x5c, 0x58, 0x45, 0x56, 0x46, 0x5e, 0x40, 0x47, 0x42, 0x53, 0x5a, 0x4a, 0x43, 0x4b };

// Tile sprite_smily: 8x12 pixels, 4x12 bytes.
const u8 sprite_smily[4 * 12] = {
	0x00, 0x51, 0xa2, 0x00,
	0x00, 0xf3, 0xf3, 0x00,
	0x51, 0xf3, 0xf3, 0xa2,
	0xf3, 0x51, 0xa2, 0xf3,
	0xf3, 0x51, 0xa2, 0xf3,
	0xf3, 0x51, 0xa2, 0xf3,
	0xf3, 0xf3, 0xf3, 0xf3,
	0xf3, 0xf3, 0xf3, 0xf3,
	0x51, 0x51, 0xa2, 0xa2,
	0x51, 0xa2, 0x51, 0xa2,
	0x00, 0xf3, 0xf3, 0x00,
	0x00, 0x51, 0xa2, 0x00
};

Este es el árbol de proyecto con los nuevos cambios:

.
├── assets
│   ├── ...
├── cfg
│   ├── build_config.mkimage_conversion.mk
│   ├── ...
├── obj
│   └── sprites
│       ├── smily.asm
│       ├── smily.lst
│       ├── smily.rel
│       ├── smily.rst
│       └── smily.sym
└── src
    ├── ...
    └── sprites
        ├── smily.c
        └── smily.h

El proceso se resume así:

assets/smily.png --> src/sprites/smily.c --> obj/sprites/smily.asm

Hemos obtenido un fichero en ensamblador: smily.asm que contiene la paleta y los sprites para usarlos directamente en nuestras funciones de ensamblador. Las etiquetas que están disponibles para usarse son: _sprite_palette y _sprite_smily

...
;--------------------------------------------------------
; code
;--------------------------------------------------------
	.area _CODE
	.area _CODE
_sprite_palette:
	.db #0x54	; 84	'T'
	.db #0x44	; 68	'D'
	.db #0x5c	; 92
	.db #0x58	; 88	'X'
	.db #0x45	; 69	'E'
	.db #0x56	; 86	'V'
	.db #0x46	; 70	'F'
	.db #0x5e	; 94
	.db #0x40	; 64
	.db #0x47	; 71	'G'
	.db #0x42	; 66	'B'
	.db #0x53	; 83	'S'
	.db #0x5a	; 90	'Z'
	.db #0x4a	; 74	'J'
	.db #0x43	; 67	'C'
	.db #0x4b	; 75	'K'
_sprite_smily:
	.db #0x00	; 0
	.db #0x51	; 81	'Q'
	.db #0xa2	; 162
	.db #0x00	; 0
	.db #0x00	; 0
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0x00	; 0
	.db #0x51	; 81	'Q'
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0xa2	; 162
	.db #0xf3	; 243
	.db #0x51	; 81	'Q'
	.db #0xa2	; 162
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0x51	; 81	'Q'
	.db #0xa2	; 162
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0x51	; 81	'Q'
	.db #0xa2	; 162
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0x51	; 81	'Q'
	.db #0x51	; 81	'Q'
	.db #0xa2	; 162
	.db #0xa2	; 162
	.db #0x51	; 81	'Q'
	.db #0xa2	; 162
	.db #0x51	; 81	'Q'
	.db #0xa2	; 162
	.db #0x00	; 0
	.db #0xf3	; 243
	.db #0xf3	; 243
	.db #0x00	; 0
	.db #0x00	; 0
	.db #0x51	; 81	'Q'
	.db #0xa2	; 162
	.db #0x00	; 0
	.area _INITIALIZER
	.area _CABS (ABS)

Dibujando sprites

Ya lo tenemos todo listo para pintar nuestro nuevo sprite. En el fichero hero.s tendremos que usar los datos del sprite, por lo que añadimos la etiqueta global _sprite_smily. Es un puntero a los datos del sprite

.area _DATA
.area _CODE
;;==============================================
;;==============================================
;; PRIVATE DATA
;;==============================================
;;==============================================

;;-- Data for drawing the sprite
.globl _sprite_smily

;;-- HERO DATA
hero_x:   .db #39  ;;-- x position (in bytes [0-79])
...

Para pintar el sprite utilizamos la función de cpctelera drawSprite

La nueva función de dibujado la metemos en hero_draw (pública):

;;======================
;; Draw the hero
;; DESTROYS: AF, BC, HL
;;=======================
hero_draw::
  ;;-- Convert the hero_x, hero_y variables into
  ;;-- the corresponding address in the Video memory
  ld   de, #0xC000  ;;-- Video initial address
  ld    a,(hero_x)
  ld    c,a         ;;-- Hero x position
  ld    a,(hero_y)
  ld    b,a         ;;-- Hero y position
  call cpct_getScreenPtr_asm

  ;; HL contains the video address
  ;; move it to the DE register
  ex de, hl

  ;; Draw our hero
  ld    hl, #_sprite_smily
  ld    bc, #0x0C04    ;; Height, Width: 8x12 pixels
  call  cpct_drawSprite_asm      
  ret

La función de borrado hero_erase también la modificamos. Y hacemos que el tamaño del sprite lo tome de las variables:

;;======================
;; Erase the hero
;; DESTROYS: AF, BC, HL
;;=======================
hero_erase::

  ;;-- Convert the hero_x, hero_y variables into
  ;;-- the corresponding address in the Video memory
  ld   de, #0xC000  ;;-- Video initial address
  ld    a,(hero_x)
  ld    c,a         ;;-- Hero x position
  ld    a,(hero_y)
  ld    b,a         ;;-- Hero y position
  call cpct_getScreenPtr_asm

  ;; HL contains the video address
  ;; move it to the DE register
  ex de, hl

  ;; Draw a Box (our hero!)
  ld     a, (hero_w)
  ld     c, a          ;; c = Hero width
  ld     a, (hero_h) 
  ld     b, a          ;; b = Hero height
  ld     a, #0x00      ;; Color pattern: 0 (Black!)
  call  cpct_drawSolidBox_asm
  ret

Las variables del tamaño del personaje las actualizamos (ahora son de 8x12). La altura es de 12 y la anchura de 4 (bytes, y hay 2 pixeles por byte)

;;-- HERO DATA
...
hero_w:   .db #4   ;;-- Width in bytes
hero_h:   .db #12   ;;-- Height in bytes
...

Modificamos la tabla de saltos también para que el personal salta más alto y dure un poco más:

;;-- Jump table
jumptable: 
  .db #-3, #-3, #-2, #-2, #-1, #-1
  .db #0,  #0, #0, #0
  .db #1, #1, #2,  #2, #3, #3
  .db #0x80

También tenemos que establecer la nueva paleta. Eso lo hacemos con la función cpct_setPalette-asm.html

Esto lo hacemos en el main.s, antes de entrar en el bucle principal

...
;;-- Change the color palette
  ld hl, #_sprite_palette
  ld de, #16
  call cpct_setPalette_asm
...

Por último, modificamos la rutina del personaje para que compruebe la colisión con la posición derecha, que ahora el tamaño es de 4 bytes. Sin embargo, en vez de cablearlo, vamos a hacer una rutina más genérica, que tenga en cuenta la variable hero_w

;;=============================================
;; moveHeroRight: Move the hero to the right
;;  (inside the line limits)
;;
;; DESTROYS:
;;=============================================
moveHeroRight:
  ;;- Check if the hero_x has reached its maximum value
  ;;-- We should check the possition 80 - hero.width
  ld a, (hero_w)
  ld b,a
  ld a, #80
  sub b          ;;-- A = 80 - hero_w
  ld b,a         ;;-- B = 80 - hero_w

  ld a, (hero_x) ;;-- A = hero_x
  cp b                 ;; hero_x == 80-hero_w?
  jr z,do_not_move_r      

    ;;- No max reached: increase the hero_x by 1
    inc a           ;;-- A = A + 1
    ld (hero_x),a   ;;-- hero_x = A

  do_not_move_r:
  ret

Al ejecutarlo vemos esto, ¡¡Se nos ha dibujado el personaje!!

  • Resultado: En esta animación vemos el juego tal cual está ahora:

Sesión: convertir y dibujar mapas de tiles en ensamblador con CPCtelera

Click to see the youtube video

La herramienta Tiled map editor

Tiled es una herramienta libre que nos permite crear mapas y escenarios para nuestros juegos. Se instala muy fácil en Linux. Sólo hay que bajarse el appimage desde el github: Tiled github. Yo tengo instalada la versión 1.7.2

El primer paso es aprender a manejarlo. Hay documentación aquí: Tiled: User manual

Los mapas se construyen a partir de un conjunto de sprites simples que se llaman tilesets (conjunto de tiles). Por ejemplo, para construir un laberinto necesitamos sprites para las paredes vertical, para las horizontales, para las esquinas, para el fondo, etc... Para practicar vamos a crear un tileset super simplificado, son sólo 4 tiles: pared vertical central, pared horizontal central, nudo y fondo

Estos 4 tiles los creamos con Gimp, y los metemos un único fichero donde están los 4 tiles agrupados, formando por ejemplo un array 2x2, pero los podríamos poner también en fila (un array de 1x4). Cada tile es de 4x4

Ahora arrancamos Tiled. Para crear un mapa nuevo le damos a File/New/New Map.... Ahora establecemos el tamaños de nuestras tiles (en nuestro caso son de 4x4) y el tamaño del mapa en tiles

Le damos a Save as y lo guardamos como level1.tmx. Se nos abre el editor de mapas:

Ahora creamos el Tileset. Pinchamos en File/New/New Tileset:

Le damos un nombre, por ejemplo tileset-1. Le indicamos el archivo donde está los tiles, que en nuestro caso era tiles8x8.png y el tamaño de los tiles que contiene: 4x4 en nuestro caso. Pinchamos en Save as y lo guardamos en el fichero tileset-1.tsx

En la parte de la derecha del editor de mapas veremos los 4 tiles de nuestro tileset (si se ven muy pequeños hay que hacer zoom)

Ahora ya podemos dibujar nuestro mapa. Este es el que he hecho de prueba:

Lo guardamos. Ya está todo listo para usarlo desde nuestro programa en ensamblador

Generando los datos del mapa

Ya tenemos nuestros dos ficheros: level1.tmx y tileset-1.tsx, con el mapa y los tiles respectivamente. Estos son ficheros en xml, por lo que podemos ver lo que tienen:

  • level1.txm:
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="40" height="32" tilewidth="4" tileheight="4" infinite="0" nextlayerid="2" nextobjectid="1">
 <tileset firstgid="1" source="tileset-1.tsx"/>
 <layer id="1" name="Tile Layer 1" width="40" height="32">
  <data encoding="csv">
2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,2,2,4,4,4,2,4,4,4,4,4,4,4,2,4,4,4,4,4,4,4,2,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
2,4,4,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,3,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,2,4,4,4,4,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,4,4,4,4,2,1,1,1,3,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,4,4,4,4,4,4,2,2,2,1,1,1,1,1,1,1,3,1,1,1,3,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,3,1,1,1,3,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,3,1,1,1,3,1,1,1,4,4,4,4,2,
3,1,4,4,4,4,4,4,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,3,1,1,1,3,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,4,4,4,4,1,1,1,3,
3,1,1,1,1,1,1,1,1,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1,1,1,3,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,4,4,4,4,2,
2,4,4,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
2,4,4,1,1,1,4,4,4,4,4,4,4,4,4,4,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,4,4,4,4,4,2,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,3,
3,1,4,4,4,4,4,4,1,1,1,1,4,4,4,4,4,1,1,1,4,4,4,4,4,4,4,4,4,4,4,4,4,2,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,
2,4,4,4,4,4,4,4,2,4,4,4,4,4,4,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2
</data>
 </layer>
</map>

Cada uno de los números 1-4 representa uno de los 4 tiles disponibles

  • tileset-1.tsx
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.5" tiledversion="1.7.2" name="tileset-1" tilewidth="4" tileheight="4" tilecount="4" columns="2">
 <image source="tiles8x8.png" width="8" height="8"/>
</tileset>

Este fichero de tileset no son más que metadatos donde se indica el nombre del fichero fuente que contiene los tiles (tiles8x8.png), las dimensiones en píxeles, y el tamaño de los tiles

Necesitamos convertir estos archivos en datos, para poderlos utilizar desde nuestros programas

A partir del tileset tenemos que generar los datos de los sprites de los 4 tiles. Esto lo hacemos en el archivo cfg/image_conversion.mk, a continuación de lo que habíamos hecho antes:

#-- Tiles generation
$(eval $(call IMG2SPRITES,assets/tiles8x8.png,0,g,4,4,$(PALETTE),tileset,src/sprites/,))

Con esto se generan los ficheros tiles8x8.c y tiles8x8.h con los datos de estos sprites. El símbolo global en c es g_tileset

#include "tiles8x8.h"
// Data created with Img2CPC - (c) Retroworks - 2007-2015
u8* const g_tileset[4] = { 
	g_tiles8x8_0, g_tiles8x8_1, g_tiles8x8_2, g_tiles8x8_3
};
// Tile g_tiles8x8_0: 4x4 pixels, 2x4 bytes.
const u8 g_tiles8x8_0[2 * 4] = {
	0x00, 0x00,
	0x00, 0x00,
	0x00, 0x00,
	0x00, 0x00
};

// Tile g_tiles8x8_1: 4x4 pixels, 2x4 bytes.
const u8 g_tiles8x8_1[2 * 4] = {
	0x04, 0x08,
	0x0c, 0x0c,
	0x0c, 0x0c,
	0x04, 0x08
};

// Tile g_tiles8x8_2: 4x4 pixels, 2x4 bytes.
const u8 g_tiles8x8_2[2 * 4] = {
	0x04, 0x08,
	0x04, 0x08,
	0x04, 0x08,
	0x04, 0x08
};

// Tile g_tiles8x8_3: 4x4 pixels, 2x4 bytes.
const u8 g_tiles8x8_3[2 * 4] = {
	0x00, 0x00,
	0x0c, 0x0c,
	0x0c, 0x0c,
	0x00, 0x00
};

El símbolo correspondiente en ensamblador es _g_tileset. Lo incluimos como símbolo global en nuestro main.s para usarlo. Para dejarlo configuado y listo para pintarse, usamos la función cpct_etm_setTileset2x4-s.html

 ...
 .globl _g_tileset
 ...
 __main::
 ...
 ;;-- Configure the tileset
  ld hl,#_g_tileset
  call cpct_etm_setTileset2x4_asm

Ahora hay que generar los datos del mapa. Esto lo hacemos desde el fichero tilemap_conversion.mk, con la siguiente línea:

$(eval $(call TMX2C,assets/level1.tmx,level0,src/niveles/,))

Creamos el directorio src/niveles y ejecutamos make. Se nos generan los ficheros level1.c y level1.h con el mapa en C:

//
// File assets/level1.tmx converted to csv using cpct_tmx2csv [20211016 16:24:41 CEST]
//   * Width:  40 columns (40 bytes, 8 bits per column)
//   * Height: 32 rows
//   * Bytes:  1280 bytes (40 x 32)
//
#include <types.h>

// Generated CSV tilemap from assets/level1.tmx
const u8 level0[40*32] = {
1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,1,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,1,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
1,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,1,3,3,3,3,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,3,3,3,3,1,0,0,0,2,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,1,1,1,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,3,3,3,3,1,
2,0,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,3,3,3,0,0,0,2,
2,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,2,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,3,3,3,3,1,
1,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
1,3,3,0,0,0,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,1,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,
2,0,3,3,3,3,3,3,0,0,0,0,3,3,3,3,3,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,
1,3,3,3,3,3,3,3,1,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,
};

El puntero al mapa lo tenemos en la etiqueta: _level0. Esta etiqueta la importamos en el main.s (como global). Usamos la función cpct_etm_drawTileBox2x4 para dibujar el mapa

.area _DATA
.area _CODE

.include "hero.h.s"
.include "obstacle.h.s"
.include "cpctelera.h.s"
.globl _sprite_palette
.globl _g_tileset
.globl _level0

;;===============================
;;  Main program entry
;;===============================
_main::

  ;;-- Disable Amstrad firmware. Needed for changing
  ;;-- the video mode
  call cpct_disableFirmware_asm

  ;;-- Change the video modeo to 0 (160x200 16 colors)
  ld c,#0
  call cpct_setVideoMode_asm

  ;;-- Change the color palette
  ld hl, #_sprite_palette
  ld de, #16
  call cpct_setPalette_asm

  ;;-- Configure the tileset
  ld hl,#_g_tileset
  call cpct_etm_setTileset2x4_asm

  ;;-- Draw the level0
  ld hl, #_level0
  push hl
  ld hl,#0xC000
  push hl
  ld bc,#0x0000   ;;-- Tile 0,0
  ld de,#0x2028   ;;-- Height/Width in tiles (of the map)
  ld a,#0x28      ;;-- Number of tiles in the row
  call cpct_etm_drawTileBox2x4_asm  ;; Draw the map!!

  main_loop:

    call hero_erase     ;; Erase the hero
    call obstacle_erase ;; Erase the bullet

    call hero_update     ;; Update the Hero
    call obstacle_update ;; Update the bullet

    ;;-- Check colision
    call hero_getPtrHL
    call obstacle_checkCollision
    ld (0xC000),a        ;;-- Draw collision
    ld (0xC001),a 
    ld (0xC002),a
    ld (0xC003),a

    call hero_draw      ;;-- Draw the hero
    call obstacle_draw  ;;-- Draw the bullet
  
    ;;-- Wait for the raster to finish
    call cpct_waitVSYNC_asm
    
    jr main_loop

Esto es lo que se ve ahora:

  • Resultado:

Clone this wiki locally