Hola a todos!
Siento molestar tanto, pero llevo ya un buen rato, intentando que el protagonista de mi "juego", al colisionar con un objeto, como un arbol o una piedra, se pare y no avance mas. El método que yo utilizo es el de tener todos los terrenos por los que el muñeco puede pasar en un tileset, y en otro tileset, tengo los elementos con los que colisiona.
Aquí os dejo el código:
// Cargamos el mapa
Pradera = new CRM32Pro_CTile();
Pradera_col = new CRM32Pro_CTile();
Pradera->Load(TILESET_RESOURCE, "Pradera");
Pradera_col->Load(TILESET_RESOURCE, "Pradera_col");
Pradera_col_sur = Pradera_col->GetSurface();
// Propiedades de cada tile
offset.x = Pradera_col->GetPosX()-7;
offset.y = Pradera_col->GetPosY()-7;
offset.w = Pradera_col->GetSizeX();
offset.h = Pradera_col->GetSizeY();
............................................................................................
while(!done) {
PJHandler();
// Bucle de eventos, para salir del programa
while(CRM32Pro.Update(&event)) {
switch(event.type) {
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_ESCAPE) done = 1;
break;
case SDL_QUIT:
done = 1;
break;
}
}
}
............................................................................................
/** FUNCION DE MANEJO DEL PROTAGONISTA **/
void PJHandler(void) {
// Realizamos un mapeado del teclado
keyboard = SDL_GetKeyState(NULL);
// Resumimos la animacion del sprite
Link->Resume();
// Comprobamos los movimientos de Link
if(keyboard[SDLK_UP]) {
Link->SelectAnim(SPRSTATE_UP);
spr_posX = Link->GetPosX();
spr_posY = Link->GetPosY() - spr_velY;
Link->SetPosition(spr_posX, spr_posY);
if(Link->Collision(Pradera_col_sur, &offset)) Link->SetPosition(spr_posX, spr_posY + spr_velX);
} else if(Link->GetAnim() == SPRSTATE_UP) { Link->SelectFrame(7); Link->Pause(); }
if(keyboard[SDLK_LEFT]) {
Link->SelectAnim(SPRSTATE_LEFT);
spr_posX = Link->GetPosX() - spr_velX;
spr_posY = Link->GetPosY();
Link->SetPosition(spr_posX, spr_posY);
if(Link->Collision(Pradera_col_sur, &offset)) Link->SetPosition(spr_posX + spr_velX, spr_posY);
} else if(Link->GetAnim() == SPRSTATE_LEFT) { Link->SelectFrame(0); Link->Pause(); }
if(keyboard[SDLK_RIGHT]) {
Link->SelectAnim(SPRSTATE_RIGHT);
spr_posX = Link->GetPosX() + spr_velX;
spr_posY = Link->GetPosY();
Link->SetPosition(spr_posX, spr_posY);
if(Link->Collision(Pradera_col_sur, &offset)) Link->SetPosition(spr_posX - spr_velX, spr_posY);
} else if(Link->GetAnim() == SPRSTATE_RIGHT) { Link->SelectFrame(7); Link->Pause(); }
if(keyboard[SDLK_DOWN]) {
Link->SelectAnim(SPRSTATE_DOWN);
spr_posX = Link->GetPosX();
spr_posY = Link->GetPosY() + spr_velY;
Link->SetPosition(spr_posX, spr_posY);
if(Link->Collision(Pradera_col_sur, &offset)) Link->SetPosition(spr_posX, spr_posY - spr_velY);
} else if(Link->GetAnim() == SPRSTATE_DOWN) { Link->SelectFrame(0); Link->Pause(); }
}
La cuestión es que el protagonista se para, pero luego ya no puedo salir de ahí; es como si se quedara bloqueado... y otra cosa es que el juego se mueve muy lento. el bucle para recorrer todos los tiles del tileset y que los dibuje está en una función, a la que llamo con SetRenderCallback(...);
En fin, haber si podéis hecharme una mano.
Salu2!!
Yo lo hago de otra forma, sobretodo porque por ahora solo uso dos tiles (toy de pruebas :P).
Primero tienes unas coordenadas que es donde el muñeco quiere ir y otras que es donde estaba. Luego compruebas si en su siguiente posicion se metera en una tile que no puede tocar, diferente del suelo, y si es asi le colocamos las coordenadas que tenia antes y parece que no se mueva. Asi haces todas las comprobaciones de golpe y te evitas tener que ir calculandolo en cada pulsacion. Y hay que mirar las cuatro esquinas del muñeco, por supuesto.
Aqui te dejo mi codigo para que le eches un vistazo, aun no he puesto nada para que cambie la animacion segun la tecla que pulsa:
void RenderGraphics(int n){
int x,y; //posicion actual
int Posx,Posy; //posicion anterior
int tx=0,ty=0; //tile que coincide con la esquina sup. izquierda del pj
int tx2=0, ty2=0; // tile abajo derecha
int toca[4]; // esquinas del pj
int mala=0; // indica si puede ponerse en la siguiente posicion
Uint8 *keys;
// Vaciamos la pantalla SDL_FillRect(CRM32Pro.screen,NULL,SDL_MapRGB(CRM32Pro.screen->format,0,0,0));
for(x=0;x<4;x++){
toca[x]=0;
}
keys=SDL_GetKeyState(NULL);
Posx=px;
Posy=py;
if(keys[SDLK_UP]){
py-=8;
}
if(keys[SDLK_DOWN]){
py+=8;
}
if(keys[SDLK_LEFT]){
px-=8;
}
if(keys[SDLK_RIGHT]){
px+=8;
}
//calculamos tiles
tx=px/32;
ty=py/32;
tx2=(px+30)/32;
ty2=(py+28)/32;
sprintf(text,"%d %d",tx,ty);
// numero de la tile de cada esquina
toca[0]=suelo[ty][tx];
toca[1]=suelo[ty][tx2];
toca[2]=suelo[ty2][tx];
toca[3]=suelo[ty2][tx2];
for(x=0;x<4;x++){
if(toca[x]!=2){ // si no es suelo
mala=1;
}
}
if(mala==0){
pj->SetPosition(px,py,0);
}else{
px=Posx;
py=Posy;
}
// Dibujamos las tiles
for(x=0;x<TILES_X;x++){
for(y=0;y<TILES_Y;y++){
tile->SetPosition(y*32,x*32);
tile->Draw(NULL,suelo[x][y]);
}
}
pj->Draw();
font->PutString(CRM32Pro.screen,5,5,text);
sprintf(text,"%d %d %d %d",toca[0],toca[1],toca[2],toca[3]);
font->PutString(CRM32Pro.screen,5,25,text);
}
Los fonts del final son solamente informacion para saber donde esta el muñeco y que tiles esta tocando o va a tocar, me viene bien cuando estoy probando cosas :P
Espero que te sea util.
Harko.
Oki muchas gracias. Ya miraré esto con mas detenimiento, porque esta semana la tengo plagada de examenes y no tengo tiempo para nada.
En fin, saludos y gracias!!
Nada que no lo consigo xD.
He creado estructuras para Sprites y Mapas para que este todo mas organizado.
Aquí os dejo el nuevo código:
// Cargamos el mapa e inicializamos sus variables
Pradera.GFX = new CRM32Pro_CTile();
Pradera.GFX->Load(TILESET_RESOURCE, "Pradera");
Pradera.GFX_collision_old = new CRM32Pro_CTile();
Pradera.GFX_collision_old->Load(TILESET_RESOURCE, "Pradera_Mask");
Pradera.GFX_collision_new = Pradera.GFX_collision_old->GetSurface();
Pradera.offset.x = 0;
Pradera.offset.y = 0;
Pradera.offset.w = 1280;
Pradera.offset.h = 980;
// Cargamos los sprites e incicializamos sus variables
Link.GFX = new CRM32Pro_CSprite();
Link.GFX->Load(SPRITES_RESOURCE, "Link");
Link.posX = 400;
Link.posY = 300;
Link.velX = 3;
Link.velY = 3;
Link.GFX->SetPosition(Link.posX, Link.posY);
//Renderizamos los graficos, con la funcion de retrollamada
CRM32Pro.SetRenderCallback(RenderGraphics);
DrawMap();
...
void RenderGraphics(int bLogicUpdate) {
PJHandler();
Link.GFX->Draw();
}
void DrawMap(void) {
// Dibujamos el mapa
for(Pradera.posY = 0; Pradera.posY < 30; Pradera.posY++) {
for(Pradera.posX = 0; Pradera.posX < 40; Pradera.posX++) {
Pradera.tX = Pradera.posX * 32;
Pradera.tY = Pradera.posY * 32;
Pradera.tile[Pradera.posY * Pradera.posX] = (Pradera.posY * 40) + Pradera.posX;
Pradera.GFX->SetPosition(Pradera.tX, Pradera.tY);
Pradera.GFX->Draw(CRM32Pro.screen, Pradera.tile[Pradera.posY * Pradera.posX] + 1);
}
}
}
void PJHandler(void) {
// Realizamos un mapeado del teclado
keyboard = SDL_GetKeyState(NULL);
// Reiniciamos la animación del personaje
Link.GFX->Resume();
Link.lastX = Link.posX;
Link.lastY = Link.posY;
// Comprobamos los movimientos de Link y las colisiones
if(keyboard[SDLK_UP]) {
if(!Link.GFX->Collision(Pradera.GFX_collision_new, &Pradera.offset)) {
Link.posY -= Link.velY;
}
Link.GFX->SetPosition(Link.posX, Link.posY);
Link.GFX->SelectAnim(SPRSTATE_UP);
} else if(Link.GFX->GetAnim() == SPRSTATE_UP) { Link.GFX->SelectFrame(0); Link.GFX->Pause(); }
if(keyboard[SDLK_LEFT]) {
if(!Link.GFX->Collision(Pradera.GFX_collision_new, &Pradera.offset)) {
Link.posX -= Link.velX;
}
Link.GFX->SetPosition(Link.posX, Link.posY);
Link.GFX->SelectAnim(SPRSTATE_LEFT);
} else if(Link.GFX->GetAnim() == SPRSTATE_LEFT) { Link.GFX->SelectFrame(4); Link.GFX->Pause(); }
if(keyboard[SDLK_RIGHT]) {
if(!Link.GFX->Collision(Pradera.GFX_collision_new, &Pradera.offset))
Link.posX += Link.velX;
Link.GFX->SetPosition(Link.posX, Link.posY);
Link.GFX->SelectAnim(SPRSTATE_RIGHT);
} else if(Link.GFX->GetAnim() == SPRSTATE_RIGHT) { Link.GFX->SelectFrame(0); Link.GFX->Pause(); }
if(keyboard[SDLK_DOWN]) {
if(!Link.GFX->Collision(Pradera.GFX_collision_new, &Pradera.offset))
Link.posY += Link.velY;
Link.GFX->SetPosition(Link.posX, Link.posY);
Link.GFX->SelectAnim(SPRSTATE_DOWN);
} else if(Link.GFX->GetAnim() == SPRSTATE_DOWN) { Link.GFX->SelectFrame(0); Link.GFX->Pause(); }
}
Pfff, la cuestión es que lo suyo sería almacenar la posición anterior del PJ, pero no se como hacerlo...
Bueno pues a ver si me podeís ayudar.
Salu2 y graciasss!!
Veamos, ante todo tienes que fijarte que lo que hace el codigo es comprobar si hay una colision y luego mover al personaje a su siguiente posicion. Con eso consigues que si en su siguiente posicion esta en colision con un tile no se mueva, esa es la razon por la que se te queda bloqueado.
Lo que tendrias que hacer, o al menos es lo que yo hago, es guardate la posicion actual del personaje, moverlo y despues comprobar si tiene colision con algun tile indebido, luego solo queda dejarlo como esta o volver a ponerlo en su anterior posicion si colisiona. Tienes que fijarte bien en el orden porque sino no consigues nada.
Y otra cosa que he comprobado, el tema de la animacion segun la tecla que pulsa quedaria algo asi, bueno ya que estoy te pongo el codigo entero:
keys=SDL_GetKeyState(NULL);
Posx=px;
Posy=py;
if(keys[SDLK_UP]){
pj->SelectAnim(SPRSTATE_UP);
pj->Resume();
py-=8;
}
if(keys[SDLK_DOWN]){
pj->SelectAnim(SPRSTATE_DOWN);
pj->Resume();
py+=8;
}
if(keys[SDLK_LEFT]){
pj->SelectAnim(SPRSTATE_LEFT);
pj->Resume();
px-=8;
}
if(keys[SDLK_RIGHT]){
pj->SelectAnim(SPRSTATE_RIGHT);
pj->Resume();
px+=8;
}
if(!keys[SDLK_UP] && !keys[SDLK_DOWN] && !keys[SDLK_LEFT] && !keys[SDLK_RIGHT]){
pj->Pause();
pj->SelectFrame(0);
}
tx=px/32;
ty=py/32;
tx2=(px+30)/32;
ty2=(py+28)/32;
sprintf(text,"%d %d",tx,ty);
toca[0]=suelo[ty][tx];
toca[1]=suelo[ty][tx2];
toca[2]=suelo[ty2][tx];
toca[3]=suelo[ty2][tx2];
for(x=0;x<4;x++){
if(toca[x]!=2){
mala=1;
}
}
if(mala==0){
pj->SetPosition(px,py,0);
}else{
px=Posx;
py=Posy;
}
Solo hace falta seleccionar la animacion adecuada y decirle que la ponga enmarcha y comprobar si se dejan de pulsar las teclas de direccion para detener la animacion seleccionando el primer frame.
Y en cuanto a las tiles lo tengo asin:
Carga de tiles:
CRM32Pro_CTile *tile;
int suelo[TILES_X][TILES_Y]=
{{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1},
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}};
.....main......................
tile = new CRM32Pro_CTile();
tile->Load(IMG_RESOURCE,"suelo");
........rendercallback
// Dibujamos las tiles
for(x=0;x<TILES_X;x++){
for(y=0;y<TILES_Y;y++){
tile->SetPosition(y*32,x*32);
tile->Draw(NULL,suelo[x][y]);
}
}
Creo que no hace tanta falta crear estructuras para esas cosas, al menos mientras no sean cosas muy grandes. Y si, el escenario lo pongo a pelo, estoy mirando como lo podria poner en el dpf y poder tener varios escenarios separados pero aun no lo tengo muy claro.
Harko.
Vale he acoplado el sistema que me ha dado a mi juego, y he pasado un mapa hecho con mappy a .h
int Pradera_map[30][40] = { todos los valores }
void DrawMap(void) {
// Dibujamos el mapa
for(Pradera.posY = 0; Pradera.posY < 30; Pradera.posY++) {
for(Pradera.posX = 0; Pradera.posX < 40; Pradera.posX++) {
Pradera_map[Pradera.posY][Pradera.posX] = (Pradera.posY * 40) + Pradera.posX;
Pradera.GFX->SetPosition(Pradera.posX * 32, Pradera.posY * 32);
Pradera.GFX->Draw(NULL, Pradera_map[Pradera.posY][Pradera.posX] + 1);
}
}
}
.....
Link.tX = Link.lastX / 32;
Link.tY = Link.lastY / 32;
Link.tX2 = (Link.lastX + 70) / 32;
Link.tY2 = (Link.lastY + 70) / 32;
Link.toca[0] == Pradera_map[Link.tY][Link.tX];
Link.toca[1] == Pradera_map[Link.tY][Link.tX2];
Link.toca[2] == Pradera_map[Link.tY2][Link.tX];
Link.toca[3] == Pradera_map[Link.tY2][Link.tY2];
for(Link.bucle = 0; Link.bucle < 4; Link.bucle++){
if(Link.toca[Link.bucle] != 1) Link.libre = 1;
}
if(Link.libre == 0){
Link.GFX->SetPosition(Link.lastX, Link.lastY, 0);
} else {
Link.posX = Link.lastX;
Link.posY = Link.lastY;
}
.....
No se si influirá que mi sprite sea de 80x80. La cosa es que ahora se supone que debería de colisionar con cualquier tile que no sea 1, ya que el 1 es por donde se puede andar. Tampoco sé si he acoplado bien la matriz al mapa .png, ya que no puedo comprobarlo...
Muchas gracias por la ayuda y siento ponerme tan pesado :oops:
Ha! Ya he conseguido cargar los tiles. Lo que pasaba era que cargaba la imagen, y la matriz la dejaba ahí suelta. Vale ahora el problema es que sigue sin colisionar nada :(
const short Pradera_map0[30][40] = { valores }
void DrawMap(void) {
for(Pradera.posY = 0; Pradera.posY < 30; Pradera.posY++) {
for(Pradera.posX = 0; Pradera.posX < 40; Pradera.posX++) {
Pradera.tile->SetPosition(Pradera.posY * 32, Pradera.posX * 32);
Pradera.tile->Draw(NULL, Pradera_map0[Pradera.posX][Pradera.posY]);
Pradera.tile->Draw(NULL, Pradera_map1[Pradera.posX][Pradera.posY]);
}
}
}
void PJHandler(void) {
for(Link.bucle = 0; Link.bucle < 4; Link.bucle++){
Link.toca[Link.bucle] = 0;
}
// Realizamos un mapeado del teclado
keyboard = SDL_GetKeyState(NULL);
Link.posX = Link.lastX;
Link.posY = Link.lastY;
// Comprobamos los movimientos de Link y las colisiones
if(keyboard[SDLK_UP]) {
Link.GFX->SelectAnim(SPRSTATE_UP);
Link.GFX->Resume();
Link.lastY -= Link.velY;
}
if(keyboard[SDLK_LEFT]) {
Link.GFX->SelectAnim(SPRSTATE_LEFT);
Link.GFX->Resume();
Link.lastX -= Link.velX;
}
if(keyboard[SDLK_RIGHT]) {
Link.GFX->SelectAnim(SPRSTATE_RIGHT);
Link.GFX->Resume();
Link.lastX += Link.velX;
}
if(keyboard[SDLK_DOWN]) {
Link.GFX->SelectAnim(SPRSTATE_DOWN);
Link.GFX->Resume();
Link.lastY += Link.velY;
}
if(!keyboard[SDLK_UP] && !keyboard[SDLK_DOWN] && !keyboard[SDLK_LEFT] && !keyboard[SDLK_RIGHT]) {
Link.GFX->Pause();
Link.GFX->SelectFrame(0);
}
Link.tX = Link.lastX / 32;
Link.tY = Link.lastY / 32;
Link.tX2 = (Link.lastX + 80) / 32;
Link.tY2 = (Link.lastY + 80) / 32;
Link.toca[0] == Pradera_map0[Link.tX][Link.tY];
Link.toca[1] == Pradera_map0[Link.tX2][Link.tY];
Link.toca[2] == Pradera_map0[Link.tX][Link.tY2];
Link.toca[3] == Pradera_map0[Link.tX2][Link.tY2];
if(Pradera_map0[Link.tY][Link.tX] == 1) Link.libre = true;
for(Link.bucle = 0; Link.bucle < 4; Link.bucle++){
if(Link.toca[Link.bucle] == 1) Link.libre = true;
}
if(Link.libre == true) {
Link.GFX->SetPosition(Link.lastX, Link.lastY, 0);
} else {
Link.posX = Link.lastX;
Link.posY = Link.lastY;
}
}
Creo que ya casi esta hecho, pero hay un error y no me doy cuenta...
Una cosa: a DrawMap() solo la llamo una vez, en el main, sin entrar en bucle ni nada. Es que si la meto en el rendercallback, el juego me funciona MUY lento.
Salu2!!