【问题标题】:Is there any benefit to using sprite sheets in Java with awt?在带有 awt 的 Java 中使用精灵表有什么好处吗?
【发布时间】:2014-08-21 11:03:13
【问题描述】:

我知道this question 解决了 Flash 的问题,this question 模糊地解决了 OpenGL 等其他渲染引擎的问题。后者通过声明调整图像的 UV 比加载全新图像更容易来断言精灵表的优越性的方式。

我目前从图像加载精灵的方式如下所示

BufferedImage spriteSheet = ImageIO.read(new File("res/sprite.png"));
Image desiredImage = spriteSheet.getSubimage(0, 0, 16, 16);

这不会调整 spriteSheet 的 UV,它会创建图像所需部分的副本,这似乎会占用更多内存。

有没有更好的方式来使用精灵?在这种情况下,使用精灵还是单独加载图像更有效?

【问题讨论】:

  • “会占用更多内存。” - 加载单独的精灵可能会在短期内使用更多内存,因为图像会被解码并转换为内部Java 使用的图像对象的表示。通常,以这种方式进行子映像会更快,并且可能会产生较小的内存负载(而不是读取每个文件),因为图像已经在 J​​ava 使用的内存模型中,但是是的,它会创建一个新的副本父图像的部分。真正的答案将取决于您打算将其用于什么。如果它是短暂的,这可能是可取的
  • 子图像也更快,但仍将归结为图像的使用方式。
  • @MadProgrammer 我通过使用paintComponent(Graphics g) 调用g.drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) 将它们绘制到JPanel
  • 我更多地考虑精灵可能会在内存中保留多长时间
  • @MadProgrammer 一般来说,他们是在组织图像组,而不是单个动画。

标签: java image performance awt sprite-sheet


【解决方案1】:

与普遍看法相反,BufferedImage.getSubimage(...)不会创建图像数据的新副本。它只是“父”图像的(实时)视图。与实际克隆数据阵列相比,这非常快速且便宜。所以,我想说以这种方式使用精灵表是非常有意义的。

对父图像所做的任何更改都将反映在子图像中,反之亦然。来自 javadoc:

返回由指定矩形区域定义的子图像。返回的 BufferedImage 与原始图像共享相同的数据数组。

换句话说,只为每个子图像实例创建一个围绕数据数组的小包装器。验证这一点的最简单方法是尝试在其中一个子图像上绘制并查看是否反映了更改。

正如@MadProgrammer 指出的那样,加载一次大图像可能比加载许多小图像更快且内存效率更高。

但是,有一些问题:

  • 较大的图像将需要较大的连续内存块。这可能是已经运行了一段时间的 Java VM 中的问题,因为可用内存会变得碎片化(在现代 VM 中可能不太成问题,如果您在游戏早期加载一次映像,则根本没有问题) .
  • 创建子图像后,在释放子图像之前无法释放父图像的内存(因为共享数据数组)。如果这不是您想要的,您需要手动创建子图像的副本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-31
    • 2011-04-24
    • 2015-06-21
    • 1970-01-01
    • 2014-10-26
    • 1970-01-01
    • 2012-02-11
    相关资源
    最近更新 更多