|
|
|
¿Qué son y para qué sirven los sprites? Un sprite es simplemente una figura o imagen de dimensiones no muy grandes, que puede desplazarse por la pantalla, es decir que posee movimiento. Hay que tener claro que tambien existen los bitmaps, que tambien son como los sprites, pero no poseen movimiento, es decir es una agrupación de pixeles que forma una figura, y por lo tanto es estática. Un sprite está formado por varios frames o cuadros, lo cuales forman una animación, por ejemplo nuestro protagonista de un juego de plataforma, o un juego de naves, etc. Así tenemos que un frame o cuadro es simplemente uno de los dibujos que se muestran en la pantalla. Los sprites pueden tener cualquier tamaño, y normalmente tendrán asociadas unas variables, las cuales por ejemplo pueden representar su posición en la pantalla, el ancho y el alto del sprite, etc. Algunas veces pueden tener factores como la velocidad, el estado del sprite. Por ejemplo en un juego un sprite tendrá varias variables, como por ejemplo una para saber si colisionó o choco con otro sprite, etc. Los sprites siempre son rectangulares, aunque al verlos en un programa no lo parezcan, esto se debe a técnicas que se utilizan una de ellas es el uso de mascaras. La principal función de los sprites es la de las animaciones, ya sea en una presentación, juego, etc. Los sprites son muy usados en los juegos 2-D, ya sean de plataformas, aventuras gráficas, etc. Aunque hay excepciones donde los sprites pueden ser utilizados en juegos 3-D, un ejemplo de ello es el conocidisimo Wolfenstein 3D, de la empresa ID Software, aunque no lo crean este juego utilizaba sprites, a diferencia de los ultimos juegos tridimensionales como el Quake, Duke Nukem, etc. Ejemplo de juegos que han utilizado sprites son el Street Fighter, Mortal Kombat, Killer Instinct, y clásicos como The Prince of Persia, la saga Keen Commander, etc. Creando un sprite Antes de crear un sprite, tendremos que
crearnos una estructura que almacene todas las variables necesarias y los
frames que formarán el sprite. Esto en C se puede hacer así:
Hemos creado un tipo de dato llamado t_sprite, que contiene las variables básicos para trabajar con un sprite. Dentro de la estructura definimos a los frames de esta forma: unsigned char *frame[MAX_FRAMES]; lo cual es un arreglo de punteros, la gracia de hacer esto que podemos crear un sprite de cualquier tamaño. MAX_FRAMES es una constante que puede ser definida así: #define MAX_FRAMES 10 Para crear cada frame deberemos reservar la memoria necesaria. Si de dan cuenta, hay solo un inconveniente. Imaginemos que tenemos un sprite de solo 3 frames, y nosotros definimos ese arreglo de tamaño 10, por lo que se desperdiciaran 7 posiciones. Esto se puede solucionar usando listas enlazadas, pero para no complicarnos lo haremos así no mas. Ya tenemos una estructura para guardar nuestros sprites, pero ahora ¿cómo almaceno los sprites en el disco duro para poder cargarlos después desde mi programa? Para esto hay varias posibilidades todas basadas en el uso de archivos, una es tener archivos independientes, es decir un archivo para cada frame. Pero esto puede resultar incomodo si tenemos un sprite por ejemplo de 50 frames, tendríamos que tener 50 archivos. En todo caso nunca tendremos tantos. Para tener archivos independientes podríamos usar los típicos archivos *.CEL del Autodesk Animator o bien crearnos un tipo de archivo a nuestra medida y esto será lo que haremos nosotros. Otra forma sería guardar todos los frames en un mismo archivo de un formato propio, o en formatos tradicionales como el GIF, PCX, BMP. De estos tres el más recomendable es el PCX, ya que es mas fácil de trabajar y comprime las imágenes. Creando nuestro propio formato de sprite Realizar esto no es complicado, simplemente hay que conocer el manejo de archivos en C. Lo que haremos será crearnos un archivo que tendrá la extensión SPR, y tendrá la siguientes estructura: CABECERA: 0 byte: ancho del sprite
IMAGEN: resto del archivo desde el byte 2. Los 2 primeros bytes contendrán
el ancho y alto de nuestro sprites y el resto del archivo será la
información de cada pixel que forma el frame.
Tamaño = ancho * alto + 2; La pregunta ahora es como creamos nuestro archivo, esto se puede hacer de varias formas, las más simple es tener nuestro sprite en un formato tradicional como el PCX, entonces crearnos un “programita” que transforme el archivo PCX en un archivo con nuestro formato. En la sección herramientas podrás encontrar un programa muy simple, que realice hace un tiempo, y hace esto. Su funcion es leer un archivo PCX, luego lo muestra en pantalla, luego guarda el ancho y el alto de la imagen y lee cada pixel y lo va guardando en un archivo. El programa también guarda la paleta. Esta última es muy importante para conocer la información de los colores que usa nuestro sprite. Veamos como nos quedaría la funcion
que lee un simple frame desde un archivo:
Lo que hace esta funcion es recibir como parámetro el nombre del archivo y un puntero a un puntero a un dato de tipo byte. Luego abrimos el archivo y vemos si existe o no. Si no existe devolvemos un error. En caso que exista leemos la cabecera para conocer las dimensiones de nuestro frame si es mas grande que 55 devolvemos un error. Si el tamaño del frame es menor o igual a 255, reservamos la memoria necesaria, así nuestro puntero contendrá en sus dos primeros bytes el ancho y el alto, del byte 2 en adelante estará la información de la imagen. Luego leemos los datos de la imagen del archivo y listo. Como vemos ya podemos leer un archivo con nuestro formato y guardar los datos en memoria. Al final de nuestro programa deberemos liberar la memoria reservada, para hacer esto simplemente llamamos a la funcion free con el puntero al frame como parámetro. Ahora veremos como crearnos una función que abra varios archivos de tipo spr, pero con la condición que todas tengan el mismo nombre y todos se encuentren enumerados. Veamos:
Espero que hayan entendido la función,
aunque no es de lo mejor, lo ideal sería usar listas enlazadas.
Tal vez más adelante en otra sección incluya como hacer esto
último.
r=LoadSpr(“auto”, &sprite, 3); suponiendo que sprite se definió así: t_sprite sprite; donde r, será una variable de tipo entero que guardará el valor que regresa la funcion y 3 corresponde al numero de frames que conforma el sprite. Ojo que la funcion puede devolver los siguientes valores: 0: Archivo
no encontrado
Pero esto no es todo debemos crearnos una
funcion que elimine todos los frames de la memoria:
De esta forma si por ejemplo queremos eliminar los frames del auto lo haríamos así: Dibujando sprites en la pantalla Ya sabemos como dejar un sprite en memoria,
pero ahora ¿cómo lo colocamos en la pantalla? Para hacer
esto podemos tomar el sprite y leer fila a fila la imagen y visualizarlas.
Lo ideal sería que esta funcion que pone un sprite en la pantalla
estuviera hecha en ensamblador. Pero por ahora nosotros veremos solo un
funcion en C:
Si se dan cuenta, esta función hará que nuestro sprite aparezca como un rectángulo, lo cual no resulta muy bonito, a continuación veremos como solucionar esto. Sprites transparentes Un sprite transparente es un sprite que tiene asociado un color específico como fondo, por ejemplo el color 0 (negro). Así cuando queramos dibujar un sprite, simplemente tendremos que “preguntar” si el color que vamos a dibujar es el color de la mascara, si es así no lo dibujaremos y pasaremos al otro. Cuando encontremos un color distinto de 0 dibujaremos dicho color. Casi siempre se utiliza el color 0 como máscara, ya que al realizar la función en ensamblador para colocar un sprite, es mucho más fácil verificar si una variable tiene el valor 0. Entonces nuestra rutina para colocar sprites
transparentes se haría así:
De ahora en adelante nosotros utilizaremos esta función, ya que sería muy “feo” que nuestro sprite se viera rectangular. Animaciones Realizar una animación de un sprite no es nada difícil. Imaginemos que tenemos un “sprite” que comprende varios frames y queremos animarla y desplazarla sobre un fondo estático. Para hacer esto tenemos tres formas de hacerlo. No son las únicas ni las mejores, pero si son las más comunas y sencillas, veamos: Método 1:“Utiliza harta memoria” 1) Crear e inicializar dos pantallas
virtuales (pv1 y pv2).
Ventajas: El mas fácil de implementar.
Desventajas: - Necesita mucha memoria, es decir dos
pantallas virtuales más los datos de los sprites,
Método 2: “No necesita mucha memoria” 1) Dibujar el fondo en la VGA o
copiarlo de alguna pantalla virtual.
Ventajas: - No necesita ninguna pantalla virtual.
Desventajas: - Dibujar en la VGA es más lento
que dibujar en una pantalla virtual.
Método 3: “Un poco de memoria” 1) Crear e inicializar una pantalla
virtual (pv).
Ventajas: - No necesita tanta memoria, solamente
una pantalla virtual.
Desventajas: - Es un poco más complejo que lo
otros métodos.
Estos tres son los métodos más comunes, pero pueden haber más. Lo que deben hacer ustedes es adaptar el método que más se ajuste a su programa, haciendo un balance entre la memoria, velocidad y calidad. Incluso pueden combinar dos o más métodos, por ejemplo, en el método 3, en lugar de dibujar el fondo y los sprites en la VGA, pueden dibujarlos en otra pantalla virtual y copiar todo después a la VGA como en el método 1. Eso reduce mucho el parpadeo e incremente la velocidad, pero consume más memoria. Ya sabemos como crear una animación,
pero se nos queda algo importante en el tintero, que pasa si cargo un sprite,
¿cómo se cuales son sus colores? Bueno muy simple, conociendo
su paleta de colores, para esto debemos tener en un archivo la paleta de
colores correspondiente al sprite que visualizaremos. Si recuerdan una
paleta tiene las valores RGB de los 256 colores que pueden estar mostrándose
en la pantalla simultáneamente en la pantalla. Entonces lo que haremos
será leer desde un archivo la paleta de colores, luego almacenarla
en un arreglo t_paleta y colocarla en el sistema con SetPal(). Para esto
crearemos una funcion que nos lea la información de una paleta desde
un archivo, es muy simple. Veamos:
Esta función recibe como parámetros el nombre de la paleta, que generalmente tiene la extensión pal, tambien recibe una variable de tipo t_paleta para guardar los datos leídos. Se abre el archivo y se verifica que el archivo tenga el tamaño 768 (recuerden: 256*3=768), y al final se lee la paleta. La funcion filesize la podrás encontrar en el archivo vgalib.h Ahora veremos como haríamos una
animación utilizando el método 1. Lo primero que se hará,
será cargar todos los sprites en memoria y cargar la paleta correspondiente.
Por ejemplo imaginemos que tenemos la toda la secuencia de frames de un
“mono” caminando. Supongamos que el sprite está formado por 5 frames.
Entonces si queremos mostrar la animación ser haría de esta
forma:
Como ven no es difícil crear animaciones. Tengan en cuenta que en el ejemplo no verificamos ningún error, como por ejemplo si no hay memoria o si no existe algún archivo. Ejemplo Ahora podrán encontrar un ejemplo similar al anterior, pero más completo y con los archivos de los sprites y paleta. Ver Librería gráfica:
vgalib.h
|