8. Cómo
crear figuras multicolor
que se muevan. Cuarto juego (aproximación "b"): Miniserpiente 2.
Contenido
de este apartado:
8.1.
Ideas generales.
Ya sabemos como usar "Mapas"
para memorizar los obstáculos y "premios" que el personaje de
nuestro juego debe esquivar o alcanzar. Pero nuestros personajes son
"pobres", con una presentación muy poco lucida. Va llegando el
momento de hacer personajes un poco más vistosos.
Aprenderemos a crear figuras
multicolor que se muevan. Además estas figuras serán
"transparentes": podrán tener "huecos" alrededor o en su
interior y a través de estos huecos deberá verse el
fondo. Estas figuras reciben el nombre de "sprites".
En Allegro tenemos rutinas para
el manejo de Sprites:
draw_sprite(screen,
figura, posicionX, posicionY);
En Pascal también
tendríamos algo parecido con la orden "putimage", pero seremos
más atrevidos: imitaremos lo que haría la orden
"draw_sprite" con una creada por nosotros, para que se entienda mejor
el funcionamiento, a cambio de que el resultado sea algo más
lento (no tendremos muchas figuras en pantalla, no será
grave).
El pseudocódigo de lo que
hará esta función (muy parecido a lo que haremos en
Pascal) sería:
procedimiento
dibujar_sprite(imagen, posicX, posicY);
para i = 1 hasta ANCHOSPRITE
para j = 1 hasta ALTOSPRITE
si imagen[j,i] <> 0 entonces
dibujar_punto(x+i-1, y+j-1,
imagen[j,i]);
Simplemente dibujamos todos los
puntos menos los que sean del color que hayamos considerado
transparente (en nuestro caso, el 0).
Y los sprites los vamos a crear
desde dentro de nuestro programa (más adelante veremos
cómo leer imágenes desde ficheros). Simplemente
será un array de dos dimensiones, qe indicará el color de
cada uno de los puntos que forman la figura:
spriteLadrillo =
{{0,2,2,2,2,2,2,2,2,0},
{2,1,1,1,1,1,1,1,1,2},
{2,1,1,1,1,1,1,1,1,2},
{2,1,1,1,1,1,1,1,1,2},
{2,1,1,1,1,1,1,1,1,2},
{2,1,1,1,1,1,1,1,3,2},
{2,1,1,1,1,1,1,3,3,2},
{2,1,1,1,1,1,3,3,2,2},
{2,2,2,2,2,2,2,2,2,0}
};
El resto del fuente es
idéntico al que hicimos en el apartado anterior. La apariencia
que buscamos (algo mejor que la anterior, pero todavía nada
espectacular) es

