04 julio 2008

Programar videojuegos con la librería SDL (y 11)

Hoy voy a terminar la sección dedicada a la programación con SDL en Delphi hablando de la creación de enemigos en un juego de plataformas.

CREANDO LOS ENEMIGOS

Para crear los sprites enemigos voy a utilizar este gráfico:


Como en el juego voy a insertar 6 enemigos, no es necesario cargar 6 sprites con los mismos gráficos. Al igual que hicimos en el juego de aviones, con un solo sprite enemigo podemos dibujar el resto.

Para ello voy a crear una nueva estructura de datos para guardar la posición de cada enemigo y su estado:

TEnemigo = record
x, y, iSubX, iSubY: Integer;
iPosicion: Integer;
bActivo, bIzquierda: Boolean;
end;

Este registro va a guardar las coordenadas de un enemigo, los subsprites que va a dibujar en ese momento, la posición al andar, si está activo y si anda hacia la izquierda o hacia la derecha.

Al igual que hicimos con los aviones vamos a añadir un array global en la unidad UPlataforma.pas para controlar a varios enemigos:

var
Fondo, Temporal, Piezas, Heroe, Enemigo: TSprite;
Enemigos: array[1..5] of TEnemigo;
...

También vamos a ampliar nuestro procedimiento cargar sprites para cargar los enemigos:

procedure CargarSprites;
begin
...
Enemigo := TSprite.Create;
Enemigo.CargarSuperficie( ExtractFilePath( ParamStr( 0 ) ) + 'enemigo.png' );
Enemigo.bSubsprites := True;
Enemigo.iAnchoSub := 40;
Enemigo.iAltoSub := 40;

CargarPantalla( 'pantalla1.txt' );
DibujarPiezasEnTemporal;
end;

Y por supuesto no nos olvidamos de liberarlo de memoria:

procedure DestruirSprites;
begin
Enemigo.Free;
Heroe.Free;
Piezas.Free;
Temporal.Free;
Fondo.Free;
end;

SITUANDO LOS ENEMIGOS EN PANTALLA

Una vez ya tenemos nuestro sprite enemigo creado vamos a crear un procedimiento encargado de colocar los enemigos en pantalla:

procedure SituarEnemigos;
var
i: Integer;
begin
Enemigos[1].x := 40;
Enemigos[1].y := 320;
Enemigos[2].x := 400;
Enemigos[2].y := 320;
Enemigos[3].x := 440;
Enemigos[3].y := 200;
Enemigos[3].bIzquierda := True;
Enemigos[4].x := 160;
Enemigos[4].y := 200;
Enemigos[4].bIzquierda := True;
Enemigos[5].x := 200;
Enemigos[5].y := 80;
Enemigos[6].x := 440;
Enemigos[6].y := 80;

for i := 1 to 6 do
Enemigos[i].bActivo := True;
end;

A este procedimiento lo podemos llamar al final del procedimiento CargarSprites:

procedure CargarSprites;
begin
...
CargarPantalla( 'pantalla1.txt' );
DibujarPiezasEnTemporal;
SituarEnemigos;
end;

Lo más difícil es lo que viene ahora. Tenemos que mover todos los enemigos a la vez:

procedure MoverEnemigos;
var
i, xMapa, yMapa: Integer;
begin
for i := 1 to 6 do
begin
yMapa := ( Enemigos[i].y + 40 ) div 40 + 1;

if Enemigos[i].bActivo then
begin
if Enemigos[i].bIzquierda then
begin
Enemigos[i].iSubY := 1;
Dec( Enemigos[i].x );
xMapa := ( Enemigos[i].x - 1 ) div 40 + 1;
if ( Mapa[xMapa,yMapa] = '0' ) or ( Mapa[xMapa,yMapa] = '1' ) then
Enemigos[i].bIzquierda := False;
end
else
begin
Enemigos[i].iSubY := 0;
Inc( Enemigos[i].x );
xMapa := ( Enemigos[i].x + 40 ) div 40 + 1;
if ( Mapa[xMapa,yMapa] = '0' ) or ( Mapa[xMapa,yMapa] = '1' ) then
Enemigos[i].bIzquierda := True;
end;

// cambiamos de fotograma
Inc( Enemigos[i].iPosicion );

if Enemigos[i].iPosicion > 4 then
begin
if Enemigos[i].iSubX = 0 then
Enemigos[i].iSubX := 1
else
Enemigos[i].iSubX := 0;

Enemigos[i].iPosicion := 0;
end;
end;
end;
end;

Este procedimiento recorre todos los enemigos y los mueve a la derecha o hacia la izquierda hasta que choquen con un obstáculo. Cuando choca cambia de dirección hasta que vuelva a chocar. También nos encargamos de cambiar de fotograma para que se produzca la animación al andar.

