Take the 2-minute tour ×

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);

        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;

        BodyDef tankDef = new BodyDef();
        Rectangle rect = tank.getRect();
        tankDef.type = BodyType.DynamicBody;
        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
                f[i] =  rand.nextInt(hillnessFactor - min + 1) + min;

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

                    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);

                    //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);

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

public void render(float delta) {
    Gdx.gl.glClearColor(1, 1, 1, 1);

    // tell the camera to update its matrices.

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



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

    ground.terrainMesh.render(GL10.GL_TRIANGLE_FAN); //I'm particularly lost on this
share|improve this question
add comment

1 Answer

I found a solution for this but it causes slight stuttering and does not work when scaled down to the World scale. Did you ever find a solution?


share|improve this answer
add comment

Your Answer


