Проблема с загрузкой листа спрайтов

Я пытаюсь загрузить этот спрайт в массив буферизованного изображения (каждый спрайт в один BufferedImage):

введите здесь описание изображения

Я открыл этот файл в фотошопе. Ширина 500, а высота 666. Итак, согласно моим расчетам, мне нужно зациклиться 64 раза (8 строк и 8 столбцов), и для каждого спрайта его ширина 500/8 (62,5), а его высота 666/8. (83,25). Поскольку getSubImage принимает только параметры типа int, я был вынужден указать ширину 62 и высоту 83 (и я думаю, именно поэтому мои изображения обрезаются).

Вот код для загрузки спрайтов (я поместил их в JFrame, чтобы показать вам результаты).

public class Test{  
    public static void main(String [] args){
        BufferedImage[] sprites = null;
        
        int width = 62;
        int height = 83;    

        try {
            BufferedImage buff = ImageIO.read(Test.class.getResourceAsStream("cyclop.gif"));
            sprites = new BufferedImage[64];
            int rows = 8;
            int cols = 8;
            for (int i = 0; i < rows; i++){
                for (int j = 0; j < cols; j++){
                    sprites[(i * cols) + j] = buff.getSubimage(i * width, j * height, width, height);
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        JFrame frame = new JFrame();
        frame.getContentPane().setLayout(new FlowLayout());
        for(BufferedImage bf : sprites)
            frame.getContentPane().add(new JLabel(new ImageIcon(bf)));
        frame.pack();
        frame.setVisible(true);
    }
}

Какие выходы:

введите здесь описание изображения

Я немного потерялся (впервые делаю это) о том, как я могу загрузить каждый спрайт в BufferedImage. Есть идеи?


person user2336315    schedule 26.01.2014    source источник
comment
Почему вы предполагаете, что все изображения имеют одинаковую ширину/высоту? Например, в третьей строке у вас есть 5 изображений, а в первой строке у вас есть 8 изображений. Также высота каждой строки также не выглядит одинаковой   -  person jonasnas    schedule 27.01.2014
comment
@jonasnas Да, я видел это, но на данный момент мне не удалось правильно загрузить первую строку. Тогда я смогу для каждой строки соответствующим образом адаптировать ширину/высоту и количество спрайтов. Если бы вы могли показать мне, как загрузить первую строку, это было бы полезно!   -  person user2336315    schedule 27.01.2014
comment
Имеют ли изображения одинаковую ширину в каждой строке? Я сомневаюсь в этом. Вы исходите из того, что все должно быть равным, но есть ли у вас основания так думать? например, если высота изображения составляет 80 пикселей, а первые 10 пикселей - это пробел, это не означает, что вы можете просто разделить 80 пикселей на 8 и получить положение каждого изображения.   -  person jonasnas    schedule 27.01.2014
comment
Таким образом, вы предполагаете, что изображения в каждой строке имеют одинаковую высоту. Это не так: столбец 1, строка 2 расширяется в пространстве столбца 5, строки 3. Безусловно, самый простой способ решить эту проблему — открыть изображение в хорошем редакторе и записать x, y и ширину, высоту каждого изображения. . Сохраните эти числа во внешнем файле или непосредственно в исполняемом файле.   -  person Jongware    schedule 27.01.2014
comment
@jonasnas Да, ты прав, и это кажется сложнее, чем я. Так что же делать? Должен ли я попытаться увидеть, сколько пикселей нужно каждому спрайту?   -  person user2336315    schedule 27.01.2014
comment
(Примечание: это интересное упражнение по программированию для автоматизации поиска расширений каждого спрайта. Это не слишком сложно, так как здесь нет «незавершенных концов» — каждая фигура самодостаточна. Если вам нужно делать это для многих листов спрайтов, возможно, это стоит затраченных усилий.)   -  person Jongware    schedule 27.01.2014
comment
@Jongware Да, я хотел бы это сделать, но понятия не имею, как это сделать! И да, это было бы полезно для будущего.   -  person user2336315    schedule 27.01.2014


Ответы (2)


В основном логика в тебе for-loop неверна...

Вы умножаете width на текущую строку (i) и height на текущий столбец (j)

for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        sprites[(i * cols) + j] = buff.getSubimage(i * width, j * height, width, height);
    }
}

Должно быть больше похоже...

for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
        sprites[(i * cols) + j] = buff.getSubimage(j * width, i * height, width, height);
    }
}

Спрайты

(Для примера я увеличил высоту до строки 95)

Теперь, очевидно, у вас есть проблема, так как спрайты разных размеров, да для вас. Я бы предложил создать простой файл поиска, который содержит строку/столбец в качестве ключа и ширину/высоту ячейки, возможно, даже x/y, чтобы вы могли просто выбрать спрайт прямо, но это зависит от вас. ..

