Sprites II: Animación de sprites (C y ASM con SDCC) En este tutorial vamos a comprobar lo sencillo que es simular el movimiento de un personaje mediante sprites. Vamos a continuar usando el personaje Nick de Snow Bros. Vamos a hacer que el personaje camine de derecha a izquierda por la pantalla, para ello necesitamos conseguir los gráficos/sprites de todos los pasos de la animación. Para hacerlo sencillo he capturado de la recreativa original únicamente 3 sprites para caminar a la izquierda y los mismos 3 sprites invertidos horizontalmente para caminar a la derecha. (Si fuera necesario por problemas de espacio o memoria se podría hacer una rutina que dibujase los sprites invertidos horizontalmente, para únicamente necesitar 3 para izquierda y derecha, pero por ahora no nos vamos a complicar). Los graficos son los siguientes:
He decidido hacerlo todo junto en un único grafico en vez de en 6 graficos individuales, también puede verse que hay un pixel en blanco a cada lado, para evitar dejar estela o tener que borrar al mover el sprite. Vamos a convertirlo a Modo 0, paleta de 16 colores para poder usarlo en el cpc. Para ello volvemos a usar ConvImgCPC como ya vimos en el tutorial Convirtiendo y mostrando una imagen en pantalla, yo lo he configurado de la siguiente manera: Como se puede ver he utilizado las opciones "Keep original size", "Overscan" poniendo 168 (28 * 6) de alto y 12 de ancho (12 bytes en modo 0 = 24 pixels). Vemos que Nick ha engordado un poco debido al aspect ratio del modo 0, pero bueno eso no nos preocupa ahora mismo. Para exportarlo seleccionamos las opciones "asm mode" y "Linear" y pulsamos "Save Picture". Guardamos el fichero en asm y lo convertimos a C fácilmente como ya vimos en el tutorial Convirtiendo y mostrando una imagen en pantalla, finalmente nos queda un fichero Nick.h como este: /* ;Généré par ConvImgCpc Version 0.16 ; Mode 0 ; 12x168 ; Linear */ #define NICK_WIDTH 12 #define NICK_HEIGHT 28 #define NUM_COLORS 16 const unsigned char NickPalette[NUM_COLORS] = {26, 0, 13, 2, 1, 10, 11, 20, 15, 3, 14, 0, 0, 0, 0, 0}; const char NickSprite[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x84 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x48, 0xE8, 0x08, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x04, 0xC0, 0xC0, 0xD4, 0xFC , 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xC0 , 0x08, 0x0C, 0x5C, 0xF8, 0xE0, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x48, 0x08, 0x00, 0x00, 0x48, 0xF0 , 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00 , 0x00, 0x00, 0x04, 0xD0, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x04, 0x48 , 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x48, 0x80 , 0x00, 0x00, 0x00, 0x0C, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x0C , 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x80 , 0x41, 0x02, 0x04, 0x0C, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x40, 0x08, 0x41, 0x83, 0x00, 0x0C, 0x48 , 0x08, 0x00, 0x00, 0x00, 0x00, 0x04, 0xC1, 0x83 , 0x02, 0x0C, 0xCC, 0x98, 0x84, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x81, 0x02, 0x00, 0xC4, 0x3C, 0x00 , 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 , 0x48, 0x8D, 0x28, 0x00, 0x00, 0x84, 0x00, 0x00 , 0x00, 0x00, 0x84, 0x0C, 0x84, 0x1C, 0x2C, 0x00 , 0x00, 0x48, 0x08, 0x00, 0x00, 0x00, 0x48, 0x0C , 0x08, 0x14, 0x6C, 0x08, 0x00, 0x04, 0x80, 0x00 , 0x00, 0x00, 0x04, 0xC0, 0x00, 0x14, 0x3C, 0x24 , 0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40 , 0x00, 0x1C, 0x1E, 0x98, 0x0C, 0x04, 0x80, 0x00 , 0x00, 0x00, 0x00, 0x48, 0x00, 0x9C, 0x1E, 0xCC , 0x24, 0x48, 0x08, 0x00, 0x00, 0x00, 0x00, 0x84 , 0x4C, 0x2D, 0x3C, 0xCC, 0x30, 0x84, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x80, 0xCC, 0x07, 0x6C, 0x98 , 0x60, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x84 , 0x49, 0x8D, 0x6C, 0x30, 0xC0, 0x30, 0x80, 0x00 , 0x00, 0x00, 0x00, 0x48, 0xC4, 0x3C, 0xCC, 0x60 , 0x90, 0x30, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 , 0xC4, 0x9C, 0x98, 0xC4, 0x98, 0x70, 0xE0, 0x00 , 0x00, 0x00, 0x00, 0x04, 0xC0, 0x98, 0x60, 0x48 , 0xC4, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x04, 0xC0 , 0xFC, 0xF8, 0xE0, 0xD0, 0xF0, 0xF0, 0x84, 0x00 , 0x00, 0x00, 0x40, 0xFC, 0xFC, 0xF0, 0xE0, 0xF0 , 0xF0, 0xE0, 0x08, 0x00, 0x00, 0x00, 0x04, 0xC0 , 0xC0, 0xC0, 0x84, 0xC0, 0xC0, 0x84, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xE8 , 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 , 0xC0, 0xC0, 0xD4, 0xFC, 0x84, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x04, 0xC0, 0x08, 0x0C, 0x5C, 0xF8 , 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x08 , 0x00, 0x00, 0x48, 0xF0, 0x84, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0xD0 , 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x00 , 0x00, 0x00, 0x04, 0x48, 0x08, 0x00, 0x00, 0x00 , 0x00, 0x40, 0x48, 0x80, 0x00, 0x00, 0x00, 0x0C , 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x80 , 0x00, 0x00, 0x00, 0x0C, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x40, 0x40, 0x80, 0x41, 0x02, 0x04, 0x0C , 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x41 , 0x83, 0x00, 0x0C, 0x48, 0x08, 0x00, 0x00, 0x00 , 0x00, 0x04, 0xC1, 0x83, 0x02, 0x0C, 0x3C, 0x98 , 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x02 , 0x00, 0x94, 0x00, 0x4C, 0x60, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x80, 0x00, 0x48, 0x28, 0x00, 0x04 , 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x84, 0x0C , 0x84, 0x28, 0x00, 0x04, 0x30, 0x80, 0x00, 0x00 , 0x00, 0x00, 0x48, 0x0C, 0x08, 0x2C, 0x00, 0x00 , 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0xC0 , 0x00, 0x6C, 0x08, 0x00, 0x18, 0x80, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x40, 0x00, 0x9C, 0x8C, 0x00 , 0x18, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 , 0x00, 0x9C, 0x8C, 0x00, 0x18, 0x80, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x40, 0x1C, 0x2D, 0x6C, 0x0C , 0x90, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 , 0xCC, 0x16, 0x6C, 0x60, 0x30, 0x80, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x04, 0xC1, 0xCC, 0xCC, 0x30 , 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x48, 0xC4, 0x9C, 0x98, 0x84, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x9C, 0x6C , 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x48, 0xD4, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0xD4, 0xFC, 0xF8, 0xF0 , 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x48, 0xC0, 0xC0, 0xC0, 0x08, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x84 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x48, 0xE8, 0x08, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x04, 0xC0, 0xC0, 0xD4, 0xFC , 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xC0 , 0x08, 0x0C, 0x5C, 0xF8, 0xE0, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x48, 0x08, 0x00, 0x00, 0x48, 0xF0 , 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00 , 0x00, 0x00, 0x04, 0xD0, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x04, 0x48 , 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x48, 0x80 , 0x00, 0x00, 0x00, 0x0C, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x0C , 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x80 , 0x41, 0x02, 0x04, 0x0C, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x40, 0x08, 0x41, 0x83, 0x00, 0x0C, 0x48 , 0x08, 0x00, 0x00, 0x00, 0x00, 0x04, 0xC1, 0x83 , 0x02, 0x0C, 0x3C, 0x98, 0x84, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x81, 0x02, 0x00, 0x94, 0x6C, 0x6C , 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 , 0x48, 0x28, 0x08, 0xCC, 0x60, 0x08, 0x00, 0x00 , 0x00, 0x00, 0x84, 0x0C, 0x84, 0x00, 0x00, 0x4C , 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0x48, 0x0C , 0x08, 0x00, 0x00, 0x4C, 0x30, 0x80, 0x00, 0x00 , 0x00, 0x00, 0x04, 0xC0, 0x00, 0x00, 0x00, 0x90 , 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 , 0x00, 0x00, 0x04, 0x90, 0x30, 0x80, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x90 , 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 , 0x1C, 0x00, 0x48, 0x30, 0x98, 0x80, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x40, 0xCC, 0x0C, 0x90, 0x64 , 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 , 0xC1, 0xCC, 0x9C, 0x6C, 0x98, 0x84, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x40, 0xCC, 0x30, 0xCC, 0x1E , 0xCC, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40 , 0xCC, 0x30, 0xC4, 0xCC, 0x30, 0xF0, 0x80, 0x00 , 0x00, 0x00, 0x00, 0x40, 0x98, 0x30, 0xC0, 0x90 , 0xFC, 0xF0, 0x80, 0x00, 0x00, 0x00, 0x48, 0xC0 , 0xFC, 0xE0, 0x48, 0xD4, 0xF8, 0xE0, 0x08, 0x00 , 0x00, 0x00, 0xD4, 0xFC, 0xF8, 0xE0, 0xD4, 0xFC , 0xE0, 0x84, 0x00, 0x00, 0x00, 0x00, 0x48, 0xC0 , 0xC0, 0x84, 0x48, 0xC0, 0x84, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x48, 0x08, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 , 0xD4, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x48, 0xFC, 0xE8, 0xC0, 0xC0 , 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0 , 0xF4, 0xAC, 0x0C, 0x04, 0xC0, 0x08, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x48, 0xF0, 0x84, 0x00, 0x00 , 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 , 0xE0, 0x08, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x04, 0x84, 0x08, 0x00, 0x00 , 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40 , 0x0C, 0x00, 0x00, 0x00, 0x40, 0x84, 0x80, 0x00 , 0x00, 0x00, 0x00, 0x40, 0x0C, 0x00, 0x00, 0x00 , 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40 , 0x0C, 0x08, 0x01, 0x82, 0x40, 0x80, 0x80, 0x00 , 0x00, 0x00, 0x00, 0x04, 0x84, 0x0C, 0x00, 0x43 , 0x82, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x48 , 0x64, 0xCC, 0x0C, 0x01, 0x43, 0xC2, 0x08, 0x00 , 0x00, 0x00, 0x04, 0x80, 0x00, 0x3C, 0xC8, 0x00 , 0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00 , 0x00, 0x14, 0x4E, 0x84, 0x00, 0x40, 0x00, 0x00 , 0x00, 0x04, 0x84, 0x00, 0x00, 0x1C, 0x2C, 0x48 , 0x0C, 0x48, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00 , 0x04, 0x9C, 0x28, 0x04, 0x0C, 0x84, 0x00, 0x00 , 0x00, 0x40, 0x08, 0x00, 0x18, 0x3C, 0x28, 0x00 , 0xC0, 0x08, 0x00, 0x00, 0x00, 0x40, 0x08, 0x0C , 0x64, 0x2D, 0x2C, 0x00, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x04, 0x84, 0x18, 0xCC, 0x2D, 0x6C, 0x00 , 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x30 , 0xCC, 0x3C, 0x1E, 0x8C, 0x48, 0x00, 0x00, 0x00 , 0x00, 0x04, 0x90, 0x90, 0x64, 0x9C, 0x0B, 0xCC , 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x30, 0xC0 , 0x30, 0x9C, 0x4E, 0x86, 0x48, 0x00, 0x00, 0x00 , 0x00, 0x48, 0x30, 0x60, 0x90, 0xCC, 0x3C, 0xC8 , 0x84, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xB0, 0x64 , 0xC8, 0x64, 0x6C, 0xC8, 0x00, 0x00, 0x00, 0x00 , 0x00, 0xD0, 0xF0, 0xC8, 0x84, 0x90, 0x64, 0xC0 , 0x08, 0x00, 0x00, 0x00, 0x00, 0x48, 0xF0, 0xF0 , 0xE0, 0xD0, 0xF4, 0xFC, 0xC0, 0x08, 0x00, 0x00 , 0x00, 0x04, 0xD0, 0xF0, 0xF0, 0xD0, 0xF0, 0xFC , 0xFC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x48, 0xC0 , 0xC0, 0x48, 0xC0, 0xC0, 0xC0, 0x08, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x48, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x04, 0xD4, 0x84, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48 , 0xFC, 0xE8, 0xC0, 0xC0, 0x08, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0xD0, 0xF4, 0xAC, 0x0C, 0x04 , 0xC0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48 , 0xF0, 0x84, 0x00, 0x00, 0x04, 0x84, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x40, 0xE0, 0x08, 0x00, 0x00 , 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 , 0x84, 0x08, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00 , 0x00, 0x00, 0x00, 0x40, 0x0C, 0x00, 0x00, 0x00 , 0x40, 0x84, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40 , 0x0C, 0x00, 0x00, 0x00, 0x40, 0x80, 0x80, 0x00 , 0x00, 0x00, 0x00, 0x40, 0x0C, 0x08, 0x01, 0x82 , 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04 , 0x84, 0x0C, 0x00, 0x43, 0x82, 0x04, 0x80, 0x00 , 0x00, 0x00, 0x00, 0x48, 0x64, 0x3C, 0x0C, 0x01 , 0x43, 0xC2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x90 , 0x8C, 0x00, 0x68, 0x00, 0x01, 0x42, 0x00, 0x00 , 0x00, 0x00, 0x04, 0x90, 0x08, 0x00, 0x14, 0x84 , 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x30 , 0x08, 0x00, 0x14, 0x48, 0x0C, 0x48, 0x00, 0x00 , 0x00, 0x00, 0x40, 0x30, 0x00, 0x00, 0x1C, 0x04 , 0x0C, 0x84, 0x00, 0x00, 0x00, 0x00, 0x40, 0x24 , 0x00, 0x04, 0x9C, 0x00, 0xC0, 0x08, 0x00, 0x00 , 0x00, 0x00, 0x40, 0x24, 0x00, 0x4C, 0x6C, 0x00 , 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x24 , 0x00, 0x4C, 0x6C, 0x00, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x40, 0x60, 0x0C, 0x9C, 0x1E, 0x2C , 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x30 , 0x90, 0x9C, 0x29, 0xCC, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x04, 0x90, 0x30, 0xCC, 0xCC, 0xC2 , 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48 , 0x64, 0x6C, 0xC8, 0x84, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x48, 0x9C, 0x6C, 0x84, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0 , 0xF4, 0xFC, 0xE8, 0x84, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x48, 0xF0, 0xF4, 0xFC, 0xE8 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 , 0xC0, 0xC0, 0xC0, 0x84, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x48, 0x08, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 , 0xD4, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x48, 0xFC, 0xE8, 0xC0, 0xC0 , 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0 , 0xF4, 0xAC, 0x0C, 0x04, 0xC0, 0x08, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x48, 0xF0, 0x84, 0x00, 0x00 , 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 , 0xE0, 0x08, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x04, 0x84, 0x08, 0x00, 0x00 , 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40 , 0x0C, 0x00, 0x00, 0x00, 0x40, 0x84, 0x80, 0x00 , 0x00, 0x00, 0x00, 0x40, 0x0C, 0x00, 0x00, 0x00 , 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40 , 0x0C, 0x08, 0x01, 0x82, 0x40, 0x80, 0x80, 0x00 , 0x00, 0x00, 0x00, 0x04, 0x84, 0x0C, 0x00, 0x43 , 0x82, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x48 , 0x64, 0x3C, 0x0C, 0x01, 0x43, 0xC2, 0x08, 0x00 , 0x00, 0x00, 0x00, 0x90, 0x9C, 0x9C, 0x68, 0x00 , 0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x04, 0x90 , 0xCC, 0x04, 0x14, 0x84, 0x00, 0x40, 0x00, 0x00 , 0x00, 0x00, 0x40, 0x30, 0x8C, 0x00, 0x00, 0x48 , 0x0C, 0x48, 0x00, 0x00, 0x00, 0x00, 0x40, 0x30 , 0x8C, 0x00, 0x00, 0x04, 0x0C, 0x84, 0x00, 0x00 , 0x00, 0x00, 0x40, 0x30, 0x60, 0x00, 0x00, 0x00 , 0xC0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x30 , 0x60, 0x08, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x40, 0x30, 0x60, 0x80, 0x00, 0x00 , 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x64 , 0x30, 0x84, 0x00, 0x2C, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x04, 0x90, 0x98, 0x60, 0x0C, 0xCC , 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x64 , 0x9C, 0x6C, 0xCC, 0xC2, 0x08, 0x00, 0x00, 0x00 , 0x00, 0x04, 0x90, 0xCC, 0x2D, 0xCC, 0x30, 0xCC , 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0xF0, 0x30 , 0xCC, 0xC8, 0x30, 0xCC, 0x80, 0x00, 0x00, 0x00 , 0x00, 0x40, 0xF0, 0xFC, 0x60, 0xC0, 0x30, 0x64 , 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD0, 0xF4 , 0xE8, 0x84, 0xD0, 0xFC, 0xC0, 0x84, 0x00, 0x00 , 0x00, 0x00, 0x48, 0xD0, 0xFC, 0xE8, 0xD0, 0xF4 , 0xFC, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48 , 0xC0, 0x84, 0x48, 0xC0, 0xC0, 0x84, 0x00, 0x00 };
Para nuestro programa utilizaremos las rutinas que ya vimos en el anterior tutorial Sprites I: Introducción al uso de sprites para poner la paleta y pintar los sprites. Vamos a hacer que se mueva de izquierda a derecha el personaje, intercalando los graficos que hemos exportado, para simular que el personaje camina. Para hacerlo de manera sencilla, vamos a introducir varios conceptos más avanzados de c como son enumeraciones, estructuras y punteros a puntero. Por ejemplo, para simplificar el sentido del movimiento usaremos el siguiente enum: enum _eDirection { Direction_Left, Direction_Right, Direction_Max };
Para manejar el personaje, su posición, movimiento y animación usaremos la siguiente estructura: struct _tSprite { int nY; int nX; int nKey; unsigned int nSpeed; unsigned int nLastMoveTime; enum _eDirection eDirection; }_tSprite;
Para manejar y almacenar los distintos 'frames' de la animación vamos a usar este array que apunta a cada uno de los 4 frames tanto para izquierda como para derecha: char *aKeyFrames[Direction_Max][4]; Que rellenaremos de la siguiente manera: aKeyFrames[Direction_Left][0] = (char *)NickSprite; aKeyFrames[Direction_Left][1] = (char *)NickSprite + NICK_WIDTH * NICK_HEIGHT; aKeyFrames[Direction_Left][2] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 2; aKeyFrames[Direction_Left][3] = (char *)NickSprite + NICK_WIDTH * NICK_HEIGHT; aKeyFrames[Direction_Right][0] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 3; aKeyFrames[Direction_Right][1] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 4; aKeyFrames[Direction_Right][2] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 5; aKeyFrames[Direction_Right][3] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 4; A pesar de que tenemos 3 graficos diferentes para cada sentido, hemos puesto 4 frames, esto es así ya que la secuencia queda de la siguiente forma: Pie izquierdo delante, pies juntos, pie derecho delante, pies juntos y luego volvería a empezar. Finalmente el código fuente entero del programa queda de la siguiente manera: //////////////////////////////////////////////////////////////////////// // sprite01.c // Mochilote - www.cpcmania.com //////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <stdlib.h> #include <string.h> #include "Nick.h" #define MAX_X 79 #define MAX_Y 199 void SetColor(unsigned char nColorIndex, unsigned char nPaletteIndex) { __asm ld a, 4 (ix) ld b, 5 (ix) ld c, b call #0xBC32 ;SCR SET INK __endasm; } void SetPalette(const unsigned char *pPalette) { unsigned char nColor = 0; for(nColor = 0; nColor < NUM_COLORS; nColor++) SetColor(nColor, pPalette[nColor]); } void PutSpriteMode0(unsigned char *pAddress, unsigned char nWidth, unsigned char nHeight, unsigned char *pSprite) { __asm LD L, 4(IX) LD H, 5(IX) LD C, 6(IX) LD B, 7(IX) LD E, 8(IX) LD D, 9(IX) _loop_alto: PUSH BC LD B,C PUSH HL _loop_ancho: LD A,(DE) LD (HL),A INC DE INC HL DJNZ _loop_ancho POP HL LD A,H ADD #0x08 LD H,A SUB #0xC0 JP NC, _sig_linea LD BC, #0xC050 ADD HL,BC _sig_linea: POP BC DJNZ _loop_alto __endasm; } //////////////////////////////////////////////////////////////////////// unsigned char char1,char2,char3,char4; unsigned int GetTime() { unsigned int nTime = 0; __asm CALL #0xBD0D ;KL TIME PLEASE PUSH HL POP DE LD HL, #_char3 LD (HL), D LD HL, #_char4 LD (HL), E __endasm; nTime = (char3 << 8) + char4; return nTime; } //////////////////////////////////////////////////////////////////////// enum _eDirection { Direction_Left, Direction_Right, Direction_Max }; char *aKeyFrames[Direction_Max][4]; struct _tSprite { int nY; int nX; int nKey; unsigned int nSpeed; unsigned int nLastMoveTime; enum _eDirection eDirection; }_tSprite; #define NUM_SPRITES 1 struct _tSprite aSprites[NUM_SPRITES]; void main() { //SCR_SET_MODE 0 __asm ld a, #0 call #0xBC0E __endasm; //SCR SET BORDER 0 __asm ld b, #0 ;black ld c, b call #0xBC38 __endasm; SetPalette(NickPalette); aKeyFrames[Direction_Left][0] = (char *)NickSprite; aKeyFrames[Direction_Left][1] = (char *)NickSprite + NICK_WIDTH * NICK_HEIGHT; aKeyFrames[Direction_Left][2] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 2; aKeyFrames[Direction_Left][3] = (char *)NickSprite + NICK_WIDTH * NICK_HEIGHT; aKeyFrames[Direction_Right][0] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 3; aKeyFrames[Direction_Right][1] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 4; aKeyFrames[Direction_Right][2] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 5; aKeyFrames[Direction_Right][3] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 4; aSprites[0].eDirection = Direction_Right; aSprites[0].nKey = 0; aSprites[0].nX = 0; aSprites[0].nY = 75; aSprites[0].nSpeed = 20; aSprites[0].nLastMoveTime = GetTime(); while(1) { unsigned char nSprite = 0; for(nSprite = 0; nSprite < NUM_SPRITES; nSprite++) { if(GetTime() - aSprites[nSprite].nLastMoveTime < aSprites[nSprite].nSpeed) continue; aSprites[nSprite].nLastMoveTime += aSprites[nSprite].nSpeed; //move aSprites[nSprite].nX += (aSprites[nSprite].eDirection == Direction_Right ? 1 : -1); if(aSprites[nSprite].nX <= 0) { aSprites[nSprite].nX = 0; aSprites[nSprite].eDirection = Direction_Right; aSprites[nSprite].nKey = 0; } if(aSprites[nSprite].nX >= (MAX_X - NICK_WIDTH)) { aSprites[nSprite].nX = MAX_X - NICK_WIDTH; aSprites[nSprite].eDirection = Direction_Left; aSprites[nSprite].nKey = 0; } aSprites[nSprite].nKey++; if(aSprites[nSprite].nKey > 3) aSprites[nSprite].nKey = 0; PutSpriteMode0((unsigned char *)(0xC000 + ((aSprites[nSprite].nY / 8u) * 80u) + ((aSprites[nSprite].nY % 8u) * 2048u) + aSprites[nSprite].nX), NICK_WIDTH, NICK_HEIGHT, (unsigned char *)aKeyFrames[aSprites[nSprite].eDirection][aSprites[nSprite].nKey]); } } } //////////////////////////////////////////////////////////////////////// Si compilamos y ejecutamos en el emulador obtenemos lo siguiente:
Vamos ahora a modificar mínimamente el programa, para que maneje 4 personajes simultáneamente, con 4 velocidades diferentes: //////////////////////////////////////////////////////////////////////// // sprite02.c // Mochilote - www.cpcmania.com //////////////////////////////////////////////////////////////////////// #include <stdio.h> #include <stdlib.h> #include <string.h> #include "Nick.h" #define MAX_X 79 #define MAX_Y 199 void SetColor(unsigned char nColorIndex, unsigned char nPaletteIndex) { __asm ld a, 4 (ix) ld b, 5 (ix) ld c, b call #0xBC32 ;SCR SET INK __endasm; } void SetPalette(const unsigned char *pPalette) { unsigned char nColor = 0; for(nColor = 0; nColor < NUM_COLORS; nColor++) SetColor(nColor, pPalette[nColor]); } void PutSpriteMode0(unsigned char *pAddress, unsigned char nWidth, unsigned char nHeight, unsigned char *pSprite) { __asm LD L, 4(IX) LD H, 5(IX) LD C, 6(IX) LD B, 7(IX) LD E, 8(IX) LD D, 9(IX) _loop_alto: PUSH BC LD B,C PUSH HL _loop_ancho: LD A,(DE) LD (HL),A INC DE INC HL DJNZ _loop_ancho POP HL LD A,H ADD #0x08 LD H,A SUB #0xC0 JP NC, _sig_linea LD BC, #0xC050 ADD HL,BC _sig_linea: POP BC DJNZ _loop_alto __endasm; } //////////////////////////////////////////////////////////////////////// unsigned char char1,char2,char3,char4; unsigned int GetTime() { unsigned int nTime = 0; __asm CALL #0xBD0D ;KL TIME PLEASE PUSH HL POP DE LD HL, #_char3 LD (HL), D LD HL, #_char4 LD (HL), E __endasm; nTime = (char3 << 8) + char4; return nTime; } //////////////////////////////////////////////////////////////////////// enum _eDirection { Direction_Left, Direction_Right, Direction_Max }; char *aKeyFrames[Direction_Max][4]; struct _tSprite { int nY; int nX; int nKey; unsigned int nSpeed; unsigned int nLastMoveTime; enum _eDirection eDirection; }_tSprite; #define NUM_SPRITES 4 struct _tSprite aSprites[NUM_SPRITES]; void main() { //SCR_SET_MODE 0 __asm ld a, #0 call #0xBC0E __endasm; //SCR SET BORDER 0 __asm ld b, #0 ;black ld c, b call #0xBC38 __endasm; SetPalette(NickPalette); aKeyFrames[Direction_Left][0] = (char *)NickSprite; aKeyFrames[Direction_Left][1] = (char *)NickSprite + NICK_WIDTH * NICK_HEIGHT; aKeyFrames[Direction_Left][2] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 2; aKeyFrames[Direction_Left][3] = (char *)NickSprite + NICK_WIDTH * NICK_HEIGHT; aKeyFrames[Direction_Right][0] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 3; aKeyFrames[Direction_Right][1] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 4; aKeyFrames[Direction_Right][2] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 5; aKeyFrames[Direction_Right][3] = (char *)NickSprite + (NICK_WIDTH * NICK_HEIGHT) * 4; aSprites[0].eDirection = Direction_Right; aSprites[0].nKey = 0; aSprites[0].nX = 0; aSprites[0].nY = 25; aSprites[0].nSpeed = 20; aSprites[0].nLastMoveTime = GetTime(); aSprites[1].eDirection = Direction_Left; aSprites[1].nKey = 0; aSprites[1].nX = 50; aSprites[1].nY = 25; aSprites[1].nSpeed = 15; aSprites[1].nLastMoveTime = GetTime(); aSprites[2].eDirection = Direction_Right; aSprites[2].nKey = 0; aSprites[2].nX = 0; aSprites[2].nY = 75; aSprites[2].nSpeed = 5; aSprites[2].nLastMoveTime = GetTime(); aSprites[3].eDirection = Direction_Right; aSprites[3].nKey = 0; aSprites[3].nX = 0; aSprites[3].nY = 150; aSprites[3].nSpeed = 10; aSprites[3].nLastMoveTime = GetTime(); while(1) { unsigned char nSprite = 0; for(nSprite = 0; nSprite < NUM_SPRITES; nSprite++) { if(GetTime() - aSprites[nSprite].nLastMoveTime < aSprites[nSprite].nSpeed) continue; aSprites[nSprite].nLastMoveTime += aSprites[nSprite].nSpeed; //move aSprites[nSprite].nX += (aSprites[nSprite].eDirection == Direction_Right ? 1 : -1); if(aSprites[nSprite].nX <= 0) { aSprites[nSprite].nX = 0; aSprites[nSprite].eDirection = Direction_Right; aSprites[nSprite].nKey = 0; } if(aSprites[nSprite].nX >= (MAX_X - NICK_WIDTH)) { aSprites[nSprite].nX = MAX_X - NICK_WIDTH; aSprites[nSprite].eDirection = Direction_Left; aSprites[nSprite].nKey = 0; } aSprites[nSprite].nKey++; if(aSprites[nSprite].nKey > 3) aSprites[nSprite].nKey = 0; PutSpriteMode0((unsigned char *)(0xC000 + ((aSprites[nSprite].nY / 8u) * 80u) + ((aSprites[nSprite].nY % 8u) * 2048u) + aSprites[nSprite].nX), NICK_WIDTH, NICK_HEIGHT, (unsigned char *)aKeyFrames[aSprites[nSprite].eDirection][aSprites[nSprite].nKey]); } } } //////////////////////////////////////////////////////////////////////// Si compilamos y ejecutamos en el emulador obtenemos lo siguiente: Como vemos, con apenas 3 graficos hemos hecho caminar a nuestro personaje e incluso a diferentes velocidades. Si nos fijamos en los dos personajes de la parte de arriba, vemos que al chocar entre ellos se produce un efecto muy típico en muchos juegos en nuestro cpc. Podéis bajar un zip con todos ficheros (código fuente, bat's para compilar, binarios y dsk's) aquí: Sprites_II.zip |
www.CPCMania.com 2012 |