Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tile a Bitmap on SurfaceView Canvas

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

like image 689
MattMatt Avatar asked Aug 24 '13 19:08

MattMatt


People also ask

How to draw Bitmap on canvas in android?

Use the Canvas method public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint) . Set dst to the size of the rectangle you want the entire image to be scaled into. EDIT: Here's a possible implementation for drawing the bitmaps in squares across on the canvas.

How do I create a Bitmap in canvas?

There is no way to extract the Bitmap out of a Canvas . The only way you can access it is to pass it yourself when creating the canvas like this new Canvas(myBitmap) and keep the reference.

What is BitmapDrawable?

android.graphics.drawable.BitmapDrawable. A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a BitmapDrawable from a file path, an input stream, through XML inflation, or from a Bitmap object. It can be defined in an XML file with the <bitmap> element.

How to use Bitmap Drawable in android?

Android App Development for Beginners This example demonstrates how do I convert Bitmap to drawable in android. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main. xml.


2 Answers

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.

like image 104
auselen Avatar answered Oct 29 '22 22:10

auselen


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.

like image 27
Geobits Avatar answered Oct 29 '22 21:10

Geobits