有效地将 BufferedImage 中的球形区域设置为一定的不透明度
Setting a spherical area in a BufferedImage to be a certain opacity efficently
首先,我搜索了 Google 和 SO 这个答案,只发现如何将实际像素更改为某个 alpha 值,这将非常慢或实际上成为BufferedImage
完全 通过使用 lwg2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR))
透明。这正是我需要的功能,但是,我需要使该值小于 1f
,而您不能使用 AlphaComposite.CLEAR
.
的这个特定实例来做到这一点
我想要这个实现的目的是让我的 2.5d 游戏中的墙在玩家走到它后面时变得透明,就像这样:
我的游戏背后的逻辑是,地形是一个 BufferedImage
,只有在调用时才会更新,然后将其余的墙等绘制到另一个 BufferedImage
实体上也被绘制,所以不透明度变换只会影响树木(或墙壁)。
这是我使用 atm 的代码,但正如我所说,我不希望我正在绘制的圆圈使图像的一部分完全透明,但只是稍微透明(大约 50%):
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.5f));
g2.fillOval(x - (int) (TILE_WIDTH * 1), y - (int) (TILE_HEIGHT * 1.5), TILE_WIDTH * 2, TILE_HEIGHT * 3);
(AlphaComposite
构造函数中的 0.5f
什么都不做)。
我之所以需要它来提高效率,是因为我每秒更新此图像 30 次,所以效率 > 质量。
所以,我最终解决了这个问题,不是通过使图像的一部分变成半透明来直接操纵图像,而是操纵我正在绘制的图像的不透明度。正如@user343760 和@NESPowerGlove 提到的,当玩家在它后面时,我可以让我正在使用的资产变成半透明的。因为我使用底层网格数组来支持我的游戏,所以我可以通过计算 tile.x - 1 == (int) player.x
和 tile.y - 1== (int) player.y
来实现。在等轴测图中,这意味着玩家在我们的视角中正位于其正上方的方块上。然后我必须解决 wall.z 大于 0 或 1 的问题,因此如果墙壁在瓷砖上方延伸 z = 5,玩家可能会阻碍他,如果瓷砖 5 块 "bellow" .针对这个问题,我实现了以下解决方案:
for(int i = 0; i < wall.getAsset(1f).getHeight()/TILE_HEIGHT; i++) {
if((tile.x - i - wall.z == (int) world.player.getX() && tile.y - i -wall.z == (int) world.player.getY())) {
lwg2.drawImage(wall.getAsset(0.5f), x, y, this);
}
}
即使玩家是 "above" 瓦片 "above" 墙所在的瓦片,这也确保了图像是透明的,因为图像超出了该限制。我已经通过使用 for 循环修复了这个问题,它在上面查找 i
次,具体取决于 image.height/tile_height
,这是一个通用常数。
如果您需要使图像的一部分透明,除了在 BufferedImage
的低级别中操纵像素外,我还没有找到可以无故障运行的解决方案。如果您还想直接擦除图像的一部分,请使用代码 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
并像往常一样绘制。请记住通过 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
.
切换回普通合成
您也可以首先使用 Composite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
以一定的不透明度进行绘制,其中 opacity
是一个 float
,其值来自 0f
到 1f
,0f
完全透明,1f
完全不透明。
我希望这对那里的任何人都有帮助。如果您找到更好的方法,请为未来的读者发表评论。
这就是我的解决方案:):
首先,我搜索了 Google 和 SO 这个答案,只发现如何将实际像素更改为某个 alpha 值,这将非常慢或实际上成为BufferedImage
完全 通过使用 lwg2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR))
透明。这正是我需要的功能,但是,我需要使该值小于 1f
,而您不能使用 AlphaComposite.CLEAR
.
我想要这个实现的目的是让我的 2.5d 游戏中的墙在玩家走到它后面时变得透明,就像这样:
我的游戏背后的逻辑是,地形是一个 BufferedImage
,只有在调用时才会更新,然后将其余的墙等绘制到另一个 BufferedImage
实体上也被绘制,所以不透明度变换只会影响树木(或墙壁)。
这是我使用 atm 的代码,但正如我所说,我不希望我正在绘制的圆圈使图像的一部分完全透明,但只是稍微透明(大约 50%):
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.5f));
g2.fillOval(x - (int) (TILE_WIDTH * 1), y - (int) (TILE_HEIGHT * 1.5), TILE_WIDTH * 2, TILE_HEIGHT * 3);
(AlphaComposite
构造函数中的 0.5f
什么都不做)。
我之所以需要它来提高效率,是因为我每秒更新此图像 30 次,所以效率 > 质量。
所以,我最终解决了这个问题,不是通过使图像的一部分变成半透明来直接操纵图像,而是操纵我正在绘制的图像的不透明度。正如@user343760 和@NESPowerGlove 提到的,当玩家在它后面时,我可以让我正在使用的资产变成半透明的。因为我使用底层网格数组来支持我的游戏,所以我可以通过计算 tile.x - 1 == (int) player.x
和 tile.y - 1== (int) player.y
来实现。在等轴测图中,这意味着玩家在我们的视角中正位于其正上方的方块上。然后我必须解决 wall.z 大于 0 或 1 的问题,因此如果墙壁在瓷砖上方延伸 z = 5,玩家可能会阻碍他,如果瓷砖 5 块 "bellow" .针对这个问题,我实现了以下解决方案:
for(int i = 0; i < wall.getAsset(1f).getHeight()/TILE_HEIGHT; i++) {
if((tile.x - i - wall.z == (int) world.player.getX() && tile.y - i -wall.z == (int) world.player.getY())) {
lwg2.drawImage(wall.getAsset(0.5f), x, y, this);
}
}
即使玩家是 "above" 瓦片 "above" 墙所在的瓦片,这也确保了图像是透明的,因为图像超出了该限制。我已经通过使用 for 循环修复了这个问题,它在上面查找 i
次,具体取决于 image.height/tile_height
,这是一个通用常数。
如果您需要使图像的一部分透明,除了在 BufferedImage
的低级别中操纵像素外,我还没有找到可以无故障运行的解决方案。如果您还想直接擦除图像的一部分,请使用代码 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
并像往常一样绘制。请记住通过 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
.
您也可以首先使用 Composite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
以一定的不透明度进行绘制,其中 opacity
是一个 float
,其值来自 0f
到 1f
,0f
完全透明,1f
完全不透明。
我希望这对那里的任何人都有帮助。如果您找到更好的方法,请为未来的读者发表评论。
这就是我的解决方案:):