cpcrslib v.2       English

Texto OBSOLETO, ver versión en inglés

Librería de funciones para Amstrad CPC para el compilador z88dk.

 

Download last version (16/02/2009): cpcrslib

 

 

Introducción.

 

La librería cpcrslib contiene rutinas y funciones que permiten el manejo de sprites y mapeado de tiles en el Amstrad CPC, programando en C y usando el compilador z88dk. A parte de estas funciones, incorpora rutinas de teclado para redefinir y detectar teclas, así como rutinas gráficas generales para cambiar el modo o los colores.

 

 

Novedades.

 

16/02/2009

cpc_PutTrSpriteTileMap2b: Rutina nueva similar a cpc_PutTrSpTileMap2b pero sin hacer el cálculo interno de la posición en el superbuffer. Por eso requiere utilizar cpc_SpUpdX y

cpc_SpUpdY para actualizar la posición del sprite. O hacerlo del modo habitual pero ejecutando luego cpc_SuperbufferAddress() después de actualizar la posición.

cpc_UpdateTileMap: Se ha actualizado para incluir las rutinas cpc_PutTrSpTileMap2 y cpc_PutTrSpriteTileMap2.

 

11/02/2009

cpc_ScrollLeft0, cpc_ScrollLeft, cpc_ScrollRight0, cpc_ScrollRight: Rutinas nuevas (beta) para hacer scroll horizontal por software en el mapa de tiles.

 

09/02/2009

cpc_PutTrSpTileMap2b: Dibuja un sprite en el mapa de tiles teniendo en cuenta que uno de los colores es transparente. El color transparente se define en tiempo de compilación como mascara1 y mascara2

 

16/01/2009

cpc_TestKey : Optimización de código, más pequeño y rápido.

cpc_RedefineKey: Optimización de código, más pequeño y rápido.

cpc_AnyKeyPressed: Reescrita de nuevo, más corta y más rápida…. Creo que la anterior no funcionaba bien.

cpc_SetBorder: Cambiada la forma de llamar a esta función, ahora más corta y rápida.

cpc_InitTileMap: Cambiada la forma de llamar a esta función, ahora más corta y rápida.

 

21/05/2008

Se incorpora una nueva rutina descompresora: Exomizer. El código Z80 es de Metalbrain, el algoritmo de Magnus Lind. Los ficheros comprimidos con exomizer son más pequeños que los comprimidos con pucruch.

 

12/03/2008

Modificaciones menores en rutinas de dibujado de sprites en mapa de tiles: Se actualiza la posición del superbuffer automáticamente.

 

28/02/2008

Añadida una función que realiza todas las fases del dibujado de los sprites en el mapa de tiles.: cpc_UpdateTileMap(ListaSprites) Se modifica el ejemplo Small Sprite demo con esta nueva función.

 

21/02/2008

Modificado el código de resetear los tiles tocados. Ahora basta con definir el tamaño de la tabla en el fichero TileMapConf.asm

 

16/02/2008

Nuevas funciones:

 

cpc_SetInkGphStr(char color, char valor)           Establece el color de las letras en modo 0, sustituye a cpc_SetColorGphStr.

cpc_SetInkGphStrM1(char color, char valor)      Establece el color de las letras en modo 1.

cpc_PutMaskSpriteTileMap2b(  sprite)              Antes era cpc_PutSpTileMap2b, cambio de nombre

cpc_PutSpTileMap2b(   sprite)                          Dibuja un sprite sin máscara en el mapa de tiles

 

13/02/2008

Nuevas funciones

cpc_PutTile4x16(int *tile, char *x, char *y)          Para dibujar tiles directamente en pantalla de dimesiones 4x16 bytes

cpc_AnyKeyPressed()                                      Devuelve 1 ó 0 según si se ha pulsado alguna tecla

cpc_SetColorGphStr(char color, char valor)       Establece el color de las letras en modo 0.

 

Y se corrigen las funciones de escritura en modo 0. Tenían un fallo que hacía que uno de los 4 pixels del ancho de cada letra no se escribiera.

 

 

Características.

 

 

Rutinas y funciones incorporadas

 

 Funciones para el dibujo de sprites.

 

En los ejemplos se usarán estos datos para definir los sprites:

 

extern char sprite[];

extern char sprite_sd[];

extern char sprite_mask0[];

extern char sprite_mask[];

#asm

._sprite

defb 2,2

._sprite_sd

defb $ff,$ff

defb $ff, $ff

._sprite_mask0

defb 2,2

._sprite_mask

defb &ff,0,&ff,0

defb &ff,0,&ff,0

#endasm

 

 

cpc_PutSp(int *sprite, char *alto, char *ancho, int *posicion);

Parámetros:

•datos del sprite

•alto del sprite

•ancho del sprite

•destino del sprite

Imprime el sprite en la posición especificada. Las dimensiones del sprite se indican en los parámetros, no en los datos del sprite.

