如何在AS3中测试矩形和不规则对象之间的碰撞?那么我怎样才能获得重叠的最低y值(顶部)?
修改
非常感谢您的回答,但checkCollision
方法始终返回false。这是我的代码:
public static function checkCollision(object1:*, object2:*):Boolean{
var object1Rect:Rectangle = object1.getRect(stage);
var object2Rect:Rectangle = object2.getRect(stage);
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);
bitmapData2.draw(object2);
var bCollide:Boolean = bitmapData1.hitTest(
new Point(object1Rect.x, object1Rect.y),
255,
bitmapData2,
new Point(object2Rect.x, object2Rect.y),
255
);
bitmapData1.dispose();
bitmapData2.dispose();
return bCollide;
}
答案 0 :(得分:1)
如果它是一个复杂的形状,请使用如下所示的bitmapdata。这适用于所有形状。
如果您仍然需要知道最低Y值,请不要忘记它也可能在X上。还有一个额外的函数(getHitPoint)来计算它,只需要在成功的命中测试中运行。它可以通过将原始函数中的位图数据传递到其中进行优化,但我将其保持独立以帮助它保持可读性。
package kazo
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* ...
* @author KM
*/
public class TestCases extends Sprite
{
private var rect :Sprite;
private var circle :Sprite;
public function TestCases() { }
/**
* Start the test case
*/
public function start():void {
trace('Starting test case');
// Rectangle
rect = new Sprite();
// Circle
circle = new Sprite();
// Draw the rectangle. Center point must be TOP LEFT
// If you're using Flash Professional, place everything at 0,0 inside the MC
rect.graphics.beginFill(0xff0000);
rect.graphics.drawRect(0, 0, 100, 100);
rect.graphics.endFill();
// Draw the circle. Center point is TOP LEFT, so the X and Y of the circle need to be equal to the radius
circle.graphics.beginFill(0xffff00);
circle.graphics.drawCircle(50, 50, 50);
circle.graphics.endFill();
// Add them
addChild(rect);
addChild(circle);
// Position
rect.x = 0;
rect.y = 100;
// Position
circle.y = 400;
circle.x = 0;
// Frame loop
addEventListener(Event.ENTER_FRAME, frameFunc);
}
/**
*
* @param e
*/
private function frameFunc(e:Event):void {
// move them around
rect.y += 1;
circle.y -= 1;
circle.x += 1;
rect.x += 1;
// Check for collisions. If found, stop. Pass 'true' as the final param if you want it to draw to the screen
if (checkCollision(rect, circle)) {
trace(getHitPoint(rect, circle));
removeEventListener(Event.ENTER_FRAME, frameFunc);
}
}
/**
*
* @param _obj1
* @param _obj2
* @param _debug
* @return
*/
private function checkCollision(_obj1:Sprite, _obj2:Sprite, _debug:Boolean = false):Boolean {
// Draw the first item to bitmapdata
var bmd1:BitmapData = new BitmapData(_obj1.width, _obj1.height, true, 0);
// ..and the second
var bmd2:BitmapData = new BitmapData(_obj2.width, _obj2.height, true, 0);
// Now draw them
bmd1.draw(_obj1);
bmd2.draw(_obj2);
// If we're in debug, also add the bitmap to the stage so we can see where we are
if (_debug) {
var bmp:Bitmap = new Bitmap(bmd1);
bmp.x = _obj1.x;
bmp.y = _obj1.y;
addChild(bmp);
var bmp2:Bitmap = new Bitmap(bmd2);
bmp2.x = _obj2.x;
bmp2.y = _obj2.y;
addChild(bmp2);
}
// Hit test including alpha channel. Obj1 X/Y, Obj2 X/Y, alpha channel
var rtn:Boolean = bmd1.hitTest(new Point(_obj1.x, _obj1.y), 255, bmd2, new Point(_obj2.x, _obj2.y), 255);
// Dispose the bitmap data, we dont need it anymore
if (!_debug) {
bmd1.dispose();
bmd2.dispose();
}
// Return the boolean
return rtn;
}
/**
* This ONLY needs to be called once a collision has been confirmed. Don't run this on every frame!
* @return
*/
private function getHitPoint(_obj1:Sprite, _obj2:Sprite, _debug:Boolean = false):Point {
var rtnPoint:Point = new Point();
// Draw the first item to bitmapdata
var bmd1:BitmapData = new BitmapData(_obj1.width, _obj1.height, true, 0);
// ..and the second
var bmd2:BitmapData = new BitmapData(_obj2.width, _obj2.height, true, 0);
// Now draw them
bmd1.draw(_obj1);
bmd2.draw(_obj2);
// Create two bitmaps
var bmp1:Bitmap = new Bitmap(bmd1);
var bmp2:Bitmap = new Bitmap(bmd2);
// Position
bmp1.x = _obj1.x;
bmp2.x = _obj2.x;
bmp1.y = _obj1.y;
bmp2.y = _obj2.y;
// Get the origins
var bitmapOrigin:Point = new Point(_obj1.x, _obj1.y);
var bitmapTwoOriginLocal:Point = bmp2.globalToLocal(bitmapOrigin);
// Find all the overlapping pixels
var overlappingPixels:Vector.<uint> = bmp2.bitmapData.getVector(new Rectangle(bitmapTwoOriginLocal.x, bitmapTwoOriginLocal.y, _obj1.width, _obj1.height));
var i:uint = 0;
var len:uint = overlappingPixels.length;
// Run through them all until we find a non-zero value
for(i; i < len; i++) {
if(overlappingPixels[i] != 0) {
// Our X collision is i % _obj1.width plus whichever X value is highest
rtnPoint.x = (i % _obj1.width) + (bmp2.x > bmp1.x ? bmp2.x : bmp1.x);
// Our Y collision is i / _obj1.height plus whichever Y value is highest
rtnPoint.y = (uint((i + 1) / _obj1.width)) + (bmp2.y > bmp1.y ? bmp2.y : bmp1.y);
// If debug, draw the collision point
if (_debug) {
var test:Sprite = new Sprite();
test.graphics.beginFill(0x008c6f);
test.graphics.drawRect(rtnPoint.x , rtnPoint.y, 10, 10);
test.graphics.endFill();
addChild(test);
}
break;
}
}
// Send it back
return rtnPoint;
}
}
}