我知道this question解决了闪存和 this question 的问题模糊地解决了 OpenGL 等各种渲染引擎的问题。后者通过声明调整图像的 UV 比加载整个新图像更容易来断言 Sprite 表的优越性。
我当前从图像加载 Sprite 的方式如下所示
BufferedImage spriteSheet = ImageIO.read(new File("res/sprite.png"));
Image desiredImage = spriteSheet.getSubimage(0, 0, 16, 16);
这不会调整 spriteSheet
的 UV,它会创建图像所需部分的副本,这看起来会占用更多内存。
有更好的方法来使用 Sprite 吗?在这种情况下,使用 Sprite 或仅单独加载图像是否更有效?
最佳答案
与普遍看法相反,BufferedImage.getSubimage(...)
不会创建图像数据的新副本。它只是“父”图像的(实时) View 。与实际克隆数据数组相比,这非常快速且便宜。所以,我想说以这种方式使用 Sprite 表是完全有意义的。
对父图像所做的任何更改都将反射(reflect)在子图像中,反之亦然。来自javadoc:
Returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image.
换句话说,仅为每个子图像实例创建数据数组周围的一个小包装器。验证这一点的最简单方法是尝试在其中一个子图像上绘制并查看更改是否得到反射(reflect)。
正如 @MadProgrammer 指出的那样,加载一次大图像可能比加载许多小图像更快、内存效率更高。
但是,有一些问题:
- 较大的图像将需要较大的连续内存块。这可能是已经运行了一段时间的 Java VM 中的一个问题,因为可用内存会变得碎片化(在现代 VM 中问题可能较少,而且如果您在游戏早期加载一次镜像,则根本没有问题)。
- 创建子图像后,在释放子图像之前无法释放父图像的内存(因为共享数据数组)。如果这不是您想要的,您需要手动创建子图像的副本。
关于java - 在 Java 中通过 awt 使用 Sprite 表有什么好处吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24500899/