Desplazamiento

En esta entrega nos centramos en el desplazamiento del escenario, lo que se define en ingles como scroll.






Este ejemplo esta completo, pero es la continuación de "El primer escenario", en el se han explicado muchas cosas que aquí ya pasaré por alto para centrarnos en el funcionamiento del scroll.

Programación


El archivo main.cpp contiene lo siguiente:
  
#include <allegro.h>
#include "global.h"
#include "players.h"
#include "mijuego.h"
   
    
void inicia_allegro()
{
 allegro_init();
 install_keyboard();
 
 set_color_depth(32);
 set_gfx_mode(GFX_AUTODETECT_WINDOWED, PANTALLA_ANCHO, PANTALLA_ALTO, 0, 0);
 
 buffer = create_bitmap(PANTALLA_ANCHO, PANTALLA_ALTO);    
    
    LOCK_VARIABLE(contador_tiempo_juego);
    LOCK_FUNCTION(inc_contador_tiempo_juego); 
    
    // Iniciamos el limitador de FPS
    install_int_ex(inc_contador_tiempo_juego, BPS_TO_TIMER( FRAME_RATE ));    
}
           
   
// programa principal 
int main()  
{ 
    inicia_allegro();
    
    carga_juego();
          
 salir = false;  
    
      
 while ( !salir )
 {   
          if ( contador_tiempo_juego )
          {
                while ( contador_tiempo_juego )
                {
                    actualiza_juego();
    
                    contador_tiempo_juego--;
                }  
                
                clear_to_color(buffer, 0x00000);    
                 
                pinta_juego();
                
                pintar_pantalla();         
                
          }else{
                                    
               rest(1);  
          }
       // tecla de salida
       if ( key[KEY_ESC] ) salir = true;
    }         
   
 destroy_bitmap(buffer);
  
 return 0;
}
END_OF_MAIN();


El siguiente archivo es el global.h
/* GLOBAL.H 

*/

// Ancho y alto de la pantalla
const int PANTALLA_ANCHO = 800;
const int PANTALLA_ALTO  = 600;

// En este BITMAP dibujaremos todo
BITMAP *buffer;

// es el espacio en pixel que recorre el jugador al andar
const int desplazamiento=4;


// Copiar el buffer a la pantalla del juego (screen)
void pintar_pantalla()
{
    blit(buffer, screen, 0, 0, 0, 0, PANTALLA_ANCHO, PANTALLA_ALTO);
}

// controla el bucle principal
bool salir;

// Variable usada para la velocidad
volatile unsigned int contador_tiempo_juego = 0;

const int FRAME_RATE = 30;

// Función para controlar la velocidad
void inc_contador_tiempo_juego()
{
    contador_tiempo_juego++;
}
END_OF_FUNCTION(inc_contador_tiempo_juego)


El siguiente archivo es el player.h
// players.h


// Esta clase se encarga del manejo del jugador
class player
{
    BITMAP *prota;  
 int x,y;
 int direccion;
 int animacion; 
          
    public:  
       void inicia();    
       void pinta(); 
       void teclado(); 
       int getx(){ return x; };
       int gety(){ return y; };
       void posiciona( int _x, int _y);
};


void player::inicia()
{
    prota  = load_bmp("personaje.bmp",NULL); 
 // inicializar vbles
 direccion = 0;
 animacion = 0;
 x = 320;
 y = 280;        
}


void player::pinta()
{
    masked_blit(prota, buffer, animacion*32, direccion*32, x, y, 32,32);  
} 

void player::teclado()
{
      int ax = x;
      int ay = y;
      // teclas control usuario
      if ( key[KEY_UP] )
      {
           y-=desplazamiento; 
           direccion = 3;              
      }
      if ( key[KEY_DOWN] )
      {
           y+=desplazamiento;
           direccion = 0;
      }
      if ( key[KEY_LEFT] )
      {
           x-=desplazamiento;
           direccion = 1;
      }
      if ( key[KEY_RIGHT] )
      {
           x+=desplazamiento;
           direccion = 2;
      }  
      if ( ax != x || ay != y )
      {
           // entra si a cambiado alguna de las variables x,y
           animacion++;
           if ( animacion > 2 ) animacion = 0;
      }                            
      
      // limites globales
      if ( x < 0 ) x = 0;
      if ( x > PANTALLA_ANCHO-32 ) x = PANTALLA_ANCHO-32;
      if ( y < 0 ) y = 0;
      if ( y > PANTALLA_ALTO-32 )  y = PANTALLA_ALTO-32;      
}

