Pixel-Perfect Collision Detection. There’s a lot of demand for this type of endeavor but there arn’t any specific examples on how people can get it to work for themselves. In an effort to help others where I struggled, here’s a rundown on how to get pixel-perfect detection with Java.
I’ll be basing this on this link: http://www.gamedev.net/reference/articles/article754.asp
The guy who wrote it, TANSTAAFL, lays out the math and other concepts pretty clear so I won’t get much into that. I’m just going to go over how to get your bitmask layer and how to use it like he recommends.
- Load the image and get it’s data into a byte array:
// Get the image's data.
private byte[] getData(String ref)
{
BufferedImage sprite = null;
URL absoluteRef = null;
try
{
absoluteRef = ImageThingie.class.getClassLoader().getResource(ref);
if(absoluteRef == null)
System.out.println("No URL? Classloader failed?");
sprite = ImageIO.read(absoluteRef);
}
catch(Exception e)
{
System.out.println("ERROR: File " + ref + " not found.");
// Just exit out of the image isn't found. It's pretty essential to the program so don't bother trying to run without it.
System.exit(0);
}
imageWidth = sprite.getWidth();
imageHeight = sprite.getHeight();
// Force RGBA.
// If it's not RGBA, well, screw it.
ColorModel glAlphaColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
new int[] {8,8,8,8},
true,
false,
ComponentColorModel.TRANSLUCENT,
DataBuffer.TYPE_BYTE);
WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, imageWidth,imageHeight, 4, null);
BufferedImage texImage = new BufferedImage(glAlphaColorModel, raster, false, new Hashtable());
Graphics2D g = (Graphics2D)texImage.getGraphics();
g.drawImage(sprite, 0, 0, null);
g.dispose();
return ((DataBufferByte)texImage.getRaster().getDataBuffer()).getData();
}
- When you read an image like this, it dumps all of it’s information into a byte array. Each pixel’s data is 4 elements long in the array. The first element holds the pixel’s Red saturation, the second is Green, third is Blue, and the last is the Alpha. For collision detection, we only need to worry about the alpha value. So, we’re going to strip it out of the image’s data.
byte imageData[] = getData(FILENAME);
byte alpha[] = new byte[IMAGEWIDTH * IMAGEHEIGHT];
// -1 is a pixel. Anything else is transparant or an alpha value.
int count = 0;
for(int i = 0; i < imageData.length; i++)
{
if(i % 4 == 0 && i != 0)
{
alpha[count] = imageData[i-1];
count++;
}
}
Now that you have an array of the image’s alpha value, you can refer back to GameDev link above and apply your collision detection technique.
If you’re doing rotational collision detection, things get a little more complicated, but the gist of things remains the same. To rotate a position in an array, you can do something like this (Note: The below is pseudocode. It won’t really work- you’re going to have to use this as a guideline for how you want your rotations to be done.):
byte rotationLayer[][] = new byte[IMAGEWIDTH][IMAGEHEIGHT];
int imageX = TRANSLATED_WORLD_X;
int imageY = TRANSLATED_WORLD_Y;
int angle = SPRITE_ANGLE;
double cos = Math.cos(Math.toRadians(angle));
double sin = Math.sin(Math.toRadians(angle));
for(int x = 0; x < IMAGEWIDTH; x++)
{
for(int y = 0; y < IMAGEHEIGHT; y++)
{
if(alpha[x][y] == -1)
{
int currentX = x + imageX;
int currentY = y + imagey;
int nextX = (int)((currentX * cos) - (currentY * sin));
int nextY = (int)((currentX * sin) + (currentY * cos));
if(nextX >= 0 && nextX < imageWidth && nextY >= 0 && nextY < imageHeight)
{
// -1 = pixel
rotationLayer[nextX][nextY] = -1;
}
}
}
}
When this is done, the byte array named rotationLayer will have the alpha data of the sprite when it’s rotated. You can then use this array to check against another ‘rotationLayer’ and do the same collision detection technique as you use for non-rotated images. The catch here however, is figuring out how to translate these coordinates into your gaming world so you can find the point of collision outside of just having a position in the array.
Later, I’ll be posting a webstartable application that loads an image and dumps it’s data into an HTML file. You’ll be able to rotate the image and whatnot so you guys can get a nice feel for how things are supposed to go. Expect that later this week. For now, I’ve got a busy weekend ahead of me outside the coding world.
I hope this helped some people. Feel free to PM me with questions or comments. I’ll try to do my best and help.
Edit: Whoops, I doubleposted before I was finished writing. I deleted the old one.