viernes, 4 de septiembre de 2015

Crear juego RPG en C++ y Allegro 4 (5) Escenarios

Continuamos con el curso de crea tu juego RPG en C++ y Allegro. En esta entrega se hará que nuestro personaje pueda salir de la casa al exterior, y recorrer el bosque.



Si quieres ver alguna de las anteriores entregas entra en el Contenido del Blog

Recuerda, si tienes algún problema con los ejemplos de la pagina, o alguna duda. Puedes plantear tu pregunta en el foro de programación:

http://creatusjuegosdecero.webege.com/index.php


Para este curso necesitaremos tres imágenes del nuevo lugar, es decir, del bosque.








Uno con la imagen completa del nuevo escenario, una segunda imagen con las zonas de choque, y una tercera imagen con las cosas por las que el protagonista pasará por debajo, como son las copas de los arboles. Es importante que las tres imágenes tengan el mismo tamaño.



El mapa de choque se utilizará para indicar con el color rojo las zonas que no podemos pisar, y por tanto chocaremos, y también con otros colores indicaremos otras acciones. En el ejemplo se utilizará el color azul para detectar la puerta de la casa.





Programación

/*
   mijuego.h
   
*/

BITMAP *casa_a;
BITMAP *casa_b;
BITMAP *casa_c;
BITMAP *bosq_a;
BITMAP *bosq_b;
BITMAP *bosq_c;


BITMAP *fondo;
BITMAP *choque;
BITMAP *cielo;

player jugador;

// indicará en que lugar estamos
// 1: casa
// 2: bosque
int lugar;


// carga todo lo necesario antes de empezar el juego
void carga_juego()
{
    jugador.inicia();
    
    casa_a = load_bmp("casa.bmp",NULL);
    casa_b = load_bmp("casa-sup.bmp",NULL);     
    casa_c = load_bmp("casa-choque.bmp",NULL);

    bosq_a = load_bmp("bosque.bmp",NULL);
    bosq_b = load_bmp("bosque-sup.bmp",NULL);     
    bosq_c = load_bmp("bosque-choque.bmp",NULL);
      
    // cargamos imagenes del primer escenario
    fondo  = casa_a;
    choque = casa_c;
    cielo   = casa_b;
    
    lugar = 1;   
}


// actualiza el estado del juego
void actualiza_juego()
{
    int cambio = 0; 
    int ax,ay;
    ax = jugador.getx();
    ay = jugador.gety(); 
    jugador.teclado(); 
    
    // comprobar si colisiona con el mapa
    bool choca = false;
    int px = jugador.getx();
    int py = jugador.gety()+16;  
    
    if ( lugar == 1)
    {
         px = jugador.getx()-160;
         py = jugador.gety()-160+16;
    }
    if (lugar == 2)
    {
         py=py+160;     
    }
      
    for ( int ci=2; ci < 30; ci++)
    {
        for (int cj=0; cj < 16; cj++)
        {

            // color rojo
            if ( getpixel( choque, px+ci, py+cj) == 0xff0000 ){
                 choca = true;
            }
            // color verde
            if ( getpixel( choque, px+ci, py+cj) == 0x00ff00 ) cambio = 1;
            // color azul
            if ( getpixel( choque, px+ci, py+cj) == 0x0000ff ) cambio = 2;
            // color amarillo
            if ( getpixel( choque, px+ci, py+cj) == 0xffff00 ) salir = true;
        }
    }    
    if ( choca ){
         // vuelve al estado anterior
         jugador.posiciona( ax,ay );
    }
    
    switch ( lugar ) 
    {           
    case 1:   // casa
         if ( cambio == 1 )
         {
              // cambiamos a otro lugar              
              lugar = 2;
              fondo  = bosq_a;
              choque = bosq_c;
              cielo  = bosq_b;  
              jugador.posiciona( 410,370 );            
         }
         break;
    case 2:   // bosque
         if ( cambio == 2 )
         {
              // cambiamos a otro lugar
              lugar = 1;
              fondo  = casa_a;
              choque = casa_c;
              cielo  = casa_b;  
              // situamos al prota dentro de la casa
              jugador.posiciona( 290,440 );            
         }
         break;  
    default:
         break;
    }                
             
}



// Se encarga de pintar todo sobre el buffer   
void pinta_juego()
{
    int ancho, alto;
    int ax=0;
    int ay=0;
    int bx=0;
    int by=0;
    
    switch ( lugar ) 
    {           
    case 1:   // casa     
             bx=160;
             by=160; 
             ancho = 480;
             alto = 325;
             break;
    case 2:   // bosque 
             ay=160;
             ancho = PANTALLA_ANCHO;
             alto  = PANTALLA_ALTO;
             break;
    default:
         break;
    }  
    
    blit( fondo, buffer, ax, ay, bx, by, ancho, alto);                   
    jugador.pinta();     
    masked_blit( cielo, buffer, ax, ay, bx, by, ancho, alto); 
}   


