开发者

Better way to generate tiles

I'll start by saying that i'm REALLY new to OpenGL ES (I started yesterday =), but I do have some Java and other languages experience.

I've looked a lot of tutorials, of course Nehe's ones and my work is mainly based on that.

As a test, I started creating a "tile generator" in order to create a small Zelda-like game (just moving a dude in a textured square would be awsome :p).

So far, I have achieved a working tile generator, I define a char map[][] array to store wich tile is on :

private char[][] map = {
            {0, 0, 20, 11, 11, 11, 11, 4, 0, 0},
            {0, 20, 16, 12, 12, 12, 12, 7, 4, 0},
            {20, 16, 17, 13, 13, 13, 13, 9, 7, 4},
            {21, 24, 18, 14, 14, 14, 14, 8, 5, 1},
            {21, 22, 25, 15, 15, 15, 15, 6, 2, 1},
            {21, 22, 23, 0, 0, 0, 0, 3, 2, 1},
            {21, 22, 23, 0, 0, 0, 0, 3, 2, 1},
            {26, 0, 0, 0, 0, 0, 0, 3, 2, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
    };

It's working but I'm no happy with it, I'm sure there is a beter way to do those things :

1) Loading Textures :

I create an ugly looking array containing the tiles I want to use on that map :

private int[] textures = {
            R.drawable.herbe, //0
            R.drawable.murdroite_haut, //1
            R.drawable.murdroite_milieu, //2
            R.drawable.murdroite_bas, //3
            R.drawable.angledroitehaut_haut, //4
            R.drawable.angledroitehaut_milieu,  //5
    };

(I cutted this on purpose, I currently load 27 tiles)

All of theses are stored in the drawable folder, each one is a 16*16 tile.

I then use this array to generate the textures and store them in a HashMap for a later use :

int[] tmp_tex = new int[textures.length]; 
gl.glGenTextures(textures.length, tmp_tex, 0); 
texturesgen = tmp_tex; //Store the generated names in texturesgen 
for(int i=0; i < textures.length; i++)
{ 
    //Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), textures[i]);
    InputStream is = context.getResources().openRawResource(textures[i]);
    Bitmap bitmap = null;
    try {
        //BitmapFactory is an Android graphics utility for images
        bitmap = BitmapFactory.decodeStream(is);

    } finally {
        //Always clear and close
        try {
            is.close();
            is = null;
        } catch (IOException e) {
        }
    } 
    // Get a new texture name 
    // Load it up 
    this.textureMap.put(new Integer(textures[i]),new Integer(i)); 
    int tex = tmp_tex[i]; 
    gl.glBindTexture(GL10.GL_TEXTURE_2D, tex); 
    //Create Nearest Filtered Texture
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

    //Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);

    //Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

    bitmap.recycle();
} 

I'm quite sure there is a better way to handle that... I just was unable to figure it. If someone has an idea, i'm all ears.

2) Drawing the tiles

What I did was create a single square and a single texture map :

/** The initial vertex definition */
    private float vertices[] = { 
                                -1.0f, -1.0f, 0.0f,     //Bottom Left
                                1.0f, -1.0f, 0.0f,      //Bottom Right
                                -1.0f, 1.0f, 0.0f,      //Top Left
                                1.0f, 1.0f, 0.0f        //Top Right
                                                };

    private float texture[] = {         
            //Mapping coordinates for the vertices
              0.0f, 1.0f,
              1.0f, 1.0f,
              0.0f, 0.0f,
              1.0f, 0.0f

                                };

Then, in my draw function, I loop through the map to define the texture to use (after pointing to and enabling the buffers) :

for(int y = 0; y < Y; y++){
    for(int x = 0; x < X; x++){
        tile = map[y][x];
        try 
            { 
                //Get the texture from the HashMap
                int textureid = ((Integer) this.textureMap.get(new Integer(textures[tile]))).intValue(); 
                gl.glBindTexture(GL10.GL_TEXTURE_2D, this.texturesgen[textureid]); 
            }    
            catch(Exception e) 
            { 
                return; 
            }

        //Draw the vertices as triangle strip
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);            
        gl.glTranslatef(2.0f, 0.0f, 0.0f); //A square takes 2x so I move +2x before drawing the next tile
    }
    gl.glTranslatef(-(float)(2*X), -2.0f, 0.0f); //Go back to the begining of the map X-wise and move 2y down before drawing the next line
}

This works great by I really think that on a 1000*1000 or more map, it will be lagging as hell (as a reminder, this is a typical Zelda world map : http://vgmaps.com/Atlas/SuperNES/LegendOfZelda-ALinkToThePast-LightWorld.png ).

I've read things about Vertex Buffer Object and DisplayList but I couldn't find a good tutorial and nodoby seems to be OK on wich one is the best / has the better support (T1 and Nexus One are ages away).

I think that's it, I've putted a lot of code but I think it helps.

Thanks in advance !开发者_如何学C


A couple of things:

  1. There's no need to use a hashmap, just use a vector/list.
  2. It may be faster/easier to have one large texture that contains all your tiles. Use appropriate texture coordinates to select the appropriate tile. You might have to be a little bit careful about texture filtering here. It sounds like you are doing a 2D game in which case you probably want to use nearest-neighbour filtering for the tiles and clamp the camera to integer pixel locations.
  3. Wouldn't it be easier to use GL_QUADS rather than GL_TRIANGLE_STRIP. Not sure about your code there - you don't seem to use the 'texture' array.
  4. The map size shouldn't make any difference, as long as you don't draw tiles that aren't on the screen. Your code should be something like:

.

int minX = screenLeft / tileSize;
int minY = screenBottom / tileSize;
int maxX = screenRight / tileSize;
int maxY = screenTop / tilesSize;
for (int x = minX; x <= maxX; ++x)
{
   for (int y = minY; y < maxY; ++y)
   {
      ...
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