像素级碰撞的一种算法

来源:互联网 发布:wordpress适合优化吗 编辑:程序博客网 时间:2024/06/07 03:29

    在flash中,任何形状的元件都是被包含在一个完整的矩形容器里的,此碰撞算法就是根据这一点来获取两个不规则形状的交集,这么说可能你听起来有些不明白,我们来进一步解释一下。

假如我们这里有两个不规则形状的MC,即mc1mc2。如下图:

为了更方便于的理解,我将形状做在的容器mc1mc2用单色的矩形来表示,如下图:

此时我们可以很明显的看到两个矩形的交集,根据mc1mc2深度不同,可以有以下两种情况:

通过观察以上两张图,我们可以发现,除了交集的部分,其他地方的像素值BitmapData是完全相同的,也就是说,当两个MC存在交集(即碰撞)的时候,交集部分的像素值会不同,当然,如果在这个交集部分,两个MC都没像素,这中情况,我们认为这两个MC是没有碰撞的。

进而,我们可以这么想,将两个容器矩形的合集放在一个BitmapData中。代码中,我们可以通过copyPixels来实现。

这样根据mc1mc2的深度不同,我们可以得到两个合集的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(
201false, LineScaleMode.NONE);
            hintRect.graphics.drawRect(
001010);
            addChild(hintRect);
            
//hintRect.graphics.
        }
        
private function getBitmap():void {
            
//使用BitmapData的draw方法,获得mc1的BitmapData数据
            btmpd1 = new BitmapData(mc1.width, mc1.height, true0);
            btmpd1.draw(mc1, 
nullnew ColorTransform(1251251251));
            
            
//使用BitmapData的draw方法,获得mc2的BitmapData数据
            btmpd2 = new BitmapData(mc2.width, mc2.height, true0);
            btmpd2.draw(mc2, 
nullnew ColorTransform(0001));
        }
        
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, true0xff0000);
            combinebtmpd2 
= new BitmapData(combineWidth, combineHeight, true0x000000);
        }
        
private function compareRect():void {
            
//这里要解释一下,前面讲的是通过两个mc的深度不同,得到的合集也不同,这么讲只是为了便于理解
            
//事实上这里我们是是通过BitmapData类的copyPixels方法,不同顺序的copy两mc的数据实现的
            
//先copy mc1,再copy mc2的
            combinebtmpd1.copyPixels(btmpd1, btmpd1.rect, new Point(00), nullnulltrue);
            combinebtmpd1.copyPixels(btmpd2, btmpd2.rect, 
new Point(mc2.x - mc1.x, mc2.y - mc1.y), nullnulltrue);
            
//先copy mc2,再copy mc1的
            combinebtmpd2.copyPixels(btmpd2, btmpd2.rect, new Point(mc2.x - mc1.x, mc2.y - mc1.y), nullnulltrue);
            combinebtmpd2.copyPixels(btmpd1, btmpd1.rect, 
new Point(00), nullnulltrue);
            
            
//交集要随时更新,所以之前的intersection要清除掉
            if (typeof(intersectionBtmpd) == "object") intersectionBtmpd.dispose();            
            intersectionBtmpd 
= combinebtmpd1.compare(combinebtmpd2);
            
            
//如果交集不为零,用框框出来!
            if (intersectionBtmpd != 0) {
                intersectionRect 
= intersectionBtmpd.getColorBoundsRect(0xFFFFFF0x000000false);
                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

原创粉丝点击