sábado, 10 de octubre de 2015

Crear juego RPG en C++ y Allegro 4 (20) Inventario

Continuamos con el curso de crea tu juego RPG en C++ y Allegro. En esta entrega se hará el inventario.





Objetivo

En este curso se añadirá los objetos. Estos objetos se podrá conseguir matando enemigos. Tambien se añade el inventario del jugador, que tiene un limite de 12 objetos.


Programación

En el archivo global.h, se añade una nueva variable, que se va a encargar de controlar cuando se esta mostrando el inventario, esta variable se llamará swinv.

int swinv;

En el archivo players.h, se añaden nuevas funciones y una variable para el manejo del inventario.

class player
{
    BITMAP *prota;  
 int x,y;
 int direccion;
 int animacion;
    bool hablar;
    int ataca;
    
    int vida;
    int vidamax; 
          
    int enivel;
    int exp;      
    
    int inventario[12];
          
    public:  
       void inicia();    
       void pinta(); 
       bool choca();
       void teclado(); 
       int getx(){ return x; };
       int gety(){ return y; };
       void posiciona( int _x, int _y);
       void cambia_escenario();
       bool accion();
       void habla();
       void no_habla();
       bool hablando(){ return hablar; };
       bool atacando(){ return ataca>1; };
       void no_ataca(){ ataca = -3; };
       int  dire(){ return direccion; };
       
       int getvida(){ return vida; };
       int getvidamax(){ return vidamax; };
       void herido(int n){ vida-=n; };
       
       BITMAP* getimg(){ return prota; };
       
       void sube_experiencia( int e );
       
       int getnivel(){ return enivel; };
       int getexp(){ return exp; };
       
       void obtiene_objeto( int id );
       int getinventario(int id){ return inventario[id]; };
}; 

La variable inventario es una matriz de 12 elementos, en los cuales se almacenará el id del objeto. La función obtiene_objeto(), recibe el id de un objeto y lo asigna a una posición de la matriz siempre que exista un hueco vacio, en el caso de estar el inventario lleno, el objeto en cuestión se pierde.
La función getinventario(), devuelve según el parámetro id, lo que se contiene en la posición id del vector inventario.

void player::obtiene_objeto( int id ){
     int n = 0;
     while ( n < 12 && inventario[n] != 0 )
     {
           n++;
     }
     // tiene un hueco
     if ( inventario[n] == 0 ){
          inventario[n] = id;
     }
}

Esta función recibe el id del objeto, e intenta almacenarlo en una de las casillas del vector inventario. Inicializa n a cero, y se repite el bucle hasta que encuentre un hueco vacio, es decir, que inventario[n]=0 o que n sea mayor que 11. En el caso de encontrar un hueco, asigna el valor de id, al vector inventario en la posición n.