Ejemplo:

cpc_PutSp(sprite_sd,2,2,0xc000);

 

cpc_PutSpXOR(int *sprite, char *alto, char *ancho, int *posicion);

Parámetros:

•datos del sprite

•alto del sprite

•ancho del sprite

•destino del sprite

Imprime el sprite en la posición especificada usando la función XOR con el byte de la pantalla.

Ejemplo:

cpc_PutSp(sprite_sd,2,2,0xc000);

 

cpc_PutMaskSp(int *sprite, char *alto, char *ancho, int *posicion);

Parámetros:

•datos del sprite

•alto del sprite

•ancho del sprite

•destino del sprite

Imprime un sprite con máscara. El primer byte es el de máscara, el segundo lleva los datos del sprite.

Ejemplo:

cpc_PutMaskSp (sprite_mask,2,2,0xc000);

 

cpc_PutSpTr(int *sprite, char *alto, char *ancho, int *posicion);

Parámetros:

•datos del sprite

•alto del sprite

•ancho del sprite

•destino del sprite

En modo 0, imprime el sprite teniendo en cuenta que el color 0 es transparente y por lo tanto se ve el fondo.

Ejemplo:

cpc_PutSpTr(sprite_mask,2,2,0xc000);

 

cpc_PutMaskSprite(int *sprite, int *posicion);

Parámetros:

•datos del sprite

•destino del sprite

Imprime un sprite con máscara. El primer byte es el de máscara, el segundo lleva los datos del sprite.

Ejemplo:

cpc_PutMaskSprite (sprite_mask0, 0xc000);

 

cpc_PutSprite(int *sprite, int *posicion);

Parámetros:

•datos del sprite

•destino del sprite

Imprime un sprite

Ejemplo:

cpc_PutSprite (sprite,0xc000);

 

cpc_PutSpriteXOR(int *sprite, int *posicion);

Parámetros:

•datos del sprite

•destino del sprite

 

Imprime el sprite en la posición especificada usando la función XOR con el byte de la pantalla.

La diferencia entre este último y el anterior es que el sprite tiene los dos primeros bytes indicando las dimensiones del sprite (ancho alto). No se requiere, por eso, pasar esos parámetros.

Ejemplo:

cpc_PutSp(sprite,0xc000);

 

 

Otras rutinas para sprites:

(Se pueden ver en ejemplo_rot_sprites_modo1.c)

 

cpc_SpRRM1(sprite);                 //rota a la derecha un sprite en modo 1

cpc_SpRLM1(sprite);              //rota a la derecha un sprite en modo 1

 

cpc_CollSp(struct sprite00, struct sprite01);    //mira si hay colisión entre los dos sprites. En caso de colisión devuelve 1.

 

cpc_PutMaskSp2x8(int *sprite2x8_sd, int *posicion);

cpc_PutMaskSp4x16(int *sprite4x16_sd, int *posicion);

Imprimen el sprite en la posición indicada. La posición es una dirección de memoria. Son rutinas para unas dimensiones específicas, que dibujan más rápido.

 

 

Funciones sobre tiles

 

Los tiles son elementos fijos en la pantalla, generalmente, para definir el mapeado. Las rutinas que se usan son específicas para unas determinadas dimensiones (no van incluidas en los datos del tile). En cualquier otro caso, se pueden usar las rutinas de los sprites para dibujar los tiles ya que, en realidad, se definen como sprites.

 

cpc_PutTile2x8(int *tile, char *x, char *y);

cpc_PutTile4x16(int *tile, char *x, char *y);

 

Imprimen el sprite de las dimensiones definidas en la posición indicada. La posición se indica como coordenadas.

 

Ejemplo general de sprites (ejemplo_sp_mask.c en el paquete de la librería)

 

#include "C:\z88dk\include\cpcrslib.h"

 

extern unsigned char sp_8x8[];

extern unsigned char sp_16x16[];

extern unsigned char tile_8x8[];

extern unsigned char buffer[];

 

#asm

._sp_8x8

defb $88,$70,$11,$E0         //MASCARA,SPRITE,MASCARA,SPRITE... La máscara se dibuja con tinta 3 en modo 1.

defb $11,$E0,$88,$70        

defb $00,$96,$00,$96

defb $00,$F0,$00,$F0

defb $00,$F7,$00,$FE

defb $00,$C7,$00,$3E

defb $00,$F3,$00,$FC

defb $88,$70,$11,$E0

 

._sp_16x16

defb $88,$70,$11,$E0,$88,$70,$11,$E0     //MASCARA,SPRITE,MASCARA,SPRITE...

defb $11,$E0,$88,$70,$11,$E0,$88,$70    

defb $00,$96,$00,$96,$00,$96,$00,$96

defb $00,$F0,$00,$F0,$00,$F0,$00,$F0

defb $00,$F7,$00,$FE,$00,$F7,$00,$FE

