Reading Pixel Data

I’m trying to figure out how to read pixel data from a BufferedImage (sprite sheet for example) and render it on screen. The main issue is how to associate the color data with coordinates so that I can do collision detection and what not. What is the standard method of reading pixel data and displaying it on screen?

EDIT:
Let’s start with just reading the pixel data from a BufferedImage (for all intents and purposes we will say everything not transparent for now) and then rendering it onto another BufferedImage at a specified x,y coordinate. Can anyone show me how to do that through manipulation of the Raster and/or setRGB() methods?

You don’t need to access the pixel data to draw a BufferedImage to the screen. Just pass the BufferedImage to Graphics.drawImage, and it will draw it. If you want to access the pixel data for collision detection, use the BufferedImage.getRGB method :slight_smile:

I know about Graphics.drawImage. The issue with that is using rectangles as collision bounds is clunky and unappealing. I want to set the ARGB values for one BufferedImage to the canvas BufferedImage at their respective coordinates on screen.

Collision != rendering.

Use whatever data type you want for collision, but as everything, the entity has an X, Y, width, and a height.

Use Graphics.drawImage for drawing, use whatever data type you want for collision.

However, I fail to see how rectangle collision is clunky and unappealing. If your images are nowhere close to rectangularly-shaped, rectangle intersect check would be innacurate…not clunky.

Maybe use a Circle v. Circle check?

Can’t you just pick the non transparent pixels and do a bitwise & when the rectangle intersect to get precise collision?

Pixel perfect collision is very a very expensive calculation. However, how would you use bitwise operations in this circumstance?

When you load a sprite, grab pixels into boolean “collision mask” array ( transparent = 0, non-transparent = 1 ).

Check collisions based on rectangles. When rectangles intersect, copy intersected area of collision mask from object A and check it with object B’s mask.

Should work, no?

Perhaps not the optimal solution, especially with larger sprites. :stuck_out_tongue:

It’d be much quicker to traverse the pixel arrays in the intersected area and check their alpha values instead of copying into a boolean array then checking for mask.

Indeed.

[EDIT]: Actually, is this really as expensive as you make it sound?

I think I’m going to try it out :>

@OP if you want to use pixel perfect collision, I could post my code if you want.

I think this code demonstrates what you’re asking for. I’m not saying this is the best way to do collision detection. I’m just trying to help answer your question.

Explanation: Notice that the red, green, blue values are not used here (just for demonstration). The alphaThreshold is arbitrary [0…255]. If using bitmask transparency, then just set this to zero. If using translucent transparency (for example, if your graphics have anti-aliased edges), setting this higher will avoid collision detection on very transparent parts. The meaning of add to collision matrix is whatever data structure you want to keep for the collision detection. (My original method actually constructs a rectangular bounding box for every non-transparent pixel in the image, but I edited that out for demonstration, and because you’re asking about per-pixel transparency detection.)


int R_BAND = 0;
int G_BAND = 1;
int B_BAND = 2;
int A_BAND = 3;
int alphaThreshold = 64;
int w = image.getWidth();
int h = image.getHeight();
Raster raster = bufferedImage.getRaster();
for (int x = 0; x < w; x++)
{
    for (int y = 0; y < h; y++)
    {
        int r = raster.getSample(x,y,R_BAND);
        int g = raster.getSample(x,y,G_BAND);
        int b = raster.getSample(x,y,B_BAND);
        int a = raster.getSample(x,y,A_BAND);
        if (a > alphaThreshold)
        {
            // add to collision matrix
        }
    }
}

Yes but the collision has to be done using the image bounds. Circle v. Circle isn’t supported in default Java, and would require some heavy math calculations to find intersection points, possibly damaging performance.

Based off of reading your discussion so far, I’m going to ask this question: does Java have a built in convenience method for returning the rectangle formed by two rectangles intersecting? If not, I’m sure we can figure out a way to do so fairly easily…

Read OP for some clarifications I made.

Circle v. Circle is the cheapest collision check there is…

Returning intersection is also super easy :stuck_out_tongue:

I would post code but I’m on my phone.

Refer to the Javadocs for java.awt.Rectangle. Have a look at Rectangle.add(…) and Rectangle.intersects(…)

Hmm… I stand corrected then. Post your code when you are able.

Please do.

Wouldn’t Rectangle2D.createIntersection(Rectangle2D) also work?

My working collision detection code:


public static boolean intersect(Entity e1, Entity e2) {
	if(e1.getBounds().intersects(e2.getBounds())) {
		Entity leftMost = e1.getX() < e2.getX() ? e1 : e2;
		Entity rightMost = e2.getX() < e1.getX() ? e1 : e2;
		
		Entity topMost = e1.getY() < e2.getY() ? e1 : e2;
		Entity bottomMost = e2.getY() < e1.getY() ? e1 : e2;
		
		int left = rightMost.getX() - leftMost.getX();
		int top = bottomMost.getY() - topMost.getY();
		int width = leftMost.getWidth() - left;
		int height = topMost.getHeight() - top;
		
		//RGBA format
		byte[] leftData = leftMost.getImageData();
		byte[] rightData = rightMost.getImageData();
		
		int leftTop = leftMost == topMost ? top : 0;
		int rightTop = rightMost == topMost ? top : 0;
		
		for(int y = 0; y < height; y++) {
			for(int x = 0; x < width; x++) {
				//If it is ARGB, remove the "3 + "
				int leftIdx = 3 + 4 * (x + left + (y + leftTop) * leftMost.getWidth());
				int rightIdx = 3 + 4 * (x + (y + rightTop) * rightMost.getWidth());
				
				if(!((leftData[leftIdx] & 0xff) < 100 || (rightData[rightIdx] & 0xff) < 100))
					return true;
			}
		}
		
		return false;
	}
	
	return false;
}