void player::posiciona( int _x, int _y)
{
     x=_x;
     y=_y;
}


Estos tres códigos, están explicados en la entrada "El primer escenario". Si tienes algún problema no dudes en consultarlo.

A continuación el mas importante mijuego.h


/*
   mijuego.h
   
*/

BITMAP *bosq_a;
BITMAP *bosq_b;
BITMAP *bosq_c;
BITMAP *UI;

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

player jugador;

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


bool desplaza;

int desplazamiento_map_x;
int desplazamiento_map_y;

// carga todo lo necesario antes de empezar el juego
void carga_juego()
{
    jugador.inicia();
    
    bosq_a = load_bmp("b02.bmp",NULL);
    bosq_b = load_bmp("b03.bmp",NULL);     
    bosq_c = load_bmp("b01.bmp",NULL);
    
    UI = load_bmp("t.bmp",NULL);
      
    // cargamos imagenes del primer escenario
    fondo  = bosq_a;
    choque = bosq_c;
    cielo  = bosq_b;
    
    lugar = 1;  
    
    desplazamiento_map_x=0;
    desplazamiento_map_y=0;     
    desplaza = true;
}


// actualiza el estado del juego
void actualiza_juego()
{
    int cambio = 0; 
    int ax,ay;
    ax = jugador.getx();
    ay = jugador.gety(); 
    
     if ( desplaza )
    {
         int d = desplazamiento / 2;
         // controla el desplazamiento del mapa si esta en los bordes
         if ( ax < 160 && desplazamiento_map_x > 0 )
         {                
              desplazamiento_map_x-=d;
              jugador.posiciona(ax+d,ay);
              ax = jugador.getx();
              ay = jugador.gety();              
              if ( ax < 60 && desplazamiento_map_x > 0  )
              {
                  desplazamiento_map_x-=d;
                  jugador.posiciona(ax+d,ay);                   
              }
         }
         if ( ay < 160 && desplazamiento_map_y > 0 )
         { 
              desplazamiento_map_y-=d;
              jugador.posiciona(ax,ay+d);
              ax = jugador.getx();
              ay = jugador.gety();                
              if ( ay < 60 && desplazamiento_map_y > 0 )
             { 
                  desplazamiento_map_y-=d;
                  jugador.posiciona(ax,ay+d);                  
             }
         }
         if ( ax > PANTALLA_ANCHO-160 && desplazamiento_map_x < fondo->w-PANTALLA_ANCHO )
         {
              desplazamiento_map_x+=d;
              jugador.posiciona(ax-d,ay);
              ax = jugador.getx();
              ay = jugador.gety();                
              if ( ax > PANTALLA_ANCHO-60 && desplazamiento_map_x < fondo->w-PANTALLA_ANCHO  )
              {
                  desplazamiento_map_x+=d;
                  jugador.posiciona(ax-d,ay);                   
              }              
         }          
         if ( ay > PANTALLA_ALTO-160 && desplazamiento_map_y < fondo->h-PANTALLA_ALTO )
         {
              desplazamiento_map_y+=d;
              jugador.posiciona(ax,ay-d);
              ax = jugador.getx();
              ay = jugador.gety();                
              if ( ay > PANTALLA_ALTO-60 && desplazamiento_map_y < fondo->h-PANTALLA_ALTO )
              {
                  desplazamiento_map_y+=d;
                  jugador.posiciona(ax,ay-d);
              }              
         }
         ax = jugador.getx();
         ay = jugador.gety();            
                 
    }   
          

    jugador.teclado(); 
   
           
    // comprobar si colisiona con el mapa
    bool choca = false;
    int px = jugador.getx()+desplazamiento_map_x;
    int py = jugador.gety()+16+desplazamiento_map_y;  
       
        
      
    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 ) cambio = 3;
            // color celeste
            if ( getpixel( choque, px+ci, py+cj) == 0x00ffff ) cambio = 4;
            // otro azul 0080ff
            if ( getpixel( choque, px+ci, py+cj) == 0x0080ff ) cambio = 5;
            // naranja
            if ( getpixel( choque, px+ci, py+cj) == 0xff8000 ) cambio = 6;
        }
    }    
    if ( choca ){
         // vuelve al estado anterior
         jugador.posiciona( ax,ay );
    }
    
    switch ( lugar ) 
    {           
    case 1:  
         if ( cambio == 1 )
         {
              //  1000,540              
          jugador.posiciona( 400,540 );
          desplazamiento_map_x = 600;
         }
         if ( cambio == 2 )
         {
              //  610,100             
          jugador.posiciona( 400,100 );
          desplazamiento_map_x = 210;
         }    
         if ( cambio == 3 )
         {             
          jugador.posiciona( 420,460 );
          desplazamiento_map_x = 0;
         }
         if ( cambio == 4 )
         {
              //  1400,350             
          jugador.posiciona( 700,350 );
          desplazamiento_map_x = 700;
         }
         if ( cambio == 5 )
         {             
          jugador.posiciona( 70,250 );
          desplazamiento_map_x = 0;
         } 
         if ( cambio == 6 )
         {            
          jugador.posiciona( 290,100 );
          desplazamiento_map_x = 0;
         }                 
         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:      
             ax = desplazamiento_map_x; 
             ay = desplazamiento_map_y;
             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); 
    masked_blit( UI, buffer, 0, 0, 0, 0, ancho, alto); 
}         


