sábado, 16 de julio de 2011

GameEngine: Capitulo 21.Fisicas 2D

Hola a todos,

Bienvenidos a un nuevo capitulo de como crear tu propio motor de videojuegos...

En capitulos anteriores hemos visto como animar un personaje , como moverlo por la pantalla mediante teclado y raton , como pintar un tilemap) y como implementar el scroll. En el capitulo de hoy seguiremos la sucesión logica e implementaremos las fisicas 2D de nuestro juego, a fin de que nuestro personaje pueda chocar contra las paredes y saltar de plataforma en plataforma.

Las fisicas no se han implementado en un modulo aparte por que están intimamente ligadas al juego y al gestor de gráficos y animaciones. Hacer un modulo aparte tal vez estorbaria mas que otra cosa.

En esta entrega se han hecho unos cuantos cambios menores (por ejemplo se ha implementado un animación de espera, para que el personaje no estuviera todo el rato corriendo), pero el cambio fuerte ha sido en el modulo de animaciones 2D y al gestor de tiles a los cuales se les ha añadido unas funciones encargadas de calcular las colisiones entre la animación del personaje y el tilemap.

TileManager:
bool TileManager::CollideWithAnim(int x, int y, char id[])
{
int i,j,t,tile,xt,yt;

for( i = 0 ; i < map_height ; i++ )
{
for( j = 0 ; j < map_width ; j++ )
{
tile = map[ (i*map_width + j) ];

if (!tile)
continue;
tile--;

t = TextureManager::singleton().GetWidth(loaded[ tile ],0);
xt = j*t;
yt = i*t;
if( Anim2DManager::singleton().CollideWithGraph( x , y , id ,
xt , yt , loaded[tile] , 0) )
{
return true;
}
}
}
//Si hemos llegado hasta aqui es que no hemos colisionado con nada.
return false;
}

Anim2DManager:
bool Anim2DManager::CollideWithGraph(int xa, int ya, char cada[], int xg, int yg, char cadg[],int part)
{
int i;
int a = -1;

for ( i = 0 ; i < MAX_ELEMENTS_LOADED ; ++i ) //Para cada elemento cargado
{
if( !strcmp(loaded[i],cada) ) //Hemos encontrado la cadena que nos interesa
{
a = i ;
break;
}
}
for(i = 0 ; i < array_anim[a].frame[array_anim[a].actual_frame].num_elements ; ++i)
{
if ( LPE.GrafCollision( xa + array_anim[a].frame[array_anim[a].actual_frame].element[i].x ,
ya + array_anim[a].frame[array_anim[a].actual_frame].element[i].y ,
array_anim[a].frame[array_anim[a].actual_frame].element[i].cad,
array_anim[a].frame[array_anim[a].actual_frame].element[i].part,
xg,yg,cadg,part ) )
{
return true;
}
}
//Si hemos llegado hasta aquí es que no tenemos colisiones
return false;
}

Código en juego:
void draw ()
{
static bool right = true;
static int jump = 0;
static int angle = 0;
static int xplayer=200, yplayer = 260;
char anim[16];

//A todo lo que pintemos a partir de ahora se le aplicará scroll.
LPE.EnableFlag("SCROLL");

TileManager::singleton().DrawMap(); //Pintamos el mapa cargado

LPE.Scroll(xplayer,yplayer);

//Por defecto el personaje no correrá sino que estará a la espera
sprintf(anim,"STAND");

//Comprovamos inicialmente que no esté chocando con nada
if (TileManager::singleton().CollideWithAnim(xplayer,yplayer,anim))
{
if (!TileManager::singleton().CollideWithAnim(xplayer+5,yplayer,anim))
xplayer+=5;

if (!TileManager::singleton().CollideWithAnim(xplayer-5,yplayer,anim))
xplayer-=5;
if (!TileManager::singleton().CollideWithAnim(xplayer,yplayer+5,anim))
yplayer+=5;

if (!TileManager::singleton().CollideWithAnim(xplayer,yplayer-5,anim))
yplayer-=5;

}

if ( LPE.KeyBoardRight() )
{
xplayer+=5;
right = true;
sprintf(anim,"RUN");
if (TileManager::singleton().CollideWithAnim(xplayer,yplayer,"RUN"))
{
xplayer -= 5;
}
}

if ( LPE.KeyBoardLeft() )
{
xplayer-=5;
right = false;
sprintf(anim,"RUN");
if (TileManager::singleton().CollideWithAnim(xplayer,yplayer,"RUN"))
{
xplayer += 5;
}

}

if ( LPE.KeyBoardUp() && !jump)
{
//Si estamos tocando el suelo
if (TileManager::singleton().CollideWithAnim(xplayer,yplayer-5,anim))
{
jump = 25;
}
}
if(jump)
{
yplayer+=jump;
if (TileManager::singleton().CollideWithAnim(xplayer,yplayer,anim))
{
yplayer -= jump;
jump = 1; //Paramos de saltar
}
jump--;
}

if ( right )
LPE.DisableFlag("INVX");
else
LPE.EnableFlag("INVX");
angle = LPE.Angle2DToMouse(xplayer,yplayer);

if( angle < 0.1 ) angle = 0.1;
yplayer-=5;
if (TileManager::singleton().CollideWithAnim(xplayer,yplayer,anim))
{
yplayer+=5;
}

//Personaje
LPE.DrawAnim(xplayer,yplayer,anim);

if(right)
LPE.DrawCenterRotate(xplayer-10,yplayer-30,angle,"PLAYER",3);
else
LPE.DrawCenterRotate(xplayer-60,yplayer-30,angle,"PLAYER",3);

//Cuando hemos acabado de pintar lo que queremos tener girado, desactivamos los flips de x
LPE.DisableFlag("INVX");
//Cuando hemos acabado de pintar lo que queremos tener con el scroll activado, lo desactivamos.
LPE.DisableFlag("SCROLL");

//Pintado de textos
LPE.DrawText("SYSTEM",200,350,"FISICAS 2D");
}


En el siguiente video podréis ver el resultado, espero que os guste:


Recordad que en la carpeta de descargas podeis bajaros el código y el ejecutable ya compilado.
Ya sin más, deseo que os haya gustado el capitulo de hoy y que os lo hayaís pasado bien.

LordPakusBlog
Nos vemos

0 comentarios :

Publicar un comentario

Entradas populares