8.2
Miniserpiente 2
en
C.
La única diferencia importante con la versión 1 es el
manejo de los sprites:
/*----------------------------*/
/* Intro a la programac de */
/* juegos, por Nacho Cabanes */
/* */
/* IPJ08C.C */
/* */
/* Octavo ejemplo: juego de */
/* "miniSerpiente" (aprox B) */
/* */
/* Comprobado con: */
/* - MinGW DevStudio 2.05 */
/* (gcc 3.4.2) y Allegro */
/* 4.03, Windows XP */
/*----------------------------*/
#include <allegro.h>
/* Posiciones X e Y iniciales */
#define POS_X_INI 16
#define POS_Y_INI 10
#define INC_X_INI 1
#define INC_Y_INI 0
/* Pausa en milisegundos entre un "fotograma" y otro */
#define PAUSA 350
/* Teclas predefinidas */
#define TEC_ARRIBA KEY_E #define TEC_ABAJO KEY_X #define TEC_IZQDA KEY_S #define TEC_DCHA KEY_D
int posX, posY; /* Posicion actual */
int incX, incY; /* Incremento de la posicion */
/* Terminado: Si ha chocado o comida todas las frutas */
int terminado;
/* La tecla pulsada */
int tecla;
/* Escala: relacion entre tamaño de mapa y de pantalla */
#define ESCALA 10
/* Ancho y alto de los sprites */
#define ANCHOSPRITE 10
#define ALTOSPRITE 10
/* Y el mapa que representa a la pantalla */
/* Como usaremos modo grafico de 320x200 puntos */
/* y una escala de 10, el tablero medira 32x20 */
#define MAXFILAS 20
#define MAXCOLS 33
char mapa[MAXFILAS][MAXCOLS]={
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"X X X",
"X F X X",
"X F X F X",
"X XXXXX X X",
"X X X X",
"X X X X X",
"X X X X XXXX",
"X X X X",
"X X X X",
"X X X X",
"X F X X",
"X X X",
"X X F X",
"X X X X",
"X X X X",
"X X F X X",
"X F X X X",
"X X F X",
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
};
int numFrutas = 8;
/* Nuestros sprites */
BITMAP *ladrilloFondo, *comida, *jugador;
typedef
char tipoSprite[ANCHOSPRITE][ALTOSPRITE];
/* El sprite en si: matriz de 10x10 bytes */
tipoSprite spriteLadrillo =
{{0,2,2,2,2,2,2,2,2,0},
{2,1,1,1,1,1,1,1,1,2},
{2,1,1,1,1,1,1,1,1,2},
{2,1,1,1,1,1,1,1,1,2},
{2,1,1,1,1,1,1,1,1,2},
{2,1,1,1,1,1,1,1,3,2},
{2,1,1,1,1,1,1,3,3,2},
{2,1,1,1,1,1,3,3,2,2},
{2,2,2,2,2,2,2,2,2,0}
};
tipoSprite spriteComida =
{{0,0,0,2,0,0,0,0,0,0},
{0,0,2,2,0,0,2,2,0,0},
{0,4,4,4,2,2,4,4,0,0},
{4,4,4,4,4,2,4,4,4,0},
{4,4,4,4,4,4,4,4,4,0},
{4,4,4,4,4,4,4,4,4,0},
{4,4,4,4,4,4,4,4,4,0},
{4,4,4,4,4,4,4,4,4,0},
{0,4,4,4,4,4,4,4,0,0}
};
tipoSprite spriteJugador =
{{0,0,3,3,3,3,3,0,0,0},
{0,3,1,1,1,1,1,3,0,0},
{3,1,1,1,1,1,1,1,3,0},
{3,1,1,1,1,1,1,1,3,0},
{3,1,1,1,1,1,1,1,3,0},
{3,1,1,1,1,1,1,1,3,0},
{0,3,1,1,1,1,1,3,0,0},
{0,0,3,3,3,3,3,0,0,0}
};
/* -------------- Rutina de crear los sprites ------------- */
void creaSprites()
{
int i, j;
ladrilloFondo = create_bitmap(10, 10);
clear_bitmap(ladrilloFondo);
for(i=0; i<ANCHOSPRITE; i++)
for (j=0; j<ALTOSPRITE; j++)
putpixel(ladrilloFondo, i, j,
palette_color[ spriteLadrillo[j][i] ]);
comida = create_bitmap(10, 10);
clear_bitmap(comida);
for(i=0; i<ANCHOSPRITE; i++)
for (j=0; j<ALTOSPRITE; j++)
putpixel(comida, i, j,
palette_color[ spriteComida[j][i] ]);
jugador = create_bitmap(10, 10);
clear_bitmap(jugador);
for(i=0; i<ANCHOSPRITE; i++)
for (j=0; j<ALTOSPRITE; j++)
putpixel(jugador, i, j,
palette_color[ spriteJugador[j][i] ]);
}
/* -------------- Rutina de dibujar el fondo ------------- */
void dibujaFondo()
{
int i, j;
clear_bitmap(screen);
for(i=0; i<MAXCOLS; i++)
for (j=0; j<MAXFILAS; j++) {
if (mapa[j][i] == 'X')
draw_sprite(screen, ladrilloFondo, i*ESCALA, j*ESCALA);
if (mapa[j][i] == 'F')
draw_sprite(screen, comida, i*ESCALA, j*ESCALA);
}
}
/* ------------------------------------------------ */
/* */
/* -------------- Cuerpo del programa ------------- */
int main()
{
allegro_init(); /* Inicializamos Allegro */
install_keyboard();
install_timer();
/* Intentamos entrar a modo grafico */
if (set_gfx_mode(GFX_SAFE, 320, 200, 0, 0) != 0) {
set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
allegro_message(
"Incapaz de entrar a modo grafico\n%s\n",
allegro_error);
return 1;
}
/* ----------------------- Si todo ha ido bien: empezamos */
creaSprites();
dibujaFondo();
/* Valores iniciales */
posX = POS_X_INI;
posY = POS_Y_INI;
incX = INC_X_INI;
incY = INC_Y_INI;
/* Parte repetitiva: */
do {
dibujaFondo();
draw_sprite (screen, jugador, posX*ESCALA, posY*ESCALA);
terminado = FALSE;
/* Si paso por una fruta: la borro y falta una menos */
if (mapa[posY][posX] == 'F') {
mapa[posY][posX] = ' ';
numFrutas --;
if (numFrutas == 0) {
textout(screen, font,
"Ganaste!", 100, 90, palette_color[14]);
terminado = TRUE;
}
}
/* Si choco con la pared, se acabo */
if (mapa[posY][posX] == 'X') {
textout(screen, font,
"Chocaste!", 100, 90, palette_color[13]);
terminado = TRUE;
}
if (terminado) break;
/* Compruebo si se ha pulsado alguna tecla */
if ( keypressed() ) {
tecla = readkey() >> 8;
switch (tecla) {
case TEC_ARRIBA:
incX = 0; incY = -1; break;
case TEC_ABAJO:
incX = 0; incY = 1; break;
case TEC_IZQDA:
incX = -1; incY = 0; break;
case TEC_DCHA:
incX = 1; incY = 0; break;
}
}
posX += incX;
posY += incY;
/* Pequeña pausa antes de seguir */
rest ( PAUSA );
}
while (TRUE); /* Repetimos indefininamente */
/* (la condición de salida la comprobamos "dentro") */
readkey();
return 0;
}
/* Termino con la "macro" que me pide Allegro */
END_OF_MAIN();
|
8.3.
Miniserpiente 2 en Pascal.
Similar, pero con la rutina de dibujar sprites desarrollada, y con la
misma apariencia:
(*----------------------------*)
(* Intro a la programac de *)
(* juegos, por Nacho Cabanes *)
(* *)
(* IPJ08P.PAS *)
(* *)
(* Octavo ejemplo: juego de *)
(* 'miniSerpiente'2 *)
(* *)
(* Comprobado con: *)
(* - FreePascal 1.06 (Dos) *)
(* - FreePascal 2.0 -Windows *)
(*----------------------------*)
uses graph, crt;
(* Cambiar por "uses wincrt, ..." bajo Windows *)
(* Posiciones X e Y iniciales *)
const
POS_X_INI = 17;
POS_Y_INI = 11;
INC_X_INI = 1;
INC_Y_INI = 0;
(* Pausa en milisegundos entre un 'fotograma' y otro *)
PAUSA = 350;
(* Teclas predefinidas *)
TEC_ARRIBA = 'E';
TEC_ABAJO = 'X';
TEC_IZQDA = 'S';
TEC_DCHA = 'D';
var
posX, posY: word; (* Posicion actual *)
incX, incY: integer; (* Incremento de la posicion *)
(* Terminado: Si ha chocado o comida todas las frutas *)
terminado: boolean;
(* La tecla pulsada *)
tecla: char;
(* Escala: relacion entre tama¤o de mapa y de pantalla *)
const
ESCALA = 10;
(* Ancho y alto de los sprites *)
ANCHOSPRITE = 10;
ALTOSPRITE = 10;
(* Y el mapa que representa a la pantalla *)
(* Como usaremos modo grafico de 320x200 puntos *)
(* y una escala de 10, el tablero medira 32x20 *)
MAXFILAS = 20;
MAXCOLS = 32;
mapa: array[1..MAXFILAS, 1..MAXCOLS] of char = (
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
'X X X',
'X F X X',
'X F X F X',
'X XXXXX X X',
'X X X X',
'X X X X X',
'X X X X XXXX',
'X X X X',
'X X X X',
'X X X X',
'X F X X',
'X X X',
'X X F X',
'X X X X',
'X X X X',
'X X F X X',
'X F X X X',
'X X F X',
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
);
const numFrutas:word = 8;
(* Nuestros sprites *)
type
tipoSprite = array[1..ANCHOSPRITE,1..ALTOSPRITE] of byte;
(* El sprite en si: matriz de 10x10 bytes *)
const spriteLadrillo: tipoSprite =
((0,2,2,2,2,2,2,2,2,0),
(2,1,1,1,1,1,1,1,1,2),
(2,1,1,1,1,1,1,1,1,2),
(2,1,1,1,1,1,1,1,1,2),
(2,1,1,1,1,1,1,1,1,2),
(2,1,1,1,1,1,1,1,1,2),
(2,1,1,1,1,1,1,1,3,2),
(2,1,1,1,1,1,1,3,3,2),
(2,1,1,1,1,1,3,3,2,2),
(2,2,2,2,2,2,2,2,2,0)
);
const spriteComida: tipoSprite =
((0,0,0,2,0,0,0,0,0,0),
(0,0,2,2,0,0,2,2,0,0),
(0,4,4,4,2,2,4,4,0,0),
(4,4,4,4,4,2,4,4,4,0),
(4,4,4,4,4,4,4,4,4,0),
(4,4,4,4,4,4,4,4,4,0),
(4,4,4,4,4,4,4,4,4,0),
(4,4,4,4,4,4,4,4,4,0),
(4,4,4,4,4,4,4,4,4,0),
(0,4,4,4,4,4,4,4,0,0)
);
const spriteJugador: tipoSprite =
((0,0,3,3,3,3,3,0,0,0),
(0,3,1,1,1,1,1,3,0,0),
(3,1,1,1,1,1,1,1,3,0),
(3,1,1,1,1,1,1,1,3,0),
(3,1,1,1,1,1,1,1,3,0),
(3,1,1,1,1,1,1,1,3,0),
(3,1,1,1,1,1,1,1,3,0),
(3,1,1,1,1,1,1,1,3,0),
(0,3,1,1,1,1,1,3,0,0),
(0,0,3,3,3,3,3,0,0,0)
);
(* -------------- Rutina de dibujar sprites -------------- *)
(* Simplemente dibuja un sprite definido anteriormente. *)
(* Copia la sintaxis de "draw_sprite" de Allegro, pero es *)
(* una rutina lenta, que solo usa Pascal puro, no seria *)
(* adecuada en programas con muchos sprites *)
procedure draw_sprite(imagen: tipoSprite; x, y: word);
var
i,j: word;
begin
for i := 1 to ANCHOSPRITE do
for j := 1 to ALTOSPRITE do
begin
if imagen[j,i] <> 0 then
putpixel(x+i-1, y+j-1, imagen[j,i]);
end;
end;
(* -------------- Rutina de dibujar el fondo ------------- *)
procedure dibujaFondo;
var
i, j: word;
begin
clearDevice;
for i:= 1 to MAXCOLS do
for j := 1 to MAXFILAS do
begin
if mapa[j,i] = 'X' then
draw_sprite(spriteLadrillo, (i-1)*ESCALA, (j-1)*ESCALA);
if mapa[j,i] = 'F' then
draw_sprite(spriteComida, (i-1)*ESCALA, (j-1)*ESCALA);
end;
end;
(* ------------------------------------------------ *)
(* *)
(* -------------- Cuerpo del programa ------------- *)
var
gd,gm, error : integer;
BEGIN
gd := D8bit;
gm := m320x200;
initgraph(gd, gm, '');
(* Si falla bajo Windows, probar gd:=0; gm:=0; *)
(* Intentamos entrar a modo grafico *)
error := graphResult;
if error <> grOk then
begin
writeLn('No se pudo entrar a modo grafico');
writeLn('Error encontrado: '+ graphErrorMsg(error) );
halt(1);
end;
(* ----------------------- Si todo ha ido bien: empezamos *)
dibujaFondo;
(* Valores iniciales *)
posX := POS_X_INI;
posY := POS_Y_INI;
incX := INC_X_INI;
incY := INC_Y_INI;
(* Parte repetitiva: *)
repeat
dibujaFondo;
draw_sprite (spriteJugador, (posX-1)*ESCALA, (posY-1)*ESCALA);
terminado := FALSE;
(* Si paso por una fruta: la borro y falta una menos *)
if (mapa[posY,posX] = 'F') then
begin
mapa[posY,posX] := ' ';
numFrutas := numFrutas - 1;
if (numFrutas = 0) then
begin
setColor(14);
outTextXY( 100, 90, 'Ganaste!' );
terminado := TRUE;
end;
end;
(* Si choco con la pared, se acabo *)
if (mapa[posY,posX] = 'X') then
begin
setColor(13);
outTextXY( 100, 90, 'Chocaste!' );
terminado := TRUE;
end;
if terminado then break;
(* Compruebo si se ha pulsado alguna tecla *)
if keypressed then
begin
tecla := upcase(readkey);
case tecla of
TEC_ARRIBA:
begin incX := 0; incY := -1; end;
TEC_ABAJO:
begin incX := 0; incY := 1; end;
TEC_IZQDA:
begin incX := -1; incY := 0; end;
TEC_DCHA:
begin incX := 1; incY := 0; end;
end;
end;
posX := posX + incX;
posY := posY + incY;
(* Peque¤a pausa antes de seguir *)
delay ( PAUSA );
until FALSE; (* Repetimos indefininamente *)
(* (la condici¢n de salida la comprobamos 'dentro') *)
readkey;
closegraph;
end.
|
8.4.
Miniserpiente 2 en Java.
Al igual que en las versiones en
C y Pascal, los únicos cambios en Java se refieren a que en
pantalla dibujaremos un Sprite en vezde una letra y a que debemos crear
esos Sprites.
De hecho, en Java tenemos
incluso un componente llamado Image (imagen), que es el
equivalente directo de nuestro Sprite. La única
complicación es que resulta muy fácil crear un Image a
partir de un fichero de imagen, pero es bastante más
difícil crearlo a partir de un "array", como hemos hecho en el
caso de C y Pascal. Aun así, veamos los pasos:
Crearemos un "array" que
contenga la información de los colores de cada punto:
int spriteLadrillo[] =
{0,2,2,2,2,2,2,2,2,0,
2,1,1,1,1,1,1,1,1,2,
2,1,1,1,1,1,1,1,1,2,
2,1,1,1,1,1,1,1,1,2,
2,1,1,1,1,1,1,1,1,2,
2,1,1,1,1,1,1,1,3,2,
2,1,1,1,1,1,1,3,3,2,
2,1,1,1,1,1,3,3,2,2,
2,2,2,2,2,2,2,2,2,0
};
Pero en Java no existe "paleta
de colores Pc estándar" ;-), así que tendremos que
convertir esos colores antes de pasarlos al objeto Image. Por ejemplo,
el color 1 querremos que sea azul, así que tendremos que darle
el nuevo valor (255 << 24) | 255 (son 4 bytes, el primero es el
canal Alpha, que deberá ser 255 para que nuestra figura sea
totalmente opaca; los tres siguientes son RGB (rojo, verde y azul, en
ese orden), en nuestro caso 0, 0,255. De igual modo, el color 2, que
será el verde, debería ser (255 << 24) | (255
<< 8), el color 4, rojo, sería (255 << 24) | (255
<< 16), y el color 3, un azul claro (cyan) podría ser algo
como (255 << 24) | (127 << 16) | (127 << 8) |
255.
Por tanto, para "corregir" los
colores de cada punto haríamos algo como:
for(i=0;
i<ANCHOSPRITE; i++)
for (j=0; j<ALTOSPRITE; j++)
{
// El color 1 sera azul
if
(spriteLadrillo[i+j*ANCHOSPRITE]==1)
spriteLadrillo[i+j*ANCHOSPRITE] = (255 << 24) | 255;
// El color 2 sera verde
if
(spriteLadrillo[i+j*ANCHOSPRITE]==2)
spriteLadrillo[i+j*ANCHOSPRITE] = (255 << 24) | (255 << 8);
// El color 3 sera cyan
if
(spriteLadrillo[i+j*ANCHOSPRITE]==3)
spriteLadrillo[i+j*ANCHOSPRITE] = (255 << 24) | (127 << 16)
| (127 << 8) | 255;
// El color 4 sera rojo
if
(spriteLadrillo[i+j*ANCHOSPRITE]==4)
spriteLadrillo[i+j*ANCHOSPRITE] = (255 << 24) | (255 << 16);
Y ya sólo nos queda pasar
toda esa información al componente "Image", que se hace usando
un "MemoryImageSource", al que le indicamos el ancho y el alto y desde
dónde queremos leer los datos:
ladrilloFondo =
createImage(new MemoryImageSource(ANCHOSPRITE, ALTOSPRITE,
spriteLadrillo, 0, ANCHOSPRITE));
Para dibujar sí que no
hay complicación
if (mapa[j].charAt(i)
== 'X')
g.drawImage(ladrilloFondo,
i*ESCALA, j*ESCALA, this);
La apariencia sería esta

Y el fuente podría ser:
/*----------------------------*/ /* Intro a la programac de */ /* juegos, por Nacho Cabanes */ /* */ /* ipj08j.java */ /* */ /* Octavo ejemplo: juego de */
/* "miniSerpiente" (aprox B) */
/* */
/* Comprobado con: */ /* - JDK 1.5.0 */ /*----------------------------*/
import java.applet.Applet;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
public class ipj08j extends Applet implements Runnable, KeyListener {
// Posiciones X e Y iniciales
final int POS_X_INI = 16;
final int POS_Y_INI = 10;
final int INC_X_INI = 1;
final int INC_Y_INI = 0;
// Pausa en milisegundos entre un "fotograma" y otro
final int PAUSA = 350;
// Ahora las imagenes de cada elemento
Image ladrilloFondo;
Image comida;
Image jugador;
// Escala: relacion entre tamaño de mapa y de pantalla
final int ESCALA = 10;
// Y el mapa que representa a la pantalla
// Como usaremos modo grafico de 320x200 puntos
// y una escala de 10, el tablero medira 32x20
final int MAXFILAS = 20;
final int MAXCOLS = 32;
String mapa[]={
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"X X X",
"X F X X",
"X F X F X",
"X XXXXX X X",
"X X X X",
"X X X X X",
"X X X X XXXX",
"X X X X",
"X X X X",
"X X X X",
"X F X X",
"X X X",
"X X F X",
"X X X X",
"X X X X",
"X X F X X",
"X F X X X",
"X X F X",
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
};
/* Ancho y alto de los sprites */
final int ANCHOSPRITE = 10;
final int ALTOSPRITE = 9;
int spriteLadrillo[] =
{0,2,2,2,2,2,2,2,2,0,
2,1,1,1,1,1,1,1,1,2,
2,1,1,1,1,1,1,1,1,2,
2,1,1,1,1,1,1,1,1,2,
2,1,1,1,1,1,1,1,1,2,
2,1,1,1,1,1,1,1,3,2,
2,1,1,1,1,1,1,3,3,2,
2,1,1,1,1,1,3,3,2,2,
2,2,2,2,2,2,2,2,2,0
};
int spriteComida []=
{0,0,0,2,0,0,0,0,0,0,
0,0,2,2,0,0,2,2,0,0,
0,4,4,4,2,2,4,4,0,0,
4,4,4,4,4,2,4,4,4,0,
4,4,4,4,4,4,4,4,4,0,
4,4,4,4,4,4,4,4,4,0,
4,4,4,4,4,4,4,4,4,0,
4,4,4,4,4,4,4,4,4,0,
0,4,4,4,4,4,4,4,0,0
};
int spriteJugador []=
{0,0,3,3,3,3,3,0,0,0,
0,3,1,1,1,1,1,3,0,0,
3,1,1,1,1,1,1,1,3,0,
3,1,1,1,1,1,1,1,3,0,
3,1,1,1,1,1,1,1,3,0,
3,1,1,1,1,1,1,1,3,0,
3,1,1,1,1,1,1,1,3,0,
0,3,1,1,1,1,1,3,0,0,
0,0,3,3,3,3,3,0,0,0
};
Thread hilo = null; // El "hilo" de la animacion
int posX, posY; // Posicion actual
int incX, incY; // Incremento de la posicion
// Terminado: Si ha chocado o comido todas las frutas
boolean terminado;
int tecla; // La tecla pulsada
// Y las teclas por defecto
final char TEC_ARRIBA = 'e';
final char TEC_ABAJO = 'x';
final char TEC_IZQDA = 's';
final char TEC_DCHA = 'd';
int numFrutas = 8;
// Rutina de crear los sprites
void creaSprites()
{
int i, j;
// Doy colores más adecuados a cada figura: ladrillos
for(i=0; i<ANCHOSPRITE; i++)
for (j=0; j<ALTOSPRITE; j++)
{
// El color 1 sera azul
if (spriteLadrillo[i+j*ANCHOSPRITE]==1) spriteLadrillo[i+j*ANCHOSPRITE] = (255 << 24) | 255;
// El color 2 sera verde
if (spriteLadrillo[i+j*ANCHOSPRITE]==2) spriteLadrillo[i+j*ANCHOSPRITE] = (255 << 24) | (255 << 8);
// El color 3 sera cyan
if (spriteLadrillo[i+j*ANCHOSPRITE]==3) spriteLadrillo[i+j*ANCHOSPRITE] = (255 << 24) | (127 << 16) | (127 << 8) | 255;
// El color 4 sera rojo
if (spriteLadrillo[i+j*ANCHOSPRITE]==4) spriteLadrillo[i+j*ANCHOSPRITE] = (255 << 24) | (255 << 16);
}
// y al final los asigno
ladrilloFondo = createImage(new MemoryImageSource(ANCHOSPRITE, ALTOSPRITE,
spriteLadrillo, 0, ANCHOSPRITE));
// Lo mismo para la comida
for(i=0; i<ANCHOSPRITE; i++)
for (j=0; j<ALTOSPRITE; j++)
{
// El color 1 sera azul
if (spriteComida[i+j*ANCHOSPRITE]==1) spriteComida[i+j*ANCHOSPRITE] = (255 << 24) | 255;
// El color 2 sera verde
if (spriteComida[i+j*ANCHOSPRITE]==2) spriteComida[i+j*ANCHOSPRITE] = (255 << 24) | (255 << 8);
// El color 3 sera cyan
if (spriteComida[i+j*ANCHOSPRITE]==3) spriteComida[i+j*ANCHOSPRITE] = (255 << 24) | (127 << 16) | (127 << 8) | 255;
// El color 4 sera rojo
if (spriteComida[i+j*ANCHOSPRITE]==4) spriteComida[i+j*ANCHOSPRITE] = (255 << 24) | (255 << 16);
}
comida = createImage(new MemoryImageSource(ANCHOSPRITE, ALTOSPRITE,
spriteComida, 0, ANCHOSPRITE));
// Y lo mismo para el jugador
for(i=0; i<ANCHOSPRITE; i++)
for (j=0; j<ALTOSPRITE; j++)
{
// El color 1 sera azul
if (spriteJugador[i+j*ANCHOSPRITE]==1) spriteJugador[i+j*ANCHOSPRITE] = (255 << 24) | 255;
// El color 2 sera verde
if (spriteJugador[i+j*ANCHOSPRITE]==2) spriteJugador[i+j*ANCHOSPRITE] = (255 << 24) | (255 << 8);
// El color 3 sera cyan
if (spriteJugador[i+j*ANCHOSPRITE]==3) spriteJugador[i+j*ANCHOSPRITE] = (255 << 24) | (127 << 16) | (127 << 8) | 255;
// El color 4 sera rojo
if (spriteJugador[i+j*ANCHOSPRITE]==4) spriteJugador[i+j*ANCHOSPRITE] = (255 << 24) | (255 << 16);
} jugador = createImage(new MemoryImageSource(ANCHOSPRITE, ALTOSPRITE,
spriteJugador, 0, ANCHOSPRITE));
}
// Inicializacion
public void init() {
// Valores iniciales
posX = POS_X_INI;
posY = POS_Y_INI;
incX = INC_X_INI;
incY = INC_Y_INI;
terminado = false;
requestFocus();
addKeyListener(this);
creaSprites();
}
// Escritura en pantalla
public void paint(Graphics g) {
int i, j; // Primero borro el fondo en negro
g.setColor( Color.black );
g.fillRect( 0, 0, 639, 479 );
// Ahora dibujo paredes y comida
for(i=0; i<MAXCOLS; i++)
for (j=0; j<MAXFILAS; j++) {
if (mapa[j].charAt(i) == 'X')
g.drawImage(ladrilloFondo, i*ESCALA, j*ESCALA, this);
if (mapa[j].charAt(i) == 'F')
g.drawImage(comida, i*ESCALA, j*ESCALA, this);
}
// Finalmente, el jugador
g.drawImage(jugador, posX*ESCALA, posY*ESCALA, this);
// Si no quedan frutas, se acabo
g.setColor( Color.yellow );
if (numFrutas == 0) {
g.drawString("Ganaste!", 100, 90);
terminado = true;
} // Si choco con la pared, se acabo
g.setColor( Color.magenta );
if (mapa[posY].charAt(posX) == 'X') {
g.drawString("Chocaste!", 100, 90);
terminado = true;
}
if (terminado) hilo=null; }
// La rutina que comienza el "Thread"
public void start() {
hilo = new Thread(this);
hilo.start();
} // La rutina que para el "Thread"
public synchronized void stop() {
hilo = null;
} // Y lo que hay que hacer cada cierto tiempo
public void run() {
Thread yo = Thread.currentThread();
while (hilo == yo) {
try {
Thread.sleep(PAUSA);
} catch (InterruptedException e){
}
posX += incX;
posY += incY;
// Si paso por una fruta: la borro y falta una menos
if (mapa[posY].charAt(posX) == 'F') {
// La borro en el mapa
StringBuffer temp = new StringBuffer(mapa[posY]);
temp.setCharAt(posX, ' ');
mapa[posY] = temp.toString();
// y en el contador
numFrutas --;
}
// En cualquier caso, redibujo
repaint();
} }
// Comprobacion de teclado
public void keyTyped(KeyEvent e) {
tecla=e.getKeyChar();
switch (tecla) {
case TEC_ARRIBA:
incX = 0; incY = -1; break;
case TEC_ABAJO:
incX = 0; incY = 1; break;
case TEC_IZQDA:
incX = -1; incY = 0; break;
case TEC_DCHA:
incX = 1; incY = 0; break;
}
repaint();
e.consume();
}
public void keyReleased(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
}
}
|
 
|