Issue loading a sprite sheet

≯℡__Kan透↙ 提交于 2019-12-25 06:55:09

问题


I'm trying to load this spritesheet into an array of buffered image (each sprite into one BufferedImage) :

I opened this file on photoshop. The width is 500 and the height is 666. So according to my calculation, I need to loop 64 times (8 rows and 8 columns) and for each sprite, its width is 500/8 (62.5) and its height is 666/8(83.25). Since getSubImage accepts only int parameters, I was forced to put the width as 62 and the height a 83 (and I think this is why it truncates my images).

Here's the code to load the sprites (I put them in a JFrame to show you the results).

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

Which outputs :

I'm a bit lost (first time I do this) on how I can load every sprite in a BufferedImage. Any ideas?


回答1:


Basically the logic in you for-loop is wrong...

You are multipling the width by the current row (i) and the height by the current col (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);
    }
}

It should be more like...

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

(I increased the height to row 95 for the example)

Now, obviously, you have an issue, as the sprites are different sizes, yea for you. I would suggest creating a simple look up file which contains the row/column as the key and the width/height of the cell, possibly even the x/y, so you can simply pick the sprite straight out, but that's up to you...




回答2:


Here is a very quickly written (and probably dirty) C solution to locate self-containing, non-overlapping sprites. I used a PNG reader to get the data in RGBA format and checked only alpha.

It works like this:

  1. find any non-zero alpha pixel, from top to bottom;
  2. starting at this pixel, form a (min,max) rectangle and keep expanding it until none of the sides contain an alpha pixel;
  3. you end up with a one-pixel wide blank border around the actual sprite, so minx,y has to be increased by 1 and maxx,y decreased -- but that happens in the coordinates-to-size calculation.
  4. finally, this rectangle gets wiped out so next loops won't see this one anymore.

Sprite rectangles may not overlap! (They don't, in this image, but better make sure it happens nowhere else.)

The output list could be sorted on x,y coordinates for clarity; I'm going to leave that, and translating this to Java, to you. This program assumes there may be 64 or less images in a single sheet (struct bounds_t[64]); make sure it's as large as necessary.

C-code (obvious PNG library structures and headers left out):

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


来源:https://stackoverflow.com/questions/21370593/issue-loading-a-sprite-sheet

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!