Todas las modificaciones se han realizado solo en el archivo mijuego.h, por tanto todos los demás archivos se dejan tal cual, solo se debe de sustituir este nuevo código y añadir las nuevas imágenes.


Paso a Paso

Se han declarado nuevas variables del tipo BITMAP, que son las que contendrá las imagenes de los escenarios. Se crea el concepto de fases, controlado con la variable lugar, que contendrá en que fase o lugar esta:

  • 1 En la casa
  • 2 En el bosque
En la función carga_juego(), cargamos todas las imágenes que se utilizarán en el programa. Las variables fondo, choque, y cielo, serán variables generales que indicaran el lugar actual en el que estamos, por tanto, siempre que se cambie de lugar (fase) se debe de actualizar estas variables con las nuevas imágenes del lugar.


    for ( int ci=2; ci < 30; ci++)
    {
        for (int cj=0; cj < 16; cj++)
        {

            // color rojo
            if ( getpixel( choque, px+ci, py+cj) == 0xff0000 ){
                 choca = true;
            }
            // color verde
            if ( getpixel( choque, px+ci, py+cj) == 0x00ff00 ) cambio = 1;
            // color azul
            if ( getpixel( choque, px+ci, py+cj) == 0x0000ff ) cambio = 2;
            // color amarillo
            if ( getpixel( choque, px+ci, py+cj) == 0xffff00 ) salir = true;
        }
    } 

En la función de colisión se han añadido algunas condiciones, según colores utilizados. Para el ejemplo utilizamos el rojo (0xff0000) para bloquear el paso del personaje, el verde (0x00ff00) para salir de la casa, el azul (0x0000ff) para volver al interior de la casa. Se han cambiado los valores del primer bucle for, ahora empieza en el 2 para acabar en el 29. Esto se ha realizado para reducir el tamaño de bloqueo del personaje, por tanto ahora el tamaño de choque es de 28x16, tal y como se muestra en la siguiente imagen el recuadro pintado de verde es lo que realmente se esta comprobando si choca.


En la función pinta_juego() siempre se pinta el fondo y el cielo. Lo único que va variando son los parámetros de muestra, que cambian según el escenario o lugar, para ello se crean las variables ax,ay, bx,by, ancho y alto.  Estos datos cambian según las propiedades de las imágenes utilizadas para los escenarios.

7 comentarios:

  1. Tengo un problema con esta sesión. Al hacer todas las modificaciones, sigue cortando el juego al salir por la puerta de la casa... He probado a lanzar excepción de allegro en caso de que no cargue bien las imágenes, pero se ve que ese no es el problema... ¿Una ayuda? Gracias. Por cierto, excelente curso: muy divertido, sencillo y muy bien explicado. Estoy deseoso de continuar con el :D

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
  2. Buenos tutoriales amigo
    una pregunta, Como funciona lo de getPixel? estoy algo confundido con la orientación de los ejes, por ejemplo por que si lugar==1 restas 160 pero si lugar==2 los sumas, no entiendo por que el cambio de operación, se supone que las dos imágenes las imprimiste a 160 en el eje Y.
    pdt: el programa funciona correctamente

    ResponderEliminar
    Respuestas
    1. El getpixel obtiene el color de la imagen choque, segun la posicion del personaje. Con respecto a lo de restar o sumar 160 se debe a que la imagen casa es inferior al tamaño de pantalla y por ello tengo que sumar 160,160, ya que la imagen empieza a mostrarse en esa posición. En cambio la imagen del bosque es mayor que la pantalla, y da la coincidencia que le doy a "ay"el valor de 160, para que la imagen bosque salga centrada en pantalla, ya que este valor indica desde donde empieza a mostrar la imagen, desde la posición (0,160) "esquina superior izquierda" hasta (800,760) "esquina inferior derecha".

      Eliminar
  3. Gracias por los tutos bro, queria preguntar que programa usas para crear los escenarios?

    ResponderEliminar
    Respuestas
    1. Las imagenes son sacadas del RPG MAKER y montadas con el Adobe Photoshop.

      Eliminar
  4. Hola man, hace tiempo estaba recién aprendiendo a programar cuando vi este tutorial. Y volví a el a releer un poco para retomar un poco la programación en C++. Solo quería decirte que muchísimas gracias por tu aporte y el tutorial realmente me sirvió mucho.

    ResponderEliminar