在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