Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Colisiones con tiles, en un tileset.

Iniciado por Puyover, 06 de Marzo de 2007, 05:33:02 PM

« anterior - próximo »

Puyover

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!!
Vivimos en la era de la televisión. Una sola toma de una enfermera bonita ayudando a un viejo a salir de una sala dice más que todas las estadísticas sanitarias. -Margaret Thatcher

Harko

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.
-=Harko´s Blog=-
Fui el primer civil en probar el "Lord of Creatures" y ademas usaban mis cascos. :D

-=Portfolio=-

Alguno de mis juegos:
-=Feed The Frog=-

Neroncity

Puyover

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!!
Vivimos en la era de la televisión. Una sola toma de una enfermera bonita ayudando a un viejo a salir de una sala dice más que todas las estadísticas sanitarias. -Margaret Thatcher

Puyover

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!!
Vivimos en la era de la televisión. Una sola toma de una enfermera bonita ayudando a un viejo a salir de una sala dice más que todas las estadísticas sanitarias. -Margaret Thatcher

Harko

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.
-=Harko´s Blog=-
Fui el primer civil en probar el "Lord of Creatures" y ademas usaban mis cascos. :D

-=Portfolio=-

Alguno de mis juegos:
-=Feed The Frog=-

Neroncity

Puyover

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:
Vivimos en la era de la televisión. Una sola toma de una enfermera bonita ayudando a un viejo a salir de una sala dice más que todas las estadísticas sanitarias. -Margaret Thatcher

Puyover

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!!
Vivimos en la era de la televisión. Una sola toma de una enfermera bonita ayudando a un viejo a salir de una sala dice más que todas las estadísticas sanitarias. -Margaret Thatcher






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.