5

I am having trouble tiling a Bitmap. I want to have the Bitmap drawn to coordinates defined in a 2D Array.

I would like to be able to draw let's say "grass" to certain coordinates, and "water,etc.." to other coordinates.

I have spent days trying to figure this out, and would very greatly appreciate any insight. I can only get the Canvas to draw 1 "grass" Bitmap, So I feel I have an error in my for loop. I have looked here and here, amongst many others, and do not want every tile to be the same. Here is my code:

MapLoader.java

public class MapLoader extends SurfaceView implements SurfaceHolder.Callback,
    Runnable {

SurfaceHolder holder;
Thread thread;

Bitmap grass = BitmapFactory.decodeResource(getResources(),
        R.drawable.grass);
boolean running = false;

int[][] grassCoords = new int[][] { { 0, 16, 32, 48, 64 },
        { 0, 16, 32, 48, 64 }, { 0, 16, 32, 48, 64 },
        { 0, 16, 32, 48, 64 }, { 0, 16, 32, 48, 64 } };

public MapLoader(Context context) {
    super(context);

    holder = getHolder();
    holder.addCallback(this);
}

public MapLoader(Context context, AttributeSet attrs) {
    super(context, attrs);

    holder = getHolder();
    holder.addCallback(this);
}

public MapLoader(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    holder = getHolder();
    holder.addCallback(this);
}

public void pause() {
    running = false;

    while (running) {
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        break;
    }
    thread = null;
}

public void resume() {
    running = true;
    thread = new Thread(this);
    thread.start();

}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {

    running = true;
    thread = new Thread(this);
    thread.start();

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    Canvas c = holder.lockCanvas();
    draw(c);
    holder.unlockCanvasAndPost(c);

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

}

@Override
public void run() {

    while (running == true) {

        // performs drawing to the canvas
        if (!holder.getSurface().isValid()) {

            continue;
        }

        Canvas c = holder.lockCanvas();

        int x = 0;
        int y = 0;

        for (x = 0; x < grassCoords.length; x += grass.getWidth()) {

            for (y = 0; y < grassCoords.length; y += grass.getHeight()) {

                c.drawBitmap(grass, x, y, null);
            }

        }

        holder.unlockCanvasAndPost(c);

    }

}

}

ActivityClass.java

public class Test extends Activity {

MapLoader mapLoader;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mapLoader = new MapLoader(this);
    setContentView(mapLoader);

}
}

Any help or suggestions (even a link to an effective method) would be greatly appreciated!

Thanks,

Matt

Community
  • 1
  • 1
MattMatt
  • 905
  • 6
  • 19

2 Answers2

4

It isn't easy to understand what you are trying to do...

How do you encode coordinates into that grassCoords array? As its current form it has 5x5 elements.

int[][] grassCoords = new int[][] { { 0, 16, 32, 48, 64 },
        { 0, 16, 32, 48, 64 }, { 0, 16, 32, 48, 64 },
        { 0, 16, 32, 48, 64 }, { 0, 16, 32, 48, 64 } };

Since it has grass in its name I assume you want to draw only grass, then you could define it like this

int[][] grassCoords = new int[][] { {0, 0}, {16, 16}, {32, 32} };

Above each element like {0, 0} would be a single coordinate for a grass tile.

Second issue is with your loop, you don't read any data from grassCoords except arrays length and when you increment the index you increment it with grass.getWidth() which doesn't really make sense.

    int x = 0;
    int y = 0;

    for (x = 0; x < grassCoords.length; x += grass.getWidth()) {

        for (y = 0; y < grassCoords.length; y += grass.getHeight()) {

            c.drawBitmap(grass, x, y, null);
        }

    }

You should iterate array correctly and fetch the data from it.

    int x = 0;
    for (x = 0; x < grassCoords.length; x++) {
        c.drawBitmap(grass, grassCoords[x][0], grassCoords[x][1], null);
    }

If I were you I would study related parts of Java tutorial at least once.

auselen
  • 27,577
  • 7
  • 73
  • 114
  • Thank you for the link and explanation. I had trouble understandind a 2d Array at first. both answers are really helpful and have taught me alot. Thank you and @Geobits as well! – MattMatt Aug 30 '13 at 23:53
2
for (x = 0; x < grassCoords.length; x += grass.getWidth()) {
    for (y = 0; y < grassCoords.length; y += grass.getHeight()) {
        c.drawBitmap(grass, x, y, null);
    }
}

The reason it only draws once is this bit right here. grassCoords.length is 5. When you add the grass width to x after the first draw, it goes over 5, and the loop ends. You need to use a separate variable for the two. Same for y. There are other issues with this, as auselen points out, but this is the reason it only draws once to begin with.

However, you can do away with the coordinates array altogether if you want to seamlessly tile a rectangle with one bitmap. You don't even need to know how many tiles wide/tall it is. This is especially useful if you're using a base layer of grass below other tiles, if you're tiling a pattern for a background image, etc. You could do that like this:

for(int x = startX; x < endX; x += grass.getWidth()){
    for(int y = startY; y < endY; y += grass.getHeight()){
        c.drawBitmap(grass, x, y, null);
    }
}

Remember, if you just want to fill with tiles at regular intervals, there is no need to define the coordinates. They will all be multiples, so defining a coordinates array at all doesn't make much sense. Just consider each tile spot as a grid point and multiply by the tile's height/width.

Geobits
  • 22,218
  • 6
  • 59
  • 103