20. Incluyendo un disparo y comprobación de colisiones. Octavo juego (aproximación "d"): Marciano 4. (*)
La idea de esta cuarta aproximación es:
- Incluiremos también la posibilidad de disparar, el movimiento vertical del disparo y la detección de colisiones entre el disparo y el enemigo. El disparo "desaparecerá" cuando golpee al enemigo o llegue a la parte superior de la pantalla, y sólo entonces se podrá volver a disparar.
Sin grandes novedades. Un tercer "personaje" a controlar, el disparo, que no añade casi ninguna complicación, salvo por el hecho de que no siempre está "activo" (puede haber momentos en los que no estemos disparando). La novedad es cómo comprobar si el disparo ha impactado en la nave enemiga. Una forma muy sencilla de conseguirlo puede ser simplemente comparar la posición del disparo y la del marciano. Como también sabemos el "tamaño" del marciano (su anchura y su altura), podemos saber si el disparo ha acertado (si su coordenada X está entre XMarciano y XMarciano+AnchoMarciano, y lo mismo para la coordenada Y).
Es muy similar a la aproximación anterior, aunque ligeramente más largo:
/*----------------------------*/ /* Intro a la programac de */ /* juegos, por Nacho Cabanes */ /* */ /* ipj20c.c */ /* */ /* Ejemplo: */ /* Un marciano y una nave */ /* movindose de forma */ /* independiente; la nave */ /* puede disparar y */ /* "matar" al marciano */ /* */ /* Comprobado con: */ /* - Djgpp 2.03 (gcc 3.2) */ /* y Allegro 4.02 - MsDos */ /*----------------------------*/ /* ------------------- Planteamiento de esta aproximacin: repetir si hayQueRedibujarMarciano dibujar marciano hayQueRedibujarMarciano = FALSO si hayQueRedibujarNave dibujar nave hayQueRedibujarNave = FALSO si (hayQueRedibujarDisparo) y (disparoActivo) dibujar disparo hayQueRedibujarDisparo = FALSO si tiempoTranscurridoNave = tiempoHastaMoverNave comprobar si se ha pulsado alguna tecla calcular nueva posicin de nave hayQueRedibujarNave = VERDADERO si teclaPulsada = teclaDisparo disparoActivo = VERDADERO si tiempoTranscurridoMarciano = tiempoHastaMoverMarciano calcular nueva posicin de marciano hayQueRedibujarMarciano = VERDADERO si (tiempoTranscurridoDisparo = tiempoHastaMoverDisparo) y (disparoActivo) calcular nueva posicin de disparo hayQueRedibujarDisparo = VERDADERO si disparoFueraDeLaPantalla disparoActivo = FALSO si colisionDisparoYMarciano finDeLaPartida hasta que se pulse ESC --------------- Planteamiento de la inicial: cargar imagen 1 y 2 del marciano entrar a modo grfico dibujar marciano en punto inicial repetir aumentar posicion horizontal si se acerca a margen lateral de la pantalla cambiar sentido horizontal de avance bajar una lnea en vertical si se acerca a parte inferior de la pantalla mover a parte superior aumentar contador de "fotogramas" si contador de fotogramas = numFotogramasPorImagen cambiar apariencia de marciano contador de fotogramas = 0 redibujar pantalla pausa hasta que se pulse ESC ------------------- */ #include <allegro.h> /* -------------- Constantes globales ------------- */ #define ANCHOPANTALLA 320 #define ALTOPANTALLA 200 // Los dos siguientes valores son los retardos // hasta mover la nave y el marciano, pero ambos // en centsimas de segundo #define RETARDOCN 10 #define RETARDOCM 25 // Y tambin el del disparo #define RETARDOCD 15 #define MARGENSUP 40 #define MARGENDCHO 30 #define MARGENIZQDO 30 #define MARGENINF 50 #define INCREMX 5 #define INCREMY 15 /* -------------- Variables globales -------------- */ PALETTE pal; BITMAP *imagen; BITMAP *nave; BITMAP *marciano1; BITMAP *marciano2; BITMAP *disparo; int fotograma = 1; int xMarciano = MARGENIZQDO; int yMarciano = MARGENSUP; int xNave = ANCHOPANTALLA / 2; int yNave = ALTOPANTALLA-16-MARGENINF; int xDisparo = 0; int yDisparo = 0; int desplMarciano = INCREMX; int desplNave = INCREMX; int puedeMoverMarciano = 1; int puedeMoverNave = 1; int puedeMoverDisparo = 0; int disparoActivo = 0; int tecla; int salir = 0; /* -------------- Rutinas de temporizacin -------- */ // Contadores para temporizacin volatile int contadorN = 0; volatile int contadorM = 0; volatile int contadorD = 0; // La rutina que lo aumenta cada cierto tiempo void aumentaContadores(void) { contadorN++; contadorM++; contadorD++; } END_OF_FUNCTION(aumentaContadores); /* -------------- Rutina de inicializacin -------- */ int inicializa() { allegro_init(); // Inicializamos Allegro install_keyboard(); install_timer(); // Intentamos entrar a modo grafico if (set_gfx_mode(GFX_SAFE, ANCHOPANTALLA, ALTOPANTALLA, 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; } // e intentamos abrir imgenes imagen = load_pcx("spr_inv.pcx", pal); if (!imagen) { set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); allegro_message("No se ha podido abrir la imagen\n"); return 1; } set_palette(pal); // Ahora reservo espacio para los otros sprites nave = create_bitmap(16, 16); marciano1 = create_bitmap(16, 16); marciano2 = create_bitmap(16, 16); disparo = create_bitmap(8, 8); // Y los extraigo de la imagen "grande" blit(imagen, nave // bitmaps de origen y destino , 32, 32 // coordenadas de origen , 0, 0 // posicin de destino , 16, 16); // anchura y altura blit(imagen, marciano1, 0, 32, 0, 0, 16, 16); blit(imagen, marciano2, 16, 32, 0, 0, 16, 16); blit(imagen, disparo, 72, 32, 0, 0, 8, 8); // Rutinas de temporizacin // Bloqueamos las variables y la funcin del temporizador LOCK_VARIABLE( contadorN ); LOCK_VARIABLE( contadorM ); LOCK_FUNCTION( aumentaContadores ); // Y ponemos el temporizador en marcha: cada 10 milisegundos // (cada centsima de segundo) install_int(aumentaContadores, 10); // Y termino indicando que no ha habido errores return 0; } /* -------------- Rutina de mover marciano -------- */ int mueveMarciano() { // Calculo nueva posicin xMarciano += desplMarciano; // Compruebo si debe bajar if ((xMarciano > ANCHOPANTALLA-16-MARGENDCHO) || (xMarciano < MARGENIZQDO)) { desplMarciano = -desplMarciano; // Direccin contraria yMarciano += INCREMY; // Y bajo una lnea } // O si debe volver arriba if (yMarciano > ALTOPANTALLA-16-MARGENINF) { xMarciano = MARGENIZQDO; yMarciano = MARGENSUP; desplMarciano = INCREMX; } } /* -------------- Rutina de mover disparo -------- */ int mueveDisparo() { // Calculo nueva posicion yDisparo -= 4; // Compruebo si ha chocado if ((xDisparo >= xMarciano) && (xDisparo <= xMarciano + 8) && (yDisparo >= yMarciano) && (yDisparo <= yMarciano + 8)) { textprintf(screen, font, xDisparo, yDisparo, palette_color[11], "Boom!"); readkey(); salir = 1; // Y se acab } // O si ha llegado arriba if (yDisparo < MARGENSUP-8) { xDisparo = 0; yDisparo = 0; puedeMoverDisparo = 0; disparoActivo = 0; } } /* ------------------------------------------------ */ /* */ /* -------------- Cuerpo del programa ------------- */ int main() { // Intento inicializar if (inicializa() != 0) exit(1); do { // Parte que se repite hasta pulsar tecla // Slo se pueden mover tras un cierto tiempo if (contadorM >= RETARDOCM) { puedeMoverMarciano = 1; contadorM = 0; } if (contadorN >= RETARDOCN) { puedeMoverNave = 1; contadorN = 0; } if ((contadorD >= RETARDOCD) && (disparoActivo)) { puedeMoverDisparo = 1; contadorD = 0; } if (puedeMoverMarciano || puedeMoverNave || puedeMoverDisparo) { // Compruebo teclas pulsadas para salir // o mover la nave if (keypressed()) { tecla = readkey() >> 8; if ( tecla == KEY_ESC) salir = 1; if (puedeMoverNave) { if (( tecla == KEY_RIGHT) && (xNave < ANCHOPANTALLA-16-MARGENDCHO)) { xNave += INCREMX; puedeMoverNave = 0; } if (( tecla == KEY_LEFT) && (xNave > MARGENIZQDO+16)) { xNave -= INCREMX; puedeMoverNave = 0; } if (( tecla == KEY_SPACE) && (!disparoActivo)) { disparoActivo = 1; puedeMoverDisparo = 1; contadorD = 0; xDisparo = xNave; yDisparo = yNave-2; } clear_keybuf(); } } // Sincronizo con el barrido para evitar // parpadeos, borro la pantalla y dibujo la nave vsync(); clear_bitmap(screen); draw_sprite(screen, nave, xNave, yNave); // Dibujo un marciano u otro, alternando if (fotograma==1) { draw_sprite(screen, marciano1, xMarciano, yMarciano); if (puedeMoverMarciano) fotograma = 2; } else { draw_sprite(screen, marciano2, xMarciano, yMarciano); if (puedeMoverMarciano) fotograma = 1; } // Y calculo su nueva posicin si corresponde if (puedeMoverMarciano) { mueveMarciano(); puedeMoverMarciano = 0; } // Y anlogo para el disparo if (puedeMoverDisparo) { mueveDisparo(); puedeMoverDisparo = 0; } if (disparoActivo) draw_sprite(screen, disparo, xDisparo, yDisparo); } } while (!salir); textprintf(screen, font, 1, 1, palette_color[11], "Partida terminada."); destroy_bitmap(imagen); readkey(); return 0; } /* Termino con la "macro" que me pide Allegro */ END_OF_MAIN();
Ahora incluyamos varios marcianos...