person MadProgrammer    schedule 27.01.2014
comment
Да, я создал класс для хранения координат и ширины/высоты каждого спрайта, и он отлично работал! - person user2336315; 27.01.2014

Ниже приведено очень быстро написанное (и, вероятно, грязное) решение на C для поиска автономных, неперекрывающихся спрайтов. Я использовал программу для чтения PNG, чтобы получить данные в формате RGBA, и проверил только альфа-канал.

Это работает следующим образом:

  1. найти любой ненулевой альфа-пиксель сверху вниз;
  2. начиная с этого пикселя, сформируйте (минимум, максимум) прямоугольник и продолжайте расширять его, пока ни одна из сторон не будет содержать альфа-пиксель;
  3. вы получаете пустую рамку шириной в один пиксель вокруг фактического спрайта, поэтому minx,y нужно увеличить на 1, а maxx,y уменьшить — но это происходит при вычислении координат к размеру.
  4. наконец, этот прямоугольник стирается, поэтому следующие циклы его больше не увидят.

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

Выходной список может быть отсортирован по координатам x, y для ясности; Я собираюсь оставить это и перевести это на Java вам. Эта программа предполагает, что на одном листе (struct bounds_t[64]) может быть 64 или меньше изображений; убедитесь, что он настолько велик, насколько это необходимо.

C-код (очевидные структуры библиотеки PNG и заголовки опущены):

struct bounds_t {
    int x,y,wide,high;
};

int alphaAt (struct pngdata_t *sheet, int x, int y)
{
    if (x >= 0 && x < sheet->wide && y >= 0 && y < sheet->high)
        return sheet->data[4*sheet->wide*y + 4*x + 3];
    return 0;
}

void floodFindBounds (struct pngdata_t *sheet, int startx, int starty, struct bounds_t *dest)
{
    int x,y;
    int hit;
    int minx = startx,miny = starty,maxx = startx,maxy = starty;

    while (maxx < sheet->wide && alphaAt (sheet, maxx+1,miny))
        maxx++;
    while (maxy < sheet->high && alphaAt (sheet, minx,maxy+1))
        maxy++;

    do
    {
        hit = 0;
        for (x=minx; x<=maxx; x++)
        {
            if (alphaAt (sheet, x,miny))
                hit |= 1;
        }
        for (y=miny; y<=maxy; y++)
        {
            if (alphaAt (sheet, minx,y))
                hit |= 2;
        }
        for (x=minx; x<=maxx; x++)
        {
            if (alphaAt (sheet, x,maxy))
                hit |= 4;
        }
        for (y=miny; y<=maxy; y++)
        {
            if (alphaAt (sheet, maxx,y))
                hit |= 8;
        }
        if (hit & 1) miny--;
        if (hit & 2) minx--;
        if (hit & 4) maxy++;
        if (hit & 8) maxx++;
    } while (hit);

    minx++;
    miny++;

    dest->x = minx;
    dest->y = miny;
    dest->wide = maxx-minx;
    dest->high = maxy-miny;
}

void wipeout (struct pngdata_t *sheet, struct bounds_t *wipe)
{
    int x,y;
    for (y=wipe->y; y<=wipe->y+wipe->high; y++)
        for (x=wipe->x; x<=wipe->x+wipe->wide; x++)
            sheet->data[4*sheet->wide*y + 4*x + 3] = 0;
}

int main (void)
{
    struct pngdata_t *sheet;
    struct bounds_t fullList[64];
    int x,y;
    int n_in_list = 0;

    sheet = read_png ("monster.png");
    if (!sheet)
    {
        printf ("unable to read sprite sheet\n");
        return 0;
    }

    printf ("ready to process\n");
    printf ("size: %d x %d\n", sheet->wide, sheet->high);

    printf ("pixel #0 = %d,%d,%d,%d\n", sheet->data[0],sheet->data[1],sheet->data[2],sheet->data[3]);

    for (y=0; y<sheet->high; y++)
    {
        for (x=0; x<sheet->wide; x++)
        {
            if (alphaAt (sheet,x,y) != 0)
            {
                floodFindBounds (sheet, x,y, &fullList[n_in_list]);
                wipeout (sheet, &fullList[n_in_list]);
                n_in_list++;
            }
        }
    }

    printf ("found %d sprites:\n", n_in_list);
    for (x=0; x<n_in_list; x++)
        printf ("  %d,%d,%d,%d\n", fullList[x].x,fullList[x].y,fullList[x].wide,fullList[x].high);
    return 0;
}
person Jongware    schedule 27.01.2014
comment
+1 Спасибо! Давненько я не программировал на C, но буду разбираться :) - person user2336315; 27.01.2014