Ahora sólo tenemos que modificar el procedimiento DibujarSprites para que dibuje a los enemigos y los mueva:

procedure DibujarSprites;
var
i: Integer;
begin
Temporal.Dibujar;
Heroe.Dibujar;

for i := 1 to 6 do
if Enemigos[i].bActivo then
begin
Enemigo.x := Enemigos[i].x;
Enemigo.y := Enemigos[i].y;
Enemigo.iSubX := Enemigos[i].iSubX;
Enemigo.iSubY := Enemigos[i].iSubY;
Enemigo.Dibujar;
end;

MoverEnemigos;
end;

Este sería el resultado:


COMPROBANDO LAS COLISIONES ENTRE SPRITES

Por último vamos a hacer que si el sprite del héroe choca con algún enemigo tenga que volver a empezar desde el principio (incluyendo volver a recoger las joyas). Eso lo vamos a hacer con el siguiente procedimiento:

procedure ComprobarEnemigos;
var
i: Integer;
begin
for i := 1 to 6 do
begin
if Enemigos[i].bActivo then
if ( Heroe.x + 20 >= Enemigos[i].x ) and ( Heroe.x + 20 <= Enemigos[i].x + 39 ) and
( Heroe.y + 20 >= Enemigos[i].y ) and ( Heroe.y + 20 <= Enemigos[i].y + 39 ) then
begin
// volvemos a colocar el equipo y los enemigos
Heroe.rx := 40;
Heroe.ry := 400;
SituarEnemigos;
CargarPantalla( 'pantalla1.txt' );

// volvemos a redibujar la pantalla de fondo
Fondo.DibujarEn( Temporal.Superficie );
DibujarPiezasEnTemporal;
end;
end;
end;

Para comprobar si el héroe choca con el enemigo lo que hago es comprobar si el centro de las coordenadas del héroe (heroe.x + 20, heroe.y + 20 ) están dentro de la cuadrícula de 40 x 40 que forma parte el enemigo. Cuando chocan entonces vuelvo a colocar al héroe, a los enemigos y las joyas, volviendo a dibujar la pantalla de fondo.

Este procedimiento hay que llamarlo desde DibujarSprites:

procedure DibujarSprites;
begin
...
MoverEnemigos;
ComprobarEnemigos;
end;


Otras cosas que se le podían haber añadido al juego es el control de vidas de modo que cada vez que nos maten decremente una vida. También haría falta meterle sonidos y una música de fondo, pero la falta de tiempo me impide cerrar el círculo.

Aquí os dejo el proyecto en RapidShare:

https://mega.nz/file/5FhU2SyD#ZavwnR9Amwcpub4wGaTI5zLsqEOPmUxuy201rtIUaOA

EL FIN DE UNA SERIE

Con esto doy más o menos por finalizado el curso de introducción a la programación de videojuegos con la librería SDL. Podía haber hecho muchos más ejemplos (juegos de estrategia, juegos de carreras, juegos de inteligencia tipo tetris, etc.), pero la falta de tiempo me impide llevarlo a cabo. Quizás en un futuro si encuentro un buen patrocinador que haga que no vuelva a trabajar podría abarcar todos estos temas (que bueno es soñar, jejeje).

Otro tema que también dejo pendiente para un futuro es la programación de videojuegos 3D con OpenGL, donde la librería SDL también da un buen soporte, pero todavía no lo tengo muy preparado y me gustaría presentarlo bien, ya que es un tema algo complicado pero apasionante.

Aprovechando también la librería OpenGL veremos también como realizar juegos 2D utilizando polígonos, lo que hace que los juegos sean espectaculares con sprites supergigantes y con los efectos que brindan las tarjetas 3D (iluminación, realzado de texturas, rotaciones, etc.).

Cuando tenga una librería bien montada crearé otra serie de artículos dedicados a la OpenGL en Delphi. En el próximo artículo voy a comenzar hablando de las novedades de RAD Studio 2007 respecto a Delphi 7. Ya va siendo hora de guardar nuestro querido Delphi 7 en el cajón y aprovechar las nuevas ventajas del nuevo IDE de CodeGear. Con Embarcadero Technologies comienza una nueva era para Delphi. Espero que sea para mejor.

Pruebas realizadas en Delphi 7.

12 comentarios:

Anónimo dijo...

