Setting a spherical area in a BufferedImage to a specific opacity
first of all, I counted Google and SO for this answer, only finding how to change actual pixels with a specific alpha value, which would be incredibly slow, or actually make a part BufferedImage
completely transparent through use lwg2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR))
. This is the exact functionality I need, however I need the value to be less 1f
, which you cannot do with this particular instance AlphaComposite.CLEAR
.
I want this implementation to make the wall inside my 2.5d game transparent when the player walks behind it, like so:
The logic of my game is that the terrain is one BufferedImage
that only updates when called, and then contains the rest of the walls, etc., is drawn onto another BufferedImage
where objects are drawn as well, so the opacity transformation will only affect trees (or walls) ...
This is the code I'm using atm, but as I said, I don't need the circle that I draw to make part of the image completely transparent, but only slightly (about 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);
( does nothing 0.5f
in the constructor AlphaComposite
).
The reason I need this to be efficient is because I am updating this image 30 times per second, so efficiency> quality.
source to share
So, I solved the problem by not manipulating the image directly, making part of the image semi-transparent, but manipulating the opacity of the images I'm drawing with. As @ user343760 and @NESPowerGlove mentioned, I could just make the assets I use semi-transparent when the player is behind it. Since I am using a base lattice array to support my game, I could do this by working if tile.x - 1 == (int) player.x
and tile.y - 1== (int) player.y
. In isometric view, this meant that the player was on the tile directly above him in our perspective. Then I had to solve the problem if wall.z is greater than 0 or 1, so there is a problem when tile 5 blocks "below", the player can hide it if the walls increased by z = 5 above the slab. For this problem, I have implemented the following solution:
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);
}
}
This also ensures that the image is transparent even if the player is "above" the tile "above" the tile where the wall is, in terms of the image extending above that limit. I fixed this with a for loop that looks like above for the i
number of times, depending on image.height/tile_height
, which is a generic constant.
If you need to make part of an image transparent, I have not found a solution that works without glitches, other than manipulating pixels at low levels BufferedImage
. If you also want to remove part of the image directly, use the code g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
and draw as usual. Don't forget to return to your normal composition in g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
.
You can also paint with a certain opacity, using Composite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
, where opacity
- is float
with values of 0f
up to 1f
, 0f
completely transparent and 1f
is completely opaque.
I hope this has helped anyone. If you find a better way to do this, please leave a comment for future readers.
This is my solution looks like this :):
source to share