像素级碰撞的一种算法

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值