ESPECTACULAR!!! es la palabra que define esta serie de Tutoriales para aprender a programar juegos en delphi. Hace poco descubri delphi y me parece una herramienta excelente, ahora mismo me puse a leer la serie de tutoriales de programacion grafica y es excelente, e incentivo al autor a que nos siga enseñando de una forma muy clara como esta primera parte. a partir de ahora me voy a poner a leer cada tutorial de esta página ya que todas las categorias me parecen interesante. Espero que puedas seguir adelante y muchas gracias por compartir tu conocimiento.

Un saludo!

Alexis Jeansalle

Administrador dijo...

Me alegro de que te guste el tutorial.

Quizás en un futuro entre en más profundad con juegos con OpenGL y DirectX.

Saludos.

Anónimo dijo...

Holas! Hace unos días necesitaba saber alguna forma de recorres directorios en windows, y encontré tu sitio, el cual me fue de super utilidad.

Y hoy, buscando de nuevo algún otro tip, me he encontrado con esta maravilla que has publicado: programar juegos en delphi O_O!!!

Te alabo sinceramente y te agradezco sobremanera tu generosidad ^_^!!

Lo que pasa es que a principios de año quise hacer un jueguito tipo tetris usando delphi, pero no supe cómo y lo di por perdido, hasta ahora que has publicado esto ^_^

Me has devuelto las esperanzas, por ello, muchas gracias!! ^o^

Saludos :D

Administrador dijo...

Me alegro mucho de que te hayan sido de utilidad mis artículos.

Y si quieres hacer un tetris no te rindas. Echándole valor uno siempre consigue lo que se propone.

Saludos.

Abismo Neo dijo...

oye y no sabes de algun book o algo apra hacer otro tipo de juegos komo dices, de carreras, de estrategia , de peleas, y kosas asi??? me encantaria aprenderlos a hacer

:) me hubiese gustado ke siguieras kon estos tutos, pero te entiendo con respecto a lo del trbaajo, es tan absorvente de tiempo ke no deja para mucho.

saludos y espero algun dia ver mas tutos de este tipo :D y si despues de aprender a hacer los demas, tengo idea talvez entre todos los ke visitamos este blog te podamos ayudar a hacer uno :)

saludos y seguimos estudiando, aun no termino el de los aviones, pero ahi vamos :D

Administrador dijo...

Podía poner muchos más ejemplos: estrategia, juegos tipo tetris, etc. pero me llevaría mucho tiempo prepararlos.

Lo que si tengo en mente es escribir un tutorial de SDL+OpenGL que lo tengo casi listo, pero todavía me quedan que pulir algunas cosas más.

El problema es el de siempre: el tiempo.

Abismo Neo dijo...

pues la verdad a mi me gustaria uno de carreras, deportes, estrategia, pero pues komo dices tu, seria kuestion de meterse, probar, intentar, fallar y volver a intentarlo, hasta ke kede, :)
sin embargo un poco de ayuda no estaria de mas :p

saludos y seguimos analizando y checando y probando codigo :D

Victor dijo...

La verdad tu blog es lo mas completo que he visto en amteria de video juego y muy sencillo como lo explicas. Realmente admiro tus conocimientos y la forma en que los transmitis. Gracias por tan valiosa herramienta espero que en algun momento vayas agregando mas sobre este tema que me quede fascinado. Saludo amigo

Unknown dijo...

Hola,
Me gustaria usar las sdl para crear una aplicacion. Necesito crear un boton, que tenga los eventos down, up y over.
Puedes orientarme como hacerlo?

Muchas gracias por el tutorial. Es genial!!!

Saludos

Administrador dijo...

En los videojuegos, los botones te los tienes que currar a mano, aunque yo me he hecho una sencilla clase llamada TBoton que tendría dentro un sprite (sprBoton) el cual tiene tres subsprites dentro para:

- Cuando no está pulsado.
- Cuando pasa el ratón por encima.
- Cuando haces clic.

Lo de controlar si el ratón pasa por encima o si hacemos clic seria asi:

if (Raton.x >= Boton.x) and (Raton.y >= Boton.y) and
(Raton.x <= Boton.x + Boton.Ancho) and (Raton.y <= Boton.y Boton.Alto) then
....

Aunque pueda parecer sencillo, lleva más trabajo del que parece y más cuando tu juego se ejecuta a 60 frames por segundo. Mucho ojo con no desperdiciar procesador.

Saludos.

Pitfiend dijo...

hoy me di tiempo para leer tus tutoriales para crear juegos. muy buenos, gracias por el tiempo dedicado a ellos. lastima que los archivos de ejemplo ya no esten disponibles.

Pitfiend dijo...

hoy me di tiempo para leer tus tutoriales para crear juegos. muy buenos, gracias por el tiempo dedicado a ellos. lastima que los archivos de ejemplo ya no esten disponibles.

Publicidad