defb $00,$C7,$00,$3E,$00,$C7,$00,$3E

defb $00,$F3,$00,$FC,$00,$F3,$00,$FC

defb $88,$70,$11,$E0,$88,$70,$11,$E0

defb $88,$70,$11,$E0,$88,$70,$11,$E0

defb $11,$E0,$88,$70,$11,$E0,$88,$70

defb $00,$96,$00,$96,$00,$96,$00,$96

defb $00,$F0,$00,$F0,$00,$F0,$00,$F0

defb $00,$F7,$00,$FE,$00,$F7,$00,$FE

defb $00,$C7,$00,$3E,$00,$C7,$00,$3E

defb $00,$F3,$00,$FC,$00,$F3,$00,$FC

defb $88,$70,$11,$E0,$88,$70,$11,$E0

._tile_8x8

defb $07,$0E            //Sin máscara

defb $2D,$C3           

defb $0F,$2D

defb $0F,$2D

defb $0F,$0F

defb $0F,$2D

defb $0F,$0F

defb $07,$0E

._buffer defs 64

#endasm

 

main(){

     

      cpc_SetMode(1);     //rutina hardware. Requiere cambiar el salto de las interrupciones

      cpc_SetModo(1);     //rutina firmware para cambiar el modo.

      cpc_SetColour(17,11);   //Ídem de lo mismo. Requiere cambiar el salto de las interrupciones

      cpc_SetInk(17,11); //rutina firmware para cambiar los colores.

 

     

      // Dibujar un sprite de 2x8 bytes en las coordenadas 10,90 de la pantalla

      cpc_PutTile2x8(tile_8x8,10,90);

     

      // Dibujar un sprite con máscara de dimensiones 2x8 bytes en la posición de pantalla indicada (&C00B)

      cpc_PutMaskSp2x8(sp_8x8,0xc00b);

     

      // Lo mismo pero con un sprite de 4x16 bytes

      // cpc_PutMaskSp4x16(sprite data,screen adress);

      cpc_PutMaskSp4x16(sp_16x16,0xc190);

     

      // Dibuja un sprite en modo 0 teniendo en cuenta que el color 0 es transparente. Se especifican las

      // dimensiones altoxancho.

      //cpc_PutSpTr(sprite data,height,widh,screen adress);

      cpc_PutSpTr(tile_8x8,8,2,0xc19b);

      // imprime un sprite de las dimensiones indicadas en la pantalla

      cpc_PutSp(tile_8x8,8,2,0xc19b);

     

      // Captura de la pantalla el area indicada y la guarda en memoria.

      cpc_GetSp(buffer,8,8,0xc054);

      // En este ejemplo, imprime en &C190 el area capturada .

      cpc_PutSp(buffer,8,8,0xc190);

      while (1){} //Repeat until the end of the world

     

     

}

 

Arriba

 

Teclado.

 

Hay dos rutinas, una para detectar la pulsación de una tecla y otra para redefinir una tecla. Se pueden tener un total de 12 teclas en uso.

There are two routines about keyboard. There can be 12 different keys in use.

 

cpc_RedefineKey(key number);                       // Espera la pulsación de una tecla y la asigna a la tecla indicada por key number.

 

cpc_TestKey(Key number);                  // Comprueba si la tecla indicada en key number se ha pulsado (devuelve 1 si se detecta)

 

cpc_AnyKeyPressed();             //Devuelve 1 si se ha pulsado alguna tecla y 0 si no se ha pulsado ninguna.

 

cpc_AssignKey(Key number, value)    //asigna una tecla al número de tecla indicado.

Ejemplo. cpc_AssignKey(0,0x4002) asigna a la tecla 0 el cursor derecho. El valor se deduce de la tabla siguiente:

 

Tabla de teclas (fuente: cpcwiki)

 

Byte:
Line

&80

&40

&20

&10

&08

&04

&02

&01

&40

F Dot

ENTER

F3

F6

F9

CURDOWN

CURRIGHT

CURUP

&41

F0

F2

F1

F5

F8

F7

COPY

CURLEFT

&42

CONTROL

\

SHIFT

F4

]

RETURN