En el archivo npc.h, en la función enemigo::herida() se añade justo despues de subir la experiencia al jugador, lo siguiente para que el jugador reciba un objeto.

    if ( v_actual <= 0 )
     {
           muerto = true;
           blit( mifondo, fondo, 0,0, x,y, 32,32); 
           rectfill( choque, x+2, y+1, x+30, y+31, 0x000000);
           sonido_muere();
           jugador.sube_experiencia(exp);
           // siempre obtiene un objeto aleatorio
           int q = objetos[rand()%6].id; 
           jugador.obtiene_objeto( q );
     }else{

En el archivo mijuego.h, se añade lo siguiente despues de la declaración de la  variable jugador.

player jugador;

struct m_objetos{   
    int id;   
};

m_objetos objetos[6];

#include "npc.h"

Se crea una esctrutura llamada m_objetos, que ahora mismo le añadimos una variable llamada id. Y luego se declara la variable objetos, que se trata de un vector de dimension 6, de la clase m_objetos.

En la función carga_juego(), se inicializan las nuevas variables, que son el vector de objetos y la variable swinv.

    // carga objetos
    for (int e=0; e < 6; e++){
        objetos[e].id = dio001 + e;
    }
    
    swinv=0;


Se crea una nueva función llamada control_inventario().

void control_inventario(){
     if ( swinv == 0 && key[KEY_I] ){
          swinv = 1;
     }
     
     if ( swinv == 3 && !key[KEY_I] ) swinv=0;
     
     if ( swinv == 2 && key[KEY_I] ){
          swinv = 3;
     }
}

Esta función se encarga de controlar cuando se pulsa la tecla I, para mostrar el inventario.

Se añade la llamada a la función control_inventario() dentro de la función actualiza_juego().

// actualiza el estado del juego
void actualiza_juego()
{

    scroll_escenario();

    evento_escenario();    
    
    jugador.teclado(); 
    
    control_inventario();
                 
    cambia_escenario();         
}


Se crea una función que muestre el inventario por pantalla, que se llama pinta_inventario().

void pinta_inventario()
{
     if ( swinv >  0 )
     {
                    
          int jx = jugador.getx();
          int jy = jugador.gety();
          
          if ( jx > PANTALLA_ANCHO/2 ){
               jx = (PANTALLA_ANCHO/4) - 160;
          }else{
               jx = (PANTALLA_ANCHO*3/4) - 160; 
          }
          
          if ( jy > PANTALLA_ALTO/2 ){
               jy = (PANTALLA_ALTO/4) - 81;
          }else{
               jy = (PANTALLA_ALTO*3/4) - 81; 
          }          
       
          // se muestra fondo inventario
          masked_blit( (BITMAP *)datosjuego[diinventario].dat, buffer, 0,0, jx,jy, 320,162);
          
          masked_blit( jugador.getimg(), buffer, 32,0, jx+65,jy+60, 32,32); 
          masked_blit( (BITMAP *)datosjuego[dio005].dat, buffer, 0,0, jx+115,jy+74, 32,32); 
          masked_blit( (BITMAP *)datosjuego[dio006].dat, buffer, 0,0, jx+12,jy+74, 32,32);          
          
          int id;
          for ( int i=0; i < 4; i++){
              for ( int j=0; j < 3; j++){
                  int num = (j*4) + i ;
                 id = jugador.getinventario( num );                 
                 if ( id != 0 ){
                      int posx = jx + 172 + i*34;
                      int posy = jy + 40 + j*34;
                      masked_blit( (BITMAP *)datosjuego[id].dat, buffer, 0,0, posx,posy, 32,32);                       
                  }
              }    
          }
          
          if ( !key[KEY_I]) swinv = 2;
     }
}

Esta función se podría haber simplificado  mucho, pero debido a la imagen que utilicé para mostrar el contenido del inventario y que cambia de posicion para que se pueda seguir jugando mientras ves el inventario se ha complicado un poco.

El codigo que hay del principio de la función hasta el comentario "//se muestra fondo inventario", esa parte se encarga de calcular la posición de la ventana inventario representada por la posicion jx,jy. Todo esto depende de la posicion del jugador, se divide la pantalla en 4 partes y se coloca el inventario en el que no se encuentra el jugador siguiendo la siguiente regla, si la posicion x es menor de la mitad de la pantalla, la posicion x del inventario será  mayor de la mitad, sino es a la inversa. Y asi igualmente para el eje y.

Despues de todo esto se pinta de forma transparente con el comando masked_blit, priemro el fondo del inventario, luego el personaje, y despues dos objetos ( armadura y espada )

El doble bucle for se utiliza para mostrar todos los posibles objetos que tenga el jugador en el inventario.


En la funcion pinta_juego(), se añade la llamada a la función pinta_inventario(). Esta llamada se pondrá despues de pintar la barra de vida y el lvlup.

    pinta_barra_vida();
    
    pinta_lvlup();
    
    pinta_inventario();


Y llegado a este punto si todo se ha copiado correctamente solo nos faltará actualizar el fichero DAT para tener las nuevas imágenes que se utilizan en este curso.

Haz clic para descargar el fichero DAT en formato RAR.



1 comentario:

Antes de publicar un comentario

Todos los comentarios que se realicen en el blog son moderados.

Debido a esto es muy probable que tu comentario no aparezca de inmediato ya que previamente debe ser revisado para evitar un mal uso (SPAM).

Podrán realizar comentario cualquiera que tenga una cuenta de Google.

Related Posts Plugin for WordPress, Blogger...