19. Moviendo una nave y un enemigo a la vez con velocidades distintas. Octavo juego (aproximación "c"): Marciano 3. (*)
La idea de esta tercera aproximación es:
- Añadiremos nuestra nave, capaz de moverse de lado a lado, a velocidad distinta. Tampoco deberá poderse salir por los lados.
El hecho de que nuestra nave se mueva, y que no pueda salir de la pantalla, son cosas que ya sabemos hacer. La dificultad está en que se mueva a la vez que el marciano y a velocidad distinta de la de éste. Ahora no podremos usar "pausa" porque el programa no deberá esperar, lo que deberemos es comprobar continuamente si ha llegado el momento de mover alguno de los dos personajes.
La idea básica sería algo como:
repetir
si hayQueRedibujarMarciano
dibujar marciano
hayQueRedibujarMarciano = FALSO
si hayQueRedibujarNave
dibujar nave
hayQueRedibujarNave = FALSO
si tiempoTranscurridoNave = tiempoHastaMoverNave
comprobar si se ha pulsado alguna tecla
calcular nueva posición de nave
hayQueRedibujarNave = VERDADERO
si tiempoTranscurridoMarciano = tiempoHastaMoverMarciano
calcular nueva posición de marciano
hayQueRedibujarMarciano = VERDADERO
hasta que se pulse ESC
No debería tener problemas. Está claro que frases como "calcular nueva posición de marciano" equivalen a varias órdenes (de hecho, a casi toda la aproximación anterior) y que expresiones como "tiempoTranscurridoMarciano" serían simplemente una resta entre dos tiempos, algo así como "HoraActual - HoraUltimoMovimientoMarciano" si tenemos un reloj disponible, o algo como "contador > RetardoEsperado" si tenemos que usar un contador, como en Allegro.
Se puede hacer así (como siempre, no es la única forma posible de plantearlo, ni siquiera la mejor, pero espero que al menos sea fácil de seguir):
/*----------------------------*/ /* Intro a la programac de */ /* juegos, por Nacho Cabanes */ /* */ /* ipj19c.c */ /* */ /* Decimosexto ejemplo: */ /* Un marciano y una nave */ /* movindose de forma */ /* independiente */ /* */ /* Comprobado con: */ /* - Djgpp 2.03 (gcc 3.2) */ /* y Allegro 4.02 - MsDos */ /* - MinGW 2.0.0-3 (gcc 3.2) */ /* y Allegro 4.02 - WinXP */ /*----------------------------*/ /* ------------------- Planteamiento de esta aproximacin: repetir si hayQueRedibujarMarciano dibujar marciano hayQueRedibujarMarciano = FALSO si hayQueRedibujarNave dibujar nave hayQueRedibujarNave = FALSO si tiempoTranscurridoNave = tiempoHastaMoverNave comprobar si se ha pulsado alguna tecla calcular nueva posicin de nave hayQueRedibujarNave = VERDADERO si tiempoTranscurridoMarciano = tiempoHastaMoverMarciano calcular nueva posicin de marciano hayQueRedibujarMarciano = VERDADERO hasta que se pulse ESC --------------- Planteamiento de la anterior: 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 #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; int fotograma = 1; int xMarciano = MARGENIZQDO; int yMarciano = MARGENSUP; int xNave = ANCHOPANTALLA / 2; int yNave = ALTOPANTALLA-16-MARGENINF; int desplMarciano = INCREMX; int desplNave = INCREMX; int puedeMoverMarciano = 1; int puedeMoverNave = 1; int tecla; int salir = 0; /* -------------- Rutinas de temporizacin -------- */ // Contadores para temporizacin volatile int contadorN = 0; volatile int contadorM = 0; // La rutina que lo aumenta cada cierto tiempo void aumentaContadores(void) { contadorN++; contadorM++; } 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); // 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); // 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 inicializacin -------- */ int mueveMarciano() { // Finalmente, 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; } } /* ------------------------------------------------ */ /* */ /* -------------- 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 (puedeMoverMarciano || puedeMoverNave) { // 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; } 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; } } } while (!salir); destroy_bitmap(imagen); readkey(); return 0; } /* Termino con la "macro" que me pide Allegro */ END_OF_MAIN();
Ahora añadamos el disparo y la detección de colisiones...