Blog de programación e ideas locas

Desarrollo: Cargando niveles de Tiled

by on Ene.05, 2012, under Desarrollo, EGa2Dengine, Engine

Ya había logrado cargar niveles con Tiled, aunque tenia un defecto en la física del nivel. Entonces tuve que primero agregar unas cosas que me recomendaron, una capa extra para definir la fisica en el Tiled. Y ya habia ordenado todo el codigo, asi que ahora me disponia a  cargar los niveles hecho en Tiled.

Cargando Niveles de Tiled(1)
Vista en el editor Tiled. Lo rojo transparente indica que es colisionable

Gracias a esta capa extra y sin muchos problemas (habian unos problemas tontos, pero como siempre no más) pude añadirle la capa fisica que necesitaba el juego.

Cargando Niveles de Tiled(3)   Vista en el juego.

Aunque no todo era de color rosa, había algo que me incomodaba en ese momento. Tiled entregaba la capa fisica (los tiles de color rojo transpararente) como una matriz o una secuencia de 0 y 1.

Por ejemplo.

1,0,0,0,1,
1,0,1,0,1,
1,1,1,1,1

Pero box2D trabaja con rectangulos, circulos, lineas y polygonos y además tenia muchos problemas con la logica del juego como por ejemplo un fantasma que camina a lo largo de una plataforma no lograba caminar correctamente porque creia que su plataforma era más pequeña de lo que se veia. Entonces ¿Como podia pasar de las colisiones que estan en una matriz a muchos rectangulos?

Bueno como esa ocasión estaba apurado hice un algoritmo bastante ingenuo (sencillo o basico)

//codigo
uint16 *data; //es la matriz con los datos guardada en un arreglo
int layer_w,layer_h; // dimensiones de la matriz
//necesitamos procesar todos los rectangulos
        Rect **r = new Rect*[layer_w];
        for(int i=0; i<layer_w; i++) {
            r[i] = new Rect[layer_h];
        }
        //agregamos los datos en los rectangulos
        for(int y=0; y<layer_h; y++) {
            for(int x=0; x<layer_w; x++) {
                if(data[y*layer_w+x]) { //todo colisionable
                    r[x][y] = Rect(x,y,1,1);
                }
            }
        }
        //ahora aplicar el algoritmo ingenuo
        //!\todo optimizar el algoritmo ingenuo
        for(int x=0; x < layer_w; x++) {
            for(int y=0; y < layer_h; y++) {
                Rect a = r[x][y];
                if(a.width !=0 || a.height != 0) {
                    //buscar
                    for(int i=x; i<layer_w; i++) {
                        for(int j=y; j<layer_h; j++) {
                            Rect v = r[i][j];
                            if(v.width != 0 || v.height != 0) {
                                Rect suma = a + v;
                                //se pueden fusionar y son los mismos datos
                                if(suma.area() == a.area()+v.area() && data[layer_w*y+x] == data[layer_w*j+i]) {
                                    r[x][y] = suma;
                                    a = suma;
                                    r[i][j].width = 0;
                                    r[i][j].height = 0;
                                }
                            }
                        }
                    }
                }
            }
        }

Algoritmo sencillo en C++, se basa en crear una matriz de rectangulos de dimension 1×1 que reprensentan los 1s en las matrices y que pueden sumarse si hay algun rectangulo contiguo.

Luego en Box2D, consideraba los rectangulos que tuvieran Area distinto de 0 quedando esto.

Cargando Niveles de Tiled(2) Vista actual del juego después de la optimización

Lo que me permitia, que mis fantasmas u otro enemigo, pueda ver correctamente la plataforma y caminar a lo largo de ella.

Saludos

:, , , , , , , , ,