在 flash 中,任何形状的元件都是被包含在一个完整的矩形容器里的,此碰撞算法就是根据这一点来获取两个不规则形状的交集,这么说可能你听起来有些不明白,我们来进一步解释一下。
假如我们这里有两个不规则形状的 MC ,即 mc1 和 mc2 。如下图:
为了更方便于的理解,我将形状做在的容器 mc1 和 mc2 用单色的矩形来表示,如下图:
此时我们可以很明显的看到两个矩形的交集,根据 mc1 和 mc2 深度不同,可以有以下两种情况:
通过观察以上两张图,我们可以发现,除了交集的部分,其他地方的像素值 BitmapData 是完全相同的,也就是说,当两个 MC 存在交集 ( 即碰撞 ) 的时候,交集部分的像素值会不同,当然,如果在这个交集部分,两个 MC 都没像素,这中情况,我们认为这两个 MC 是没有碰撞的。
进而,我们可以这么想,将两个容器矩形的合集放在一个 BitmapData 中。代码中,我们可以通过 copyPixels 来实现。
这样根据 mc1 和 mc2 的深度不同,我们可以得到两个合集的 BitmapData ,然后我们将这两个合集里的像素值进行相减得到 resultBitmapData ,代码中可以通过 BitmapData 类的 compare 来实现,存在以下两种情况:
1, 两个 mc 的交集部分的像素值不同时为空,相减之后,如果结果 resultBitmapData 不为空,则我们可以判断两个 mc 有碰撞,如果结果 resultBitmapData 为空,则我们说,两个 mc 没有发生碰撞。
2, 两个 mc 的交集部分的像素值同时为空,这样只有一种结果, resultBitmapData 为空,这种情况我们认识两个 mc 是没有发生碰撞的。
综上所述,我们可以根据 resultBitmapData 中的像素值是否为空来判断,两不规则的形状是否发生碰撞。具体 AS 代码实现如下:
package
{
import flash.display. * ;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.events.MouseEvent;
/**
*
* @author 拉登 http://blog.sina.com.cn/ladeng6666
*
* getBitmap():void
* 获得两个mc的BitmapData数据
* getMaxRect():void
* 创建两个mc的BitmapData合集combineBtmpd1和combineBtmpd2
* compareRect():void
* 按不同顺序将两个mc的数据copy到合集combineBtmpd1和combineBtmpd2
* 中去,然后将两个合集相减,得到交集
*/
public class Main extends Sprite
{
private var btmpd1 :BitmapData;
private var btmpd2 :BitmapData;
private var combinebtmpd1 :BitmapData;
private var combinebtmpd2 :BitmapData;
private var intersectionBtmpd;
private var intersectionRect :Rectangle;
private var hintRect :Sprite;
public function Main()
{
// 让mc1元件具有按钮模式,去掉mc2的Mouse事件
mc1.buttonMode = true ;
mc2.mouseEnabled = false ;
// 添加mc1的鼠标事件,用来拖动
mc1.addEventListener(MouseEvent.MOUSE_DOWN, dragHandle);
// 让mc2停在第一帧上,表示没有碰撞
mc2.gotoAndStop( 1 );
hintRect = new Sprite();
hintRect.graphics.lineStyle( 2 , 0 , 1 , false , LineScaleMode.NONE);
hintRect.graphics.drawRect( 0 , 0 , 10 , 10 );
addChild(hintRect);
// hintRect.graphics.
}
private function getBitmap(): void {
// 使用BitmapData的draw方法,获得mc1的BitmapData数据
btmpd1 = new BitmapData(mc1.width, mc1.height, true , 0 );
btmpd1.draw(mc1, null , new ColorTransform( 125 , 125 , 125 , 1 ));
// 使用BitmapData的draw方法,获得mc2的BitmapData数据
btmpd2 = new BitmapData(mc2.width, mc2.height, true , 0 );
btmpd2.draw(mc2, null , new ColorTransform( 0 , 0 , 0 , 1 ));
}
private function getMaxRect(): void {
// 得到mc1,mc2所在的容器矩形合集,并生成两个相同新的bitmapdata,bc1,bc2,以便稍后相比较
var combineX = (mc1.x > mc2.x) ? mc2.x:mc1.x;
var combineY = (mc1.y > mc2.y) ? mc2.y:mc1.y;
var combineWidth = (mc1.x > mc2.x) ? (mc1.x - mc2.x + mc1.width):(mc2.x - mc1.x + mc2.width);
var combineHeight = (mc1.y > mc2.y) ? (mc1.y - mc2.y + mc1.height):(mc2.y - mc1.y + mc2.height);
// 创建两个大小完全相同的合集BitmapData,以便后面进行比较
combinebtmpd1 = new BitmapData(combineWidth, combineHeight, true , 0xff0000 );
combinebtmpd2 = new BitmapData(combineWidth, combineHeight, true , 0x000000 );
}
private function compareRect(): void {
// 这里要解释一下,前面讲的是通过两个mc的深度不同,得到的合集也不同,这么讲只是为了便于理解
// 事实上这里我们是是通过BitmapData类的copyPixels方法,不同顺序的copy两mc的数据实现的
// 先copy mc1,再copy mc2的
combinebtmpd1.copyPixels(btmpd1, btmpd1.rect, new Point( 0 , 0 ), null , null , true );
combinebtmpd1.copyPixels(btmpd2, btmpd2.rect, new Point(mc2.x - mc1.x, mc2.y - mc1.y), null , null , true );
// 先copy mc2,再copy mc1的
combinebtmpd2.copyPixels(btmpd2, btmpd2.rect, new Point(mc2.x - mc1.x, mc2.y - mc1.y), null , null , true );
combinebtmpd2.copyPixels(btmpd1, btmpd1.rect, new Point( 0 , 0 ), null , null , true );
// 交集要随时更新,所以之前的intersection要清除掉
if (typeof(intersectionBtmpd) == " object " ) intersectionBtmpd.dispose();
intersectionBtmpd = combinebtmpd1.compare(combinebtmpd2);
// 如果交集不为零,用框框出来!
if (intersectionBtmpd != 0 ) {
intersectionRect = intersectionBtmpd.getColorBoundsRect( 0xFFFFFF , 0x000000 , false );
hintRect.x = mc1.x + intersectionRect.x;
hintRect.y = mc1.y + intersectionRect.y;
hintRect.width = intersectionRect.width;
hintRect.height = intersectionRect.height;
mc2.gotoAndStop( 2 );
txt.text = " 有碰撞,交集部分相对于mc1的位置是: x: " + intersectionRect.x + " ,y: " + intersectionRect.y + " ,width: " + intersectionRect.width + " ,height: " + intersectionRect.height;
} else {
hintRect.x = - 100 ;
mc2.gotoAndStop( 1 );
txt.text = " 无碰撞 " ;
}
}
private function removeAllBitmapData(){
combinebtmpd1.dispose();
combinebtmpd2.dispose();
combinebtmpd1 = null ;
combinebtmpd2 = null ;
}
private function dragHandle(e:MouseEvent) {
// 鼠标按下后,开始拖到mc1
mc1.startDrag( false );
// 同时对舞台的MOUSE_MOVE事件进行侦听,以便更新碰撞区域的显示
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveHandle);
stage.addEventListener(MouseEvent.MOUSE_UP, upHandle);
}
private function moveHandle(e:MouseEvent) {
getBitmap();
getMaxRect();
compareRect();
}
private function upHandle(e:MouseEvent) {
mc1.stopDrag();
removeAllBitmapData();
stage.removeEventListener(MouseEvent.MOUSE_MOVE, moveHandle);
}
}
}
源文件地址:
http://www.brsbox.com/filebox/down/fc/5433809492a7867ccd5478d5e821015b