Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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

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


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.