Мозаика растрового изображения на холсте SurfaceView

У меня возникли проблемы с размещением Bitmap. Я хочу, чтобы Bitmap отображалось в координатах, определенных в 2D Array.

Я хотел бы иметь возможность рисовать, скажем, «траву» в определенных координатах и ​​«воду и т. Д.» В других координатах.

Я потратил дни, пытаясь понять это, и был бы очень признателен за любое понимание. Я могу заставить Canvas нарисовать только 1 "траву" Bitmap, поэтому я чувствую, что у меня ошибка в цикле for. Я посмотрел здесь и здесь, среди многих других, и не хочу, чтобы все плитки были одинаковыми. Вот мой код:

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

}
}

Любая помощь или предложения (даже ссылка на эффективный метод) будут очень признательны!

Спасибо,

Мэтт


person MattMatt    schedule 24.08.2013    source источник


Ответы (2)


Нелегко понять, что вы пытаетесь сделать...

Как вы кодируете координаты в этот массив grassCoords? В своей текущей форме он имеет 5x5 элементов.

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

Поскольку в его названии есть grass, я предполагаю, что вы хотите рисовать только траву, тогда вы можете определить ее следующим образом.

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

Над каждым элементом, например {0, 0}, будет одна координата тайла травы.

Вторая проблема связана с вашим циклом: вы не читаете никаких данных из grassCoords, кроме длины массивов, и когда вы увеличиваете индекс, вы увеличиваете его на grass.getWidth(), что на самом деле не имеет смысла.

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

    }

Вы должны правильно перебирать массив и извлекать из него данные.

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

На вашем месте я бы изучил соответствующие части учебника по Java на не реже одного раза.

person auselen    schedule 30.08.2013
comment
Спасибо за ссылку и объяснение. Сначала у меня были проблемы с пониманием двумерного массива. оба ответа действительно полезны и многому меня научили. Спасибо вам и @Geobits! - person MattMatt; 31.08.2013

for (x = 0; x < grassCoords.length; x += grass.getWidth()) {
    for (y = 0; y < grassCoords.length; y += grass.getHeight()) {
        c.drawBitmap(grass, x, y, null);
    }
}

Причина, по которой он рисует только один раз, заключается в том, что вот этот бит. grassCoords.length это 5. Когда вы добавляете ширину травы к x после первого рисования, она превышает 5, и цикл заканчивается. Вам нужно использовать отдельную переменную для двух. То же самое для y. Как указывает auselen, с этим есть и другие проблемы, но это причина, по которой он рисует только один раз для начала.

Однако вы можете вообще отказаться от массива координат, если хотите плавно замостить прямоугольник одним растровым изображением. Вам даже не нужно знать, сколько тайлов в ширину/в высоту. Это особенно полезно, если вы используете базовый слой травы под другими плитками, если вы накладываете шаблон для фонового изображения и т. д. Вы можете сделать это следующим образом:

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

Помните, что если вы просто хотите заполнить тайлами через равные промежутки времени, нет необходимости задавать координаты. Все они будут кратными, поэтому определение массива координат вообще не имеет особого смысла. Просто рассмотрите каждое пятно плитки как точку сетки и умножьте на высоту/ширину плитки.

person Geobits    schedule 30.08.2013