Problem Implementing Texture on Libgdx Mesh of Randomized Terrain

Posted by BrotherJack on Game Development See other posts from Game Development or by BrotherJack
Published on 2013-06-08T01:50:00Z Indexed on 2014/05/30 3:55 UTC
Read the original article Hit count: 229

I'm having problems understanding how to apply a texture to a non-rectangular object. The following code creates textures such as this:

enter image description here

from the debug renderer I think I've got the physical shape of the "earth" correct. However, I don't know how to apply a texture to it. I have a 50x50 pixel image (in the environment constructor as "dirt.png"), that I want to apply to the hills. I have a vague idea that this seems to involve the mesh class and possibly a ShapeRenderer, but the little i'm finding online is just confusing me.

Bellow is code from the class that makes and regulates the terrain and the code in a separate file that is supposed to render it (but crashes on the mesh.render() call). Any pointers would be appreciated.

public class Environment extends Actor{
      Pixmap sky;
      public Texture groundTexture;
      Texture skyTexture;
      double tankypos; //TODO delete, temp
      public Tank etank; //TODO delete, temp
      int destructionRes; // how wide is a static pixel
      private final float viewWidth;
      private final float viewHeight;
      private ChainShape terrain;
      public Texture dirtTexture;
      private World world;
      public Mesh terrainMesh;

      private static final String LOG = Environment.class.getSimpleName();

      // Constructor
      public Environment(Tank tank, FileHandle sfileHandle, float w, float h, int destructionRes) {
        world = new World(new Vector2(0, -10), true);
        this.destructionRes = destructionRes;
        sky = new Pixmap(sfileHandle);
        viewWidth = w;
        viewHeight = h;
        skyTexture = new Texture(sky);
        terrain = new ChainShape();
        genTerrain((int)w, (int)h, 6);

        Texture tankSprite = new Texture(Gdx.files.internal("TankSpriteBase.png"));
        Texture turretSprite = new Texture(Gdx.files.internal("TankSpriteTurret.png"));
        tank = new Tank(0, true, tankSprite, turretSprite);
        Rectangle tankrect = new Rectangle(300, (int)tankypos, 44, 45);
        tank.setRect(tankrect);

        BodyDef terrainDef = new BodyDef();  
        terrainDef.type = BodyType.StaticBody;  
        terrainDef.position.set(0, 0);  
        Body terrainBody = world.createBody(terrainDef);

        FixtureDef fixtureDef = new FixtureDef();  
        fixtureDef.shape = terrain;
        terrainBody.createFixture(fixtureDef);

        BodyDef tankDef = new BodyDef();
        Rectangle rect = tank.getRect();
        tankDef.type = BodyType.DynamicBody;
        tankDef.position.set(0,0);
        tankDef.position.x = rect.x;
        tankDef.position.y = rect.y;
        Body tankBody = world.createBody(tankDef);

        FixtureDef tankFixture = new FixtureDef();
        PolygonShape shape = new PolygonShape();
        shape.setAsBox(rect.width*WORLD_TO_BOX, rect.height*WORLD_TO_BOX);
        fixtureDef.shape = shape;

        dirtTexture = new Texture(Gdx.files.internal("dirt.png"));
        etank = tank;
      }

      private void genTerrain(int w, int h, int hillnessFactor){
            int width = w;
            int height = h;

            Random rand = new Random();
            //min and max bracket the freq's of the sin/cos series
            //The higher the max the hillier the environment
            int min = 1;

            //allocating horizon for screen width
            Vector2[] horizon = new Vector2[width+2];
            horizon[0] = new Vector2(0,0);
            double[] skyline =  new double[width]; //TODO skyline necessary as an array?

            //ratio of amplitude of screen height to landscape variation
            double r = (int) 2.0/5.0;

            //number of terms to be used in sine/cosine series
            int n = 4;
            int[] f = new int[n*2];

            //calculating omegas for sine series
            for(int i = 0; i < n*2 ; i ++){             
                f[i] =  rand.nextInt(hillnessFactor - min + 1) + min;
            }

            //amp is the amplitude of the series
            int amp =  (int) (r*height);
            double lastPoint = 0.0;                             
            for(int i = 0 ; i < width; i ++){
                skyline[i] = 0;

                for(int j = 0; j < n; j++){
                    skyline[i] += ( Math.sin( (f[j]*Math.PI*i/height) ) +  Math.cos(f[j+n]*Math.PI*i/height) );
                }

                skyline[i] *= amp/(n*2);
                skyline[i] += (height/2);
                skyline[i] = (int)skyline[i]; //TODO Possible un-necessary float to int to float conversions
                tankypos = skyline[i];
                horizon[i+1] = new Vector2((float)i, (float)skyline[i]);
                if(i == width) lastPoint = skyline[i];
            }
            horizon[width+1] = new Vector2(800, (float)lastPoint);
            terrain.createChain(horizon);
            terrain.createLoop(horizon);

                    //I have no idea if the following does anything useful :(
            terrainMesh = new Mesh(true, (width+2)*2, (width+2)*2, 
                    new VertexAttribute(Usage.Position, (width+2)*2, "a_position"));
            float[] vertices = new float[(width+2)*2];
            short[] indices = new short[(width+2)*2];
            for(int i=0; i < (width+2); i+=2){
                vertices[i] = horizon[i].x;
                vertices[i+1] = horizon[i].y;
                indices[i] = (short)i;
                indices[i+1] = (short)(i+1);
            }
            terrainMesh.setVertices(vertices);
            terrainMesh.setIndices(indices);
      }

Here is the code that is (supposed to) render the terrain.

@Override
public void render(float delta) {
    Gdx.gl.glClearColor(1, 1, 1, 1);
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

    // tell the camera to update its matrices.
    camera.update();

    // tell the SpriteBatch to render in the
    // coordinate system specified by the camera.

    backgroundStage.draw();
    backgroundStage.act(delta);

    uistage.draw();
    uistage.act(delta);

    batch.begin();
    debugRenderer.render(this.ground.getWorld(), camera.combined);
    batch.end();

    //Gdx.graphics.getGL10().glEnable(GL10.GL_TEXTURE_2D);
    ground.dirtTexture.bind();
    ground.terrainMesh.render(GL10.GL_TRIANGLE_FAN); //I'm particularly lost on this
    ground.step();
}

© Game Development or respective owner

Related posts about textures

Related posts about box2d