[

CLR

&43

.

/

 :

 ;

P

@

-

^

&44

,

M

K

L

I

O

9

0

&45

SPACE

N

J

H

Y

U

7

8

&46

V

B

F

G

T

R

5

6

&47

X

C

D

S

W

E

3

4

&48

Z

CAPSLOCK

A

TAB

Q

ESC

2

1

&49

DEL

-

-

-

-

-

-

-

 

 

 

 

Ejemplo general de uso del teclado (prueba_teclado.c en el paquete de la librería)

 

#include <stdio.h>

#include "cpcrslib.h"

 

extern unsigned char text[]

extern unsigned char text2[]

extern unsigned char ok[]

extern unsigned char no[]

#asm

._text

DEFM "Pulsa la tecla a redefinir."

defb 0      //fin de la cadena

._text2

DEFM "Pulsa la tecla para comprobar que fun-  ciona."

defb 0      //fin de la cadena

._ok

DEFM "OK"

defb 0

._no

DEFM "no"

defb 0

#endasm

 

 

main(){

      cpc_SetModo(1);              //Set mode using firmware

      cpc_PrintStr(text);                //Show text using firmware

      cpc_Redefine_Key(0);         //redefine key. There are 12 available keys (0..1)

      cpc_PrintStr(text2);

      while (1) {

            if (cpc_TestKey(0)==1) {     //test if the key has been pressed.

                  cpc_PrintStr(ok);

            }

      }

}

 

Arriba

 

 

Descompresión.

 

cpc_Uncrunch(origen_datos,destino_datos); 

Se utiliza el pucrunch para descomprimir un archivo comprimido:

 

cpc_UnExo(origen_datos,destino_datos);

Se utiliza el UnExo para descomprimir un archivo comprimido:

 

Nota. En el fichero se incluyen los ejecutables para comprimir desde una ventada DOS de Windows. La sintaxis habitual es:

 

pucruch -d -c0 filein fileout

 

exo filein fileout

 

El fichero generado (fileout) es el que se debe incorporar en el programa para que la librería lo descomprima.

 

Ejemplo:

#include "cpcrslib.h"

extern unsigned char binary_data[];

#asm

._binary_data

   BINARY "sample.exp"

#endasm

 

main(){

            cpc_SetModo(1);

            // UnExo disables interrupts while processing file.

            cpc_UnExo(binary_data,0xc000);

            while (1) {}

}

 

Arriba

 

Texto gráfico.

 

Permiten escribir en modo 0 o modo 1 un texto en mayúsculas en formato gráfico:

 

En modo 0:

cpc_PrintGphStr("HOLA;CARACOLA<",0xc190);                     //indicando directamente la posición gráfica donde escribir

cpc_PrintGphStrXY("ADIOS;CARACOLA<",20,100);    //indicando la posición

                                                                                  //gráfica donde escribir mediante coordenadas gráficas

cpc_SetInkGphStr(char color, char valor);                  // Establece el color de las letras escritas en modo 0. Cada letra está definida por 4 colores (0..3) y los valores que

puede tomar para un resultado agradable son:

0

2

8

10

32

34

40

42

128

130

136

138

160

162

168

170

 

 

En modo 1:

cpc_PrintGphStrM1("HOLA;CARACOLA<",0xc190);    

cpc_PrintGphStrXYM1("ADIOS;CARACOLA<",20,100);          

cpc_SetInkGphStrM1(char color, char valor);              // Establece el color de las letras escritas en modo 0. Cada letra está definida por 4 colores (0..3). Los valores válidos para resultados agradables son: 0, 8, 128, 136

 

Los caracteres son de 4x8 pixeles. Se pueden cambiar en el archivo cpc_Chars.asm de la librería.  Cada byte define una línea, dentro de cada byte, cada grupo de 2 bits define un píxel de un color (hay 4 colores como máximo en una letra).

 

 

 

Arriba

 

Pantalla

 

Cambio de modo:

cpc_SetMode(modo)               //Accediendo directamente al hardware. Requiere haber quitado el salto           

                                               //de las interrupciones que trae el CPC por defecto.

cpc_SetModo(modo)               //Usando el firmware.

 

Cambio de colores:

cpc_SetColour(numero tinta, color)    //Accediendo directamente al hardware. Requiere haber quitado el salto           

                                                           //de las interrupciones que trae el CPC por defecto.

 

cpc_SetBorder(color)                          //Usando el firmware:

cpc_SetInk(numero_tinta, color)        

 

 

cpc_GetScrAddress(x,y)          //devuelve la posición de memoria correspondiente a las coordenadas x,y introducidas. Por ejemplo, para (x,y)=(0,0) devuelve &C000

 

En cualquier caso, todas las rutinas de la librería están utilizadas en los ejemplos adjuntos y es el mejor método para entenderlas y aprender a usarlas.

 

Arriba

 

Música y sonidos

 

Estas rutinas se encuentran el la librería cpcwyzlib. Aún no existe un programa compositor de música ni de efectos para el placer pero  sí que hay un ejemplo de música y efectos de sonido en el paquete cpcrslib. No olvidar compilar con –lcpcwyzlib.

 

Establecer los datos que se utilizarán:

cpc_WyzInitPlayer(TABLA_SONIDOS,TABLA_PAUTAS,TABLA_EFECTOS, TABLA_SONG); 

cpc_WyzLoadSong(0);             //selecciona la canción

cpc_WyzSetPlayerOff();                       //para la música y el sonido

cpc_WyzSetPlayerOn();                       //comienza la música y los efectos

cpc_WyzStartEffect(0);             //reproduce un efecto

 

Arriba

 

Mapa de tiles

 

Resumen de rutinas y funciones:

 

cpc_UpdScr()

cpc_UpdScrAddresses()

cpc_ShowTileMap(z)

cpc_SetTile(x,y,tile)

cpc_SetTouchTile(x,y,tile)

cpc_ReadTile(x,y)

cpc_TouchTileXY(x,y)

cpc_ShowTouchedTiles()

cpc_PutSpTileMap(sprite)

cpc_PutTrSpTileMap2b(sprite)

cpc_PutTrSpriteTileMap2b(sprite)

cpc_PutMaskSpTileMap2b(sprite)

cpc_PutMaskSpriteTileMap2b(sprite)

cpc_PutORSpTileMap2b(sprite)

cpc_SuperbufferAddress(x,y)

cpc_ResetTouchedTiles()

 

cpc_ScrollRight0();

cpc_ScrollLeft0();

cpc_ScrollRight();

cpc_ScrollLeft();

 

 

 

Uso de las rutinas de mapeado de tiles.

 

Un poco de teoría para intentar aclarar conceptos.

 

Estas rutinas permiten dibujar y move sprites sobre la pantalla manteniendo el fondo y sin parpadeos.  Los sprites pueden ser del tamaño que se quiera y el número de ellos que se desee, pero hay que tener en cuenta que las capacidades del CPC son limitadas y contra más sprites, más tiempo llevará al procesador dibujarlos y más lento se moveá.

 

Los tiles son de 2x8 bytes (ancho x alto). Se puede definir un área máxima de 40x20 tiles, dependiendo del modo serán de 320x160 pixels en modo 1 y 160x160 pixels en modo 0.

Se crea una copia del área de tiles que llamaremos superbuffer. El superbuffer está tileado. A la pantalla visible se traspasan los tiles del superbuffer.

El superbuffer, en memoria utilizada sería 40x2x160 bytes=12800 bytes (&3200) como máximo. Por defecto, el inicio del superbuffer se sitúa en &100 y llegaría como máximo hasta &3300 (&3200+&100). Es importante tener esto en cuenta para poner el inicio del código del programa por encima del superbuffer, si no, al usarlo, se machacará dando resultados inesperados en la ejecución.

 

Pasos para dibujar el mapa en pantalla:

  1. Se establecen los tiles que forman el mapa. Véase el mapa como una matriz (suponiendo que es de 10x5 tiles)

{  1, 1, 1, 1, 1, 1, 1, 1, 1, 1

   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, 2, 2, 2, 2, 2, 2, 2, 2 }

 

  1. Se envía el superbuffer completo a la pantalla.

 

Para representar un sprite se realizan los siguientes pasos:

  1. Se miran los tiles que toca el sprite, tanto en su posición actual como en su posición anterior (fase 1). Estos tiles se denominan tiles tocados.
  2. Se restauran los tiles en el superbuffer. Consiste en borrar todo rastro del sprite en el superbuffer para dejarlo limpio.
  3. Se dibuja el sprite en el buffer (fase 2).
  4. Se envían los tiles tocados a la pantalla, con lo que se ve el sprite en su nueva posición, con el fondo correspondiente.

 

Vamos a utilizar dos tipos de coordenadas, las gráficas y las del mapa de tiles. Las coordenadas gráficas indican incrementos de byte en byte y son las que se utilizan para dibujar los sprites y serán las que se denominen x,y. Las coordenadas del mapa de tiles son referidas a tiles y se denominarán tx, ty. En principio, todas las coordenadas serán tx, ty excepto las que van dentro de los datos del sprite.

Por ejemplo, dentro del mapa definido antes, la coordenada x=10, y =10 correspondería a un punto dentro del tile marcado en rojo y la coordenada tx=2, ty=3 sería el tile marcado en azul.

 

Un poco de práctica para afianzar los conceptos no aclarados en la teoría:

 

El funcionamiento, para definir la pantalla con tiles es:

1º Se define la pantalla: se indican que tiles la componen usando

cpc_SetTile(tx,ty,tile);

 

El mapa del ejemplo se podría rellenar de la siguiente manera:

 

void draw_tilemap(void) {

      unsigned char x,y;

      y=0;

      for(x=0; x<10;x++) {

            cpc_SetTile(x,y,1);

      }

      for(y=1;y<4;y++) {

            for (x=0; x<10;x++) {

            cpc_SetTile(x,y,0);

            }

      }

      y=4;

      for (x=0; x<10;x++) {

            cpc_SetTile(x,y,2);

      }

}

 

2º. Se muestra la pantalla:

cpc_ShowTileMap(0);

El parámetro indica los bytes de ancho que se quieren traspasar. Poniendo 0 se hace el traspaso del ancho completo de la pantalla de tiles.

 

Con la pantalla definida lo que hemos conseguido es tener un buffer con toda la información que es donde se dibujan los sprites antes de pasarlos a la pantalla. Los sprites tienen que usar la estructura:

 

struct sprites{  

      int sp0;          //2 bytes   Sprite actual (con dimensiones)

      int sp1;          //2 bytes   Sprite anterior (con dimensiones)

      int coord0;       //2 bytes   posición en superbuffer

      int coord1;       //2 bytes   posición anterior en superbuffer

      unsigned char cx, cy; //2 bytes   coordenadas nuevas  x,y

      unsigned char ox, oy;   //2 bytes   coordenadas actuales x,y

      unsigned char move;   // si NO es 0, el sprite se mueve.   Todavía no implementado.

}

 

Si se quieren añadir campos, se añadirían al final.

 

Para iniciar un sprite hay que indicar, inicialmente los campos

           sp0 (que es el sprite a dibujar)

           sp1 (que es el sprite anterior, pero se inicia con el anterior la primera vez)

           ox (coordenada anterior x)

           oy (coordenada anterior y)

           cx (coordenada x)

           cy (coordenada y)

 

Con estos datos en los sprites, ya se pueden dibujar y move por el fondo sin que se estropee el mismo.

 

En un ciclo de movimiento, lo primero que hay que hacer es resetear la tabla de tiles tocados (los últimos que se han trasladado a la pantalla visible):

cpc_ResetTouchedTiles();

 

Poner y dibujar sprites consta de 4 pasos:

 

1. Meter todos los sprites en el buffer (fase 1):

cpc_PutSpTileMap(sprite00);

cpc_PutSpTileMap(sprite01);

...

Esto hace que se lean los tiles de la posición anterior del sprite y los actuales y los meta en la tabla de tiles tocados.

 

Si en algún momento, nos interesa cambiar algún tile del fondo (por ejemplo, para modificar una puerta abierta por una cerrada), se tiene que actualizar el buffer en el buffer y pasarlo a la pantalla:

cpc_SetTile(tx,ty,tile);

cpc_TouchTileXY(tx,ty);   //mete el tile en la tabla de tiles tocados para restaurarlos

 

Para los casos en los que se tengan que hacer estas dos funciones seguidas existe la función

cpc_SetTouchTileXY(tx,ty,tile) que las realiza.

 

2. Se restaura el superbuffer (limpia los sprites movidos para dibujar las nuevas posiciones)

cpc_UpdScr();

 

3. Se dibujan los sprites en el buffer en las coordenadas correspondientes (fase 2)

cpc_PutMaskSpTileMap2b(sprite00);

cpc_PutORSpTileMap2b(sprite01);

...

           

4. Ahora, después de este paso, el buffer tiene los sprites limpios, sólo resta enviar a la pantalla los tiles pertinentes que limpien la posición anterior y dibujen los sprites en su sitio:

cpc_ShowTouchedTiles();

 

 

Y esto es  casi todo, hay algunas opciones distintas para dibujar un sprite en el buffer (fase2):

cpc_PutMaskSpTileMap2b(sprite00): Mete un sprite con máscara

cpc_PutORSpTileMap2b(sprite00): Mete un sprite sin máscara pero haciendo la operación OR.

cpc_PutSpTileMap2b(sprite00): Mete un sprite sin máscara

cpc_PutTrSpTileMap2b(): dibuja un sprite en el buffer teniendo en cuenta uno de los colores como transparente. El color transparente se define en tiempo de compilación através de los mascara1 y mascara2. Ver TileMapConf.asm

 

cpc_ReadTile(tx,ty) devuelve el número de tile correspondiente a las coordenadas x,y del mapa de tiles.

 

cpc_SuperbufferAddress(x,y) Establece el valor sprite.coord0  correspondiente a la posición dentro del superbuffer determinada por las coordenadas del sprite sprite.cx, sprite.cy

 

Hay otra posibilidad a la hora de hacer la fase 2 con los sprites :

cpc_SpUpdX(struct sprite, value)        // mueve el sprite a la izquierda (<0) o a la derecha (>0). El salto es el indicado en value.

cpc_SpUpdY(struct sprite, value)        // mueve el sprite arriba (<0) o abajo (>0). El salto es el indicado en value.

cpc_PutMaskSpriteTileMap2b(struct sprite)    // Mete el sprite en el mapa de tiles (Superbuffer), es más rápida que la rutina cpc_PutMaskSpTileMap2b pero requiere mover el sprite con las funciones cpc_SpUpdX or cpc_SpUpdX. Hay un ejemplo en el archivo small_sprite_demo.c.

cpc_PutTrSpriteTileMap2b(struct sprite)         // Mete el sprite en el mapa de tiles (Superbuffer), es más rápida que la rutina cpc_PutTrSpTileMap2b pero requiere mover el sprite con las funciones cpc_SpUpdX or cpc_SpUpdX.

 

 

 

cpc_UpdateTileMap(listaSprites)         // engloba todas las funciones para dibujar los sprites en la pantalla en una sola función. Serían los pasos 1,2,3 y 4 antes descritos, sin incluir las funciones cpc_SetTile(tx,ty,tile), cpc_TouchTileXY(tx,ty) y cpc_SetTouchTileXY(tx,ty,tile) que se realizarían justo antes de cpc_UpdateTileMap() y después de cpc_ResetTouchedTiles()

 

La entrada tiene que ser una lista de los sprites que se van a representar. El último elemento de la lista será el valor 0xffff para marcar el final.

int spriteList[10];
spriteList[0]=sprite00;
...
sprite[n]=0xffff; //siempre cierro la lista con 0xffff para poder detectar que no hay más valores dentro.

Por otra parte, el control de si un sprite se dibuja o restaura su fondo se hace con el valor move de la estructura de sprites.
Para que se realice la primera fase el programa se fija en el bit 0 de move. Si es 0 no se realiza, si es 1, se realiza.
Para ver si el sprite se dibuja en el mapa de tiles, se fija en los bits 1,2 y 3 de move. Si son 000 no se dibuja el sprite. Los restantes valores hasta ahora son:
001 -> cpc_PutMaskSpriteTileMap2b
010 -> cpc_PutMaskSpTileMap2b
011 -> cpc_PutORSpTileMap2b
100 -> cpc_PutSpTileMap2b

101 -> cpc_PutTrSpTileMap2

110 -> cpc_PutTrSpriteTileMap2

Por ejemplo, quiero dibujar el sprite00 con la última función todo el rato, y que siempre se restaure su fondo:
el valor move sería 00001001 en binario.... como no se cómo se pasa un número binario en z88dk, lo pongo en decimal:
sprite00.move=9;
Si resulta que el sprite no se mueve de su sitio, me basta con que se dibuje sin restaurar el fondo:
sprite00.move=8; //00001000
Si quiero restaurar el fondo pero que el sprite no se dibuje (por ejemplo, para hacer desaparecer un sprite que antes se dibujaba):
sprite00.move=1; //00000001
Y así sucesivamente.

 

Nota: El ejemplo small sprite demo se ha modificado para utilizar esta nueva función.

 

 

Rutinas de  scroll

 

Se han incluído cuatro funciones nuevas para realizar scroll horizontal por software. No se consigue un scroll muy bueno pero algún uso se le podrá dar. Cada paso de scroll corresponde a un tile (2bytes) y se realiza en dos pasos:

1.     Se mueve el mapa de tiles con cpc_ScrollLeft0() or cpcScrollRight0(). Después de este paso hay que actualizar la columna derecha o izquierda del mapa de tiles para que refleje la nueva situación tras el scroll.

2.     Se hace el scroll del area visible con cpc_ScrollLeft() or cpcScrollRight(). Este paso mueve el area visible hacia la derecha o izquierda y añada la nueva columna de tiles en su lugar correspondiente.

Para aclararlo se ha incluido un ejemplo en la scroll_transparent.

Para hacer el scroll hay que definir la columna izquierda del área visible en el archivo TileMapConf.asm

 

 

TileMapConf.asm

 

Este fichero es básico para utilizar el mapeado de tiles ya que tiene los parámetros del mapa y la definición del buffer y de las posiciones de memoria gráfica que se utilizarán. A continuación se presenta la estructura básica del fichero, que tiene que ser indicado en la compilación.

 

 

 

XLIB TileMapConf.asm

 

XDEF tiles

XDEF pantalla_juego

XDEF tiles_tocados

XDEF posiciones_pantalla

XDEF posiciones_super_buffer

 

XDEF posicion_inicial_area_visible

XDEF posicion_inicial_superbuffer

XDEF ancho_pantalla_bytes

XDEF alto_pantalla_bytes

XDEF ancho_pantalla_bytes_visible

 

; ***************************************************

; Transparent colour for cpc_PutTrSpTileMap2b/ cpc_PutTrSpriteTileMap2b routine

XDEF mascara1

XDEF mascara2

; ***************************************************

 

 

;XDEF tile

; ***************************************************

; Scroll Left Addresses column

; not requiered if scroll not used

XDEF ColumnScr

; ***************************************************

 

 

; ***************************************************

; Transparent colour for cpc_PutTrSpTileMap2b routine

; For printing sprites using transparent color (mode 0) transparent color selection is requiered.

; Selección color transparente. Escribir las 2 máscaras que correspondan al color elegido.

;Example colour number 7:

defc mascara1 = $54    

defc mascara2 = $a8

;0: $00, $00

;1: $80, $40

;2: $04, $08

;3: $44, $88

;4: $10, $20

;5: $50, $A0

;6: $14, $28

;7: $54, $A8

;8: $01, $02

;9: $41, $82

;10: $05, $0A

;11: $45, $8A

;12: $11, $22

;13: $51, $A2

;14: $15, $2A

;15: $55, $AA

; ***************************************************

 

 

;------------------------------------------------------------------------------------

; VALORES QUE DEFINEN EL BUFFER Y LA PANTALLA

;------------------------------------------------------------------------------------

defc posicion_inicial_area_visible = $c050     ;Indica la posición en pantalla del tile superior izquierdo.

defc posicion_inicial_superbuffer = $100       ;Posición de inicio donde se guardan los datos del buffer. El tamaño del

                                   ;buffer es 2x8xT_WIDTHxT_HEIGHT

                                   ;(El tamaño del buffer es ancho_pantalla_bytes*alto_pantalla_bytes)

;------------------------------------------------------------------------------------

 

;------------------------------------------------------------------------------------

;DIMENSIONES DEL MAPA DE TILES

;------------------------------------------------------------------------------------

defc T_WIDTH = 32       ;max=40 tiles          

defc T_HEIGHT = 16           ;max=20 tiles

;------------------------------------------------------------------------------------

 

 

 

;------------------------------------------------------------------------------------

;Parámetros que normalmente no se tocan

;------------------------------------------------------------------------------------

;------------------------------------------------------------------------------------

; El ancho de pantalla influye determinantemente en numerosas rutinas que hay que actualizar si se cambia.

defc ancho_pantalla_bytes = 2*T_WIDTH    ;Cada tile es de 2 bytes de ancho.

defc alto_pantalla_bytes = 8*T_HEIGHT          ;Cada tile es de 8 bytes de alto.

defc ancho_pantalla_bytes_visible = 2*T_WIDTH  ;dentro del area definida, cuánto se debe mostrar.

 

.datos_mapeador

;------------------------------------------------------------------------------------

;Con la definición del mapeado hay que tener en cuenta que las coordenadas son:

;ANCHO=64 bytes (128 pixels en modo 0)

;ALTO=128 pixels

.posiciones_pantalla                     ;Posiciones en las que se dibujan los tiles

defw posicion_inicial_area_visible+$50*0

defw posicion_inicial_area_visible+$50*1 

defw posicion_inicial_area_visible+$50*2

defw posicion_inicial_area_visible+$50*3

defw posicion_inicial_area_visible+$50*4

defw posicion_inicial_area_visible+$50*5

defw posicion_inicial_area_visible+$50*6

defw posicion_inicial_area_visible+$50*7

defw posicion_inicial_area_visible+$50*8

defw posicion_inicial_area_visible+$50*9

defw posicion_inicial_area_visible+$50*10

defw posicion_inicial_area_visible+$50*11

defw posicion_inicial_area_visible+$50*12

defw posicion_inicial_area_visible+$50*13

defw posicion_inicial_area_visible+$50*14

defw posicion_inicial_area_visible+$50*15

defw posicion_inicial_area_visible+$50*16

defw posicion_inicial_area_visible+$50*17

defw posicion_inicial_area_visible+$50*18

defw posicion_inicial_area_visible+$50*19

 

.posiciones_super_buffer                       ;muestra el inicio de cada línea

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*0

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*1

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*2

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*3

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*4

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*5

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*6

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*7

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*8

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*9

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*10

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*11

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*12

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*13

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*14

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*15

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*16

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*17

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*18

defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*19

 

.pantalla_actual defw 0     

 

.pantalla_juego  defs T_WIDTH*T_HEIGHT   ;En tiles, es el mapa donde cada byte dice el tile que tiene.

defb $FF                                 ;Este byte es importante, marca el fin de la pantalla.

 

.tiles_tocados defs 150 ;cuando un tile es tocado, se marca en esta tabla para luego restaurarlo.

                  ;Es una tabla sin duplicados. Cada tile tocado se representa por 2 bytes. Se pueden

                  ;tocar hasta 75 tiles.

;------------------------------------------------------------------------------------

 

 

; ***************************************************

; Scroll Left Addresses column

; not requiered if scroll not used comment it ;)

; one word for each scrollable line

.ColumnScr

defw $C0AA

defw $C8AA

defw $D0AA

defw $D8AA

defw $E0AA

defw $E8AA

defw $F0AA

defw $F8AA

; ***************************************************

     

 

;------------------------------------------------------------------------------------

;DEFINICIÓN DE LOS TILES. Se guardan a partir de .tiles

;------------------------------------------------------------------------------------

.tiles                  ;Son de 2x8 bytes.  Cada bloque de 16 bytes es un tile y en las rutinas se hace la

                  ;llamada al mismo mediante su posición, desde 0 hasta el último.

 

;defb 2,8

;defb $70,$c0

;defb $f0,$68

;defb $f0,$84

;defb $f0,$e0

;defb $f0,$a4

;defb $e0,$c0

;defb $50,$60

;defb $00,$00

 

Arriba

 

 

 

 

 

(c) Raúl Simarro 2007-08 Contacto, dudas, sugerencias, ...