How can I get the upper, bottom, rightmost and leftmost point of a pixel-perfect BitmapData collision? This is my collision-detection code:
public static function checkCollision(object1:*, object2:*, debug:Boolean = false):Boolean{
var object1Rect:Rectangle = object1.getRect(stage);
var object2Rect:Rectangle = object2.getRect(stage);
var object1Point:Point = new Point(object1Rect.x, object1Rect.y);
var object2Point:Point = new Point(object2Rect.x, object2Rect.y);
var bitmapData1:BitmapData = new BitmapData(
object1Rect.width,
object1Rect.height,
true,
0
);
var bitmapData2:BitmapData = new BitmapData(
object2Rect.width,
object2Rect.height,
true,
0
);
var clr:ColorTransform = new ColorTransform();
if(debug)
clr.color = 0x00ff00;
bitmapData1.draw(object1, new Matrix(1, 0, 0, 1, -object1Rect.x, -object1Rect.y), clr);
bitmapData2.draw(object2, null, clr);
if(debug){
if(bmp1.stage)
stage.removeChild(bmp1);
bmp1 = new Bitmap(bitmapData1);
bmp1.x = object1Point.x;
bmp1.y = object1Point.y;
stage.addChild(bmp1);
if(bmp2.stage)
stage.removeChild(bmp2);
bmp2 = new Bitmap(bitmapData2);
bmp2.x = object2Point.x;
bmp2.y = object2Point.y;
stage.addChild(bmp2);
}
var bCollide:Boolean = bitmapData1.hitTest(
object1Point,
255,
bitmapData2,
object2Point,
255
);
if(!debug){
bitmapData1.dispose();
bitmapData2.dispose();
}
return bCollide;
}
And it works perfeclty fine. However, the code I use to detect the top hitpoint doesn't work properly. This is the code:
public static function getHitPoint(object1:*, object2:*):Point{
var point:Point = new Point();
var object1Rect:Rectangle = object1.getRect(stage);
var object2Rect:Rectangle = object2.getRect(stage);
var object1Point:Point = new Point(object1Rect.x, object1Rect.y);
var object2Point:Point = new Point(object2Rect.x, object2Rect.y);
var bitmapData1:BitmapData = new BitmapData(
object1.width,
object1.height,
true,
0
);
var bitmapData2:BitmapData = new BitmapData(
object2.width,
object2.height,
true,
0
);
bitmapData1.draw(object1, new Matrix(1, 0, 0, 1, -object1Rect.x, -object1Rect.y));
bitmapData2.draw(object2);
var bitmap1:Bitmap = new Bitmap(bitmapData1);
var bitmap2:Bitmap = new Bitmap(bitmapData2);
bitmap1.x = object1Point.x;
bitmap1.y = object1Point.y;
bitmap2.x = object2Point.x;
bitmap2.y = object2Point.y;
var bitmapOrigin:Point = new Point(object1Point.x, object1Point.y);
var bitmap2OriginLocal:Point = bitmap2.globalToLocal(bitmapOrigin);
var overlappingPixels:Vector.<uint> = bitmap2.bitmapData.getVector(
new Rectangle(bitmap2OriginLocal.x, bitmap2OriginLocal.y, object1Rect.width, object1Rect.height)
);
for(var i:String in overlappingPixels){
var index:uint = uint(i);
if(overlappingPixels[i] != 0){
point.x = (index % object1.width) + (bitmap2.x > bitmap1.x ? bitmap2.x : bitmap1.x);
point.y = (uint(index / bitmap1.height)) + (bitmap2.y > bitmap1.y ? bitmap2.y : bitmap1.y);
break;
}
}
return point;
}
I've got no idea why, but the getHitPoint()
function sometimes returns the wrong coordinates. Can anyone please explain why that is? And how can I detect the bottommost, the leftmost and the rightmost hitpoint?
Edit
I now know why getHitPoint()
sometimes returned a wrong value: point.y = (uint(index / bitmap1.height)) + (bitmap2.y > bitmap1.y ? bitmap2.y : bitmap1.y);
should be point.y = (uint(index/bitmap1.
width
)) + (bitmap2.y > bitmap1.y ? bitmap2.y : bitmap1.y);
Edit 2
I found out how to get the bottom hitpoint:
public static function getHitPoint(object1:*, object2:*, direction:int = 0):*{
var point:Point = new Point();
var object1Rect:Rectangle = object1.getRect(stage);
var object2Rect:Rectangle = object2.getRect(stage);
var object1Point:Point = new Point(object1Rect.x, object1Rect.y);
var object2Point:Point = new Point(object2Rect.x, object2Rect.y);
var bitmapData1:BitmapData = new BitmapData(
Math.round(object1Rect.width),
Math.round(object1Rect.height),
true,
0
);
var bitmapData2:BitmapData = new BitmapData(
Math.round(object2Rect.width),
Math.round(object2Rect.height),
true,
0
);
bitmapData1.draw(object1, new Matrix(1, 0, 0, 1, -object1Rect.x, -object1Rect.y));
bitmapData2.draw(object2);
var bitmap1:Bitmap = new Bitmap(bitmapData1);
var bitmap2:Bitmap = new Bitmap(bitmapData2);
bitmap1.x = object1Point.x;
bitmap1.y = object1Point.y;
bitmap2.x = object2Point.x;
bitmap2.y = object2Point.y;
var bitmapOrigin:Point = new Point(object1Point.x, object1Point.y);
var bitmap2OriginLocal:Point = bitmap2.globalToLocal(bitmapOrigin);
var overlappingPixels:Vector.<uint> = bitmap2.bitmapData.getVector(
new Rectangle(bitmap2OriginLocal.x, bitmap2OriginLocal.y, object1Rect.width, object1Rect.height)
);
switch(direction){
case 0: //top
for(var i:String in overlappingPixels){
var index:uint = uint(i);
if(overlappingPixels[i] != 0){
point.x = (index % bitmap1.width) + (bitmap2.x > bitmap1.x ? bitmap2.x : bitmap1.x);
point.y = (uint((index)/bitmap1.width)) + (bitmap2.y > bitmap1.y ? bitmap2.y : bitmap1.y);
return point;
}
}
case 1: //right
// I still need this
case 2: //bottom
overlappingPixels.reverse();
for(var i:String in overlappingPixels){
var index:uint = uint(i);
if(overlappingPixels[i] != 0){
point.x = bitmap1.width - (index % bitmap1.width) + (bitmap2.x > bitmap1.x ? bitmap2.x : bitmap1.x);
point.y = (bitmap2.y + bitmap2.height > bitmap1.y + bitmap1.height ? bitmap1.y + bitmap1.height : bitmap2.y + bitmap2.height) - (uint(index/bitmap1.width));
return point;
}
}
case 3: //left
// I still need this too
}
return false;
}
I still need a way to get the left and rightmost hitpoints though
You don't need to do it like you're doing there. You can do it all within a single function, which returns everything back correctly. I've added comments to the below. Please take note of what I've changed, as when you're trying to do it as you're doing now, with the code you changed, it is impossible.
This works for any shape, any direction. It'll give you the exact X and Y of the collision.
Please do not make this into a static function. Put it into a global class and use a Singleton to manage it instead. Things start to go very badly wrong when you being using static functions and reference the stage.
Also, if you're going to be working with pixel values of less than 1 (ie 99.75), the below will need a bit of adapting to cater for that. I've assumed you're using whole pixels, given your Math.round usage.
For context, my entire class is below which shows how I was using this function. You can copy/paste this class and it will work. It shows how you move sprites around the screen, once it finds a collision, then it works out where the collision took place.
This class is for absolute pixel perfect collision detection, including an example.