miércoles, 7 de octubre de 2015

Crear juego RPG en C++ y Allegro 4 (18) Experiencia

Continuando con nuestro juego, después de la lucha cuando se mata al enemigo debemos recibir experiencia. Pues de esa parte nos vamos a encargar en este tutorial.






Objetivo

Hacer que el personaje tenga experiencia y nivel. Y según un numero de experiencia suba un nivel. También se mostrará al igual que la barra de vida, la barra de experiencia para que el jugador sepa cuanto le falta para el próximo nivel.


Programación

Empezamos por el archivo global.h, aquí se añade unas nuevas variables.

bool lvl_up;
int nlvlup;
int lux, luy;

Con estas variable se controlará lo siguiente:

  • lvl_up se utiliza para indicar si se ha subido nivel, si es TRUE entonces indica que si sube nivel.
  • nlvlup se utiliza para mostrar por pantalla la imagen LVL UP!, va contando el numero de veces que se ha mostrado.
  • lux,luy sirven para posicionar por pantalla la imagen LVL UP!.

En el archivo players.h, se añaden nuevas variables y funciones para la experiencia, quedando la clase de la siguiente forma:

class player
{
    BITMAP *prota;  
 int x,y;
 int direccion;
 int animacion;
    bool hablar;
    int ataca;
    
    int vida;
    int vidamax; 
          
    int enivel;
    int exp;      
          
    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; };
       
       void sube_experiencia( int e );
       
       int getnivel(){ return enivel; };
       int getexp(){ return exp; };
}; 

La variable enivel contiene el nivel actual del personaje, y la variable exp contiene la experiencia actual. Se han añadido dos funciones para poder ver los valores de las dos nuevas variables, la función getnivel() y getexp(). Y la función sube_experiencia(), tiene como parámetro la cantidad de experiencia que se aumenta, se encarga de aumentar el valor de la experiencia y comprobar si se ha llegado a un nuevo nivel.

void player::sube_experiencia( int e )
{
     exp = exp + e;
     int nxp = 100 * ( enivel + 1 );
     
     if ( exp >= nxp  && nxp != 1 )
     {
          exp = exp - nxp;
          enivel++;
          // ha subido de nivel !!
          sonido_sube_nivel();
          lvl_up = true;
          
          nxp = 100 * ( enivel + 1 );
          while ( exp >= nxp )
          {                
              exp = exp - nxp;
              enivel++;
              // ha subido de nivel !!
              sonido_sube_nivel(); 
              nxp = 100 * ( enivel + 1 );               
          }                     
     }   
}

La variable nxp contiene el valor de la ecuación 100 * (enivel + 1), esto quiere decir que al nivel 1 el valor de nxp es 200, a nivel 2 es 300, a nivel 3 es 400, y así sucesivamente. Esta ecuación tiene una progresión aritmética, quiere decir que la diferencia entre dos términos sucesivos cualesquiera de la secuencia es una constante, en este caso es 100. Al usar este tipo de ecuación se esta haciendo que  la dificultad de subir un nivel sea relativamente sencillo. Esta ecuación no es la mas correcta pero para nosotros nos vale por el momento, próximamente se hará un curso exclusivo hablando de esta ecuación y la dificultad.

En la esta función se encarga de sumar la experiencia que se recibe por el parámetro e. Luego se compara con el nivel de experiencia que se necesita para subir el nivel actual (npx) y si es superior la experiencia actual (exp), a esta experiencia actual se le resta lo npx. Se calcula el valor del próximo nivel de experiencia (npx) y si exp sigue siendo mayor se repite hasta que no lo sea.

En la funcion player::inicia(), se inicializan a cero las nuevas variables.

    exp = 0;
    enivel = 0;

En el archivo audio.h, se añade la funcion del sonido para cuando sube de nivel.

void sonido_sube_nivel(){
    play_sample ( (SAMPLE *)datosjuego[dsubenivel].dat, 110,128, 1300, 0 );   
}

En el archivo npc.h,  en la clase enemigo se añade una nueva variable exp, y una función para actualizar este valor.