Al principio se declaran las variables de las imágenes que se van a utilizar, en este caso  bosq_a, bosq_b, bosq_c, UI, fondo, choque y cielo.  Se declara la variable desplaza que es la que indicará que el escenario tiene scroll, para este desplazamiento del escenario se utilizan las variables desplazamiento_map_x y desplazamiento_map_y.
La función carga_juego() se encarga de cargar todas las imágenes necesarias, inicializa las variables necesarias para un correcto funcionamiento.

La función actualiza_juego(), aquí es donde se controla el scroll del mapa comprobando previamente que desplaza sea true. Se controla el desplazamiento del mapa cuando el personaje llega al borde de la ventana. Hay que tener en cuenta de que el jugador esta posicionado según el tamaño de la ventana, es decir, tendrá un valor entre el 0,0 y el 800,600.

También actualiza la posición del jugador y comprueba si choca con el escenario.

Como la posición del jugador no es absoluta con respecto al escenario antes de comprobar el pixel de choque debe calcularse la posición absoluta px,py. Para ello se obtiene la posición del jugador con respecto a la ventana y se le añade el desplazamiento del mapa según el eje que corresponda. 

A continuación se comprueba el color y se le da un valor a la variable cambio. Después de comprueba que valor tiene cambio y según su valor posiciona al jugador a una nueva posición. De esta forma haremos que nuestro personaje se desplace a otro mapa o a una nueva posición según deseemos.

La función pinta_juego(), se encarga de pintar el fondo, pinta el personaje, la imagen cielo y la imagen UI.

Las imágenes utilizada para el juego se encuentra en la sección de descarga, o puede descargarlas haciendo click aqui


En este video se muestra el funcionamiento del código, vemos como el personaje al acercarse al borde de la pantalla se inicia el scroll, es decir, el movimiento del escenario.
SHARE
    Blogger Comment

8 comentarios:

  1. esta genial, te sigo desde el blog antiguo, me gustaría que a tu juego le pusieras: objetos(cascos, espadas, armaduras,etc..) y que halla una interfaz de inventario, donde puedas usar los botones del mouse(para arrastrar y mover tus objetos).

    ResponderEliminar
    Respuestas
    1. Eso ya esta hecho, mira el siguiente video:
      https://www.youtube.com/watch?v=j6tVvif8rzQ

      Para hacerlo entra en el apartado dedicado al inventario :
      http://devcpp-allegro.blogspot.com.es/2015/10/crear-juego-rpg-en-c-y-allegro-4-20.html
      http://devcpp-allegro.blogspot.com.es/2015/10/crear-juego-rpg-en-c-y-allegro-4-21.html

      Eliminar
  2. oye, puedes subir el proyecto completo? es dificil seguir tu tutorial si no se tiene el codigo completo o no se explica bien...

    ResponderEliminar
    Respuestas
    1. Concretamente este tutorial tiene el codigo completo, de los 4 archivos que lleva. Solo tienes que copiar y pegar.

      Eliminar
  3. Hola amigo, te sigo desde el blog pasado, estaría increíble que subieras todos los recursos que utilizaste en tu blog anterior

    ResponderEliminar
  4. Cuando usas bosq_ y cargas las imagenes b02, b03 y b01.bmp entiendo que cargas fondo, cielo y choque, ¿pero que imagen quieres cargar con t.bmp?

    ResponderEliminar
    Respuestas
    1. Esa imagen se utiliza para la interfaz del usuario, una imagen que se mostrará por encima de todo. Que se puede utilizar para mostrar datos del jugador ( vida, etc.)

      Eliminar
  5. gracias por tu aporte, lo valoro mucho bro, de corazon y ojala lo puedas continuar, muchas gracias nuevamente!

    ResponderEliminar