• 关于tink的碰撞检测类【2】


    分析算法的思路:

     

    Step1:假设stage(黑色)上有4个显示对象red_mc,green_mc,blue_mc,yellow_mc,层级关系是stage>root>red_mc,stage>root>yellow_mc>blue_mc>green_mc。要检测碰撞的对象是red_mc和green_mc。如图


                                      图1

     

    补充约定:为方便表述,这里约定显示对象的“初始状态”为相对父级容器坐标系未进行旋转,缩放,即对象的transform.matrix对象是[a=1,b=0,c=0,d=1]。

     

    Step2:一开始,图1中的4个mc都处于初始状态。但这样的碰撞检测不考验算法,因此对它们做缩放,旋转,平移处理(我直接在flashIDE里完成的),使得red_mc和green_mc的空间位置足够复杂。如图:



                                       图2
    补充知识:draw()方法的一个细节

      如下代码(文档类):
       varbmd1:BitmapData = new BitmapData(150,150);
       bmd1.draw(red_mc);
       varbmp1:Bitmap = new Bitmap(bmd1);
       this.addChild(bmp1);

      若red_mc处于初始状态(即图1中的red_mc),效果如下:



                                       图3
    十分正常。但是,若用同样地代码来draw变形后的red_mc(即图2中的red_mc),会是什么样子呢?图2中red_mc尺寸太大,这块儿150*150的白色像素会不会只能draw入red_mc的一部分呢?效果如下:


                                       图4

    看来,仍旧是以初始状态的red_mc为绘制源。

    这就是draw(X)方法的一个细节:不管X怎样变形,平移,都选取X的初始状态作为绘制源。此外,当X处于层层容器嵌套之下时(green_mc就是这种情况),不管它n多父级的变形操作对X形状产生怎样影响,draw也一样选取X的初始状态为绘制源。

     

    Step3:前两步作为准备,现在开始碰撞检测的第一步,利用flash自带的hitTestObject()函数做预判断。若这一步判断false肯定没戏了。

    补充知识:

    1.hitTestObject()是基于AABB包围体的碰撞检测,即检测虚线框的碰撞。(red_mc的虚线框看似并未仅包住red_mc,这是因为red_mc


                                     图5

    进行过旋转变换。)

    2.hitTestObject()检测碰撞时,并不关心对象是否在显示列表内。这点很重要。

     

    Step4.通过上步的预判断,再进一步检测:获取两个包围体的交叠矩形区域,用rect1存储相关信息(x,y,width,height),判断rect1区域内red_mc和green_mc是否有像素重叠。若true便碰上了。

    补充知识:显示对象的matrix属性

    matrix本身的a,b,c,d没什么好说,这里记下matrix操作的细节。

    1.red_mc.transform.matrix,这个记录矩阵(习惯称它记录矩阵,文档上称“变换矩阵”),是red_mc相对于父级容器坐标系的记录矩阵。就像通常所说red_mc.x也是red_mc相对于父级坐标系的x轴偏移。

     

    2.要想获得red_mc相对于再上一级,即parent.parent的记录矩阵,该如何呢?直接用parent的matrix乘上red_mc的matrix就好了。

     

    3.若想获取red_mc相对于stage的记录矩阵呢?理论上是root.transform.matrix*........(各级父容器的矩阵逐级相乘)......*red_mc.transform.matrix。很累,flash为此提供了concatenatedMatrix属性,就是显示对象相对于stage的记录矩阵。(矩阵乘法是不能用*号的,应该是concat,我是想写快点儿)

     

    4.假若要获取red_mc相对于root的记录矩阵呢?直接逐级相乘没问题。不过,concatenated属性提供了一个简洁思路------varrootM:Matrix=root.transform.matrix.clone();

             var rootM1:Matrix=red_mc.transform.concatenatedMatrix;

             rootM.invert();//取得root的逆矩阵

              rootM1.concatenatedMatrix.concat(rootM);//这样,rootM1就转化为相对于root的

     

    5.matrix的concat()方法似有bug

    当a,d任意为0时,计算的结果就不大对,例如下面两个矩阵

    var A:Matrix=newMatrix(1,1,2,2,0,0);

    var B:Matrix=newMatrix(0,0,1,1,1,0);

    A.concat(B);

    trace(A);//输出的ty不是2,我用笔算了几遍,ty都是2

    当a,d都不为0时,计算结果没有问题,以后还是放心用吧,因为a,d任意为0,显示对象便不存在了,应不会存在这种情况。

    自己写了个矩阵运算类,是很无脑的算法:行对列相乘。很慢很稳妥。是不是内置的矩阵乘法运算采用另外算法,才会有这样的bug呢?

     

    6.matrix的concat()方法用起来要小心顺序

    A.concat(B),对应的数学式为(矩阵B*矩阵A),矩阵乘法不满足交换律,这个地方跟常规思路又不同(至少跟我想的顺序相反),因此操作时应小心。

     

    7.不要直接修改显示对象matrix的a,b,c,d,tx,ty属性,也不要直接应用scale,rotate等操作。因为任何设置都是无效的。

    如:varA:Matrix=red_mc.taransform.matrix;//A引用的是red_mc.taransform.matrix的一份拷贝

       A.scale(0.5,0.5);//编译不会报错,但这个操作只修改A,对red_mc.taransform.matrix不造成修改

       A.a=2;//同上

    正确的操作是这样的:

      varA:Matrix=red_mc.transform.matrix.clone();

      //varA:Matrix=red_mc.transform.matrix也行

     A.scale(0.5,0.5);

     A.a=2;

     red_mc.tansform.matrix=A;//创建一个合适矩阵,交付给red_mc.transform.matrix引用。

     

    8.想对matrix执行scale操作时,用scale方法:

    A.sacle(0.5,0.5);

    不要写:A.a/=A.b/=2;当matrix的b,c属性不为0,这个操作完成的并不是scale功能。

     

    补充知识:BlendMode.DIFFERENCE

    文档讲的很清楚:

    将显示对象的原色与背景颜色进行比较,然后从较亮的原色值中减去较暗的原色值。此设置通常用于得到更明亮的颜色。

    例如,如果显示对象的某个像素的 RGB 值为0xFFCC33,背景像素的 RGB 值为 0xDDF800,则显示像素的结果 RGB 值为 0x222C33(因为 0xFF -0xDD = 0x22,0xF8 - 0xCC = 0x2C,且 0x33 - 0x00 = 0x33)。

     

    补充知识:draw()方法的matrix参数有何效果

    文档说:用于缩放、旋转位图或转换位图的坐标

    下面用代码和效果图说明:

       varbmd1:BitmapData = new BitmapData(200,200);
       bmd1.draw(red_mc,newMatrix(1,0,0,1,0,0));//先不对绘制源做处理,看看正常的样子
       varbmp1:Bitmap = new Bitmap(bmd1);
       this.addChild(bmp1);

                                           图6

    很正常,跟图4吻合

    再看:

       varbmd1:BitmapData = new BitmapData(200,200);
       bmd1.draw(red_mc,newMatrix(1,0,0,1,110,110));//让绘制源沿x,y轴正方向平移了(110,110)的向量
       varbmp1:Bitmap = new Bitmap(bmd1);
       this.addChild(bmp1);

                                           图7
    果然,绘制源相对注册点偏移了(110,110)

    再看:

       varbmd1:BitmapData = new BitmapData(200,200);
       bmd1.draw(red_mc,new Matrix(2, 0, 0, 2, 0, 0));
       varbmp1:Bitmap = new Bitmap(bmd1);
       this.addChild(bmp1);


                                                图8
    果然缩放了两倍

    这便是matrix参数的功能。

    问:如何才能draw到图8中舞台下部的red_mc的形貌呢?

    答:肉眼看到的red_mc的形貌,是它在stage坐标系中的形貌,因此将draw参数设置为red_mc.transform.concatenatedMatrix,这样绘制源便从初始状态变换到相对舞台的形貌。

    试一下:

       varbmd1:BitmapData = new BitmapData(200, 200);
       //为了便于区分,施加一个colorTransform让draw到的像素变为蓝色
       bmd1.draw(red_mc,a_mc.transform.concatenatedMatrix,newColorTransform(1,1,1,-255,-255,255));
       varbmp1:Bitmap = new Bitmap(bmd1);
       this.addChild(bmp1);


                                             图9

    什么也没有?因为像素块太小了,red_mc经过矩阵变换,已经跑到了它外面去。

    将像素块增大,看看:

       varbmd1:BitmapData = new BitmapData(300, 300);
       //为了便于区分,施加一个colorTransform让draw到的像素变为蓝色
       bmd1.draw(a_mc,a_mc.transform.concatenatedMatrix,newColorTransform(1,1,1,1,-255,-255,255,255));
       varbmp1:Bitmap = new Bitmap(bmd1);
       this.addChild(bmp1);


                                            图10
    这下好啦!很准。

    但,假如像素块儿尺寸因为某种原因不能修改,该怎么办?那就再折磨draw()方法的matrix参数,让red_mc平移到舞台原点:

       varbmd1:BitmapData = new BitmapData(200, 200);
       //为了便于区分,施加一个colorTransform让draw到的像素变为蓝色
       var m1:Matrix= a_mc.transform.concatenatedMatrix;
       m1.tx += 0 -m1.tx;
       m1.ty += 0 -m1.ty;
       bmd1.draw(a_mc,m1,newColorTransform(1,1,1,1,-255,-255,255,255));
       varbmp1:Bitmap = new Bitmap(bmd1);
       this.addChild(bmp1);

    效果:

                                               图11

    就是要这个样子。

     

    刚才说到Step4:获取两个包围体的交叠矩形区域,用rect1存储相关信息(x,y,width,height),判断rect1区域内red_mc和green_mc是否有像素重叠。如图:

                   

                                               图12
    判断rect1区域内red_mc和green_mc是否有像素重叠的思路:

    new出来一块儿跟rect1等大的黑色像素块。用一种colorTransform去drawrect1区域内的red_mc,再用另一种colorTransform去draw rect1区域内的green_mc,同时采用blendMode.DIFFERENCE混合模式,一旦出现特定颜色,则有像素重叠。

     

    至于如何准确的draw到rect1区域内的red_mc/green_mc的像素,在补充里已经给出思路。

    现在再看tink的那个类应该很简单了。并且,个人认为他的类存在一些错误,下篇讨论
  • 相关阅读:
    LINUX 下编译不通过解答
    线程与进程
    机房收费系统之报表总结2
    【android开发】10款实用的Android UI工具,非常有用!
    EMPTY表示元素不能包含文本,也不能包含子元素
    ResultSet是结果集对象
    如果没有指定Cookie的时效,那么默认的时效是。(选择1项)
    用于调用存储过程的对象是。(选择1项)
    Statement和PreparedStatement都是用来发送和执行SQL语句的
    DTD与XML Schema都是XML文档。(选择1项)
  • 原文地址:https://www.cnblogs.com/weiweishuo/p/3082646.html
Copyright © 2020-2023  润新知