class enemigo : public npc {
      int vida;
      int v_actual; 
      bool muerto;     
      int golpeado;
      int exp;
     public:
        void crea( BITMAP *_img, int _x, int _y, int dir, int _estado, int _lugar, int v );
        void herida( int d ); 
        void pinta();
        bool ha_muerto() { return muerto; };
        void movimiento();
        bool frente();
        void daexp(int e){ exp = e; };        
};

En la función enemigo::crea(), se debe inicializar la nueva variable, para nuestro caso le daremos el valor por defecto de 50.

    exp = 50; 

Se añade en la función enemigo::herida() la llamada a la función sube_experiencia(), que se añadirá después del sonido_muere().

           jugador.sube_experiencia(exp);

En el archivo mijuego.h, se añade una nueva barra en la función pinta_barra_vida(), aparte de pintar la barra de vida, ahora también pintará la barra de experiencia.

void pinta_barra_vida()
{
   
    int n = (jugador.getvida()*150) / jugador.getvidamax() ;

    rectfill( buffer, PANTALLA_ANCHO-162, 10, PANTALLA_ANCHO-8, 25, 0x003300);   
    rectfill( buffer, PANTALLA_ANCHO-160, 12, PANTALLA_ANCHO-160+n, 23, 0x00ff00);       
    rectfill( buffer, PANTALLA_ANCHO-160, 12, PANTALLA_ANCHO-160+n, 15, 0xbbffaa);
    rect( buffer, PANTALLA_ANCHO-162, 10, PANTALLA_ANCHO-8, 25, 0x000000); 
  
    int nxp = 100 * ( jugador.getnivel() + 1 );
    int n2 = (jugador.getexp()*150) / nxp ;

    rectfill( buffer, PANTALLA_ANCHO-162, 30, PANTALLA_ANCHO-8, 45, 0x000033);   
    rectfill( buffer, PANTALLA_ANCHO-160, 32, PANTALLA_ANCHO-160+n2, 43, 0x0000ff);       
    rectfill( buffer, PANTALLA_ANCHO-160, 32, PANTALLA_ANCHO-160+n2, 35, 0xbbaaff);
    rect( buffer, PANTALLA_ANCHO-162, 30, PANTALLA_ANCHO-8, 45, 0x000000); 
    textprintf_centre_ex( buffer, font, PANTALLA_ANCHO - 80, 34, 0xFFFFFF, -1, "Niv: %d", 
                    jugador.getnivel() );  
} 


Se crea una nueva función llamada pinta_lvlup(), que se encargará de mostrar una imagen con el texto LVL UP! por encima del jugador.

void pinta_lvlup()
{
     if ( lvl_up )
     {
          nlvlup = 1;
          lux = jugador.getx();
          luy = jugador.gety();
          lvl_up = false;
     }
     if ( nlvlup > 0 )
     {
          masked_blit ( (BITMAP *)datosjuego[dilvlup].dat, buffer, 0,0, lux, luy - nlvlup*2, 32,32 );
          int num = FRAME_RATE / 10;
           if ( tiempo_total % num == 0 )
           {
              nlvlup++;              
           }
           if  ( nlvlup > 40 ) nlvlup = 0;
     }
} 

Con la variable num, se obtiene un valor para que la imagen se muestre 10 veces en un segundo, y se va aumentando la variable nlvlup para contar cuantas veces se ha mostrado, cuando supere las 40 se reinicia a cero.

En la función pinta_juego(), se añade la llamada a la funcion pinta_lvlup() justo después de la llamada a la funcion pinta_barra_vida().

Y aqui ya termina la programación, solo falta tener el ultimo archivo DAT, que contiene el sonido y la imagen.

Puedes descargar archivo DAT haciendo clic aqui

A continuación  teneis un video donde se muestra como el jugador lucha contra varios enemigos. Dos de ellos dan mas experiencia, que son los soldados, de este modo suben varios niveles. Cuando se sube de nivel aparece encima del jugador la imagen que pone "LVL UP".


No hay comentarios:

Publicar un comentario