加载精灵表的问题

时间:2014-01-26 23:20:24

标签: java bufferedimage sprite-sheet

我正在尝试将此spritesheet加载到缓冲图像数组中(每个sprite为一个BufferedImage):

enter image description here

我在photoshop上打开了这个文件。宽度为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);
    }
}

哪个输出:

enter image description here

我有点迷失(我第一次这样做)关于如何加载BufferedImage中的每个精灵。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

基本上你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);
    }
}

Sprites

(我将高度增加到第95行)

现在,显然,你有一个问题,因为精灵的大小不同,是的。我建议创建一个简单的查找文件,其中包含行/列作为键和单元格的宽度/高度,甚至可能是x / y,因此您可以直接选择精灵,但这取决于您。 ..

答案 1 :(得分:1)

这是一个非常快速编写(可能很脏)的C解决方案,用于定位自包含,非重叠的精灵。我使用PNG阅读器获取RGBA格式的数据,并仅检查alpha。

它的工作原理如下:

  1. 从上到下查找任何非零alpha像素;
  2. 从此像素开始,形成一个(最小,最大)矩形并继续展开,直到所有边都不包含像素;
  3. 您最终会在实际精灵周围出现一个像素宽的空白边框,因此minx,y必须增加1并且maxx,y减少 - 但这会发生在坐标到大小的位置计算
  4. 最后,这个矩形被消灭了,所以接下来的循环再也看不到这个了。
  5. 精灵矩形可能重叠! (他们不会,在这张图片中,但更好地确保它在其他任何地方都没有发生。)

    为清楚起见,输出列表可以在x,y坐标上排序;我要离开那个,把它翻译成Java,给你。该程序假设一张纸上可能有64张或更少的图像(struct bounds_t[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;
    }