分析算法的思路:
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。如图
补充约定:为方便表述,这里约定显示对象的“初始状态”为相对父级容器坐标系未进行旋转,缩放,即对象的transform.matrix对象是[a=1,b=0,c=0,d=1]。
Step2:一开始,图1中的4个mc都处于初始状态。但这样的碰撞检测不考验算法,因此对它们做缩放,旋转,平移处理(我直接在flashIDE里完成的),使得red_mc和green_mc的空间位置足够复杂。如图:
补充知识:draw()方法的一个细节
十分正常。但是,若用同样地代码来draw变形后的red_mc(即图2中的red_mc),会是什么样子呢?图2中red_mc尺寸太大,这块儿150*150的白色像素会不会只能draw入red_mc的一部分呢?效果如下:
看来,仍旧是以初始状态的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
进行过旋转变换。)
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();
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的一份拷贝
正确的操作是这样的:
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参数有何效果
文档说:用于缩放、旋转位图或转换位图的坐标
下面用代码和效果图说明:
很正常,跟图4吻合
再看:
果然,绘制源相对注册点偏移了(110,110)
再看:
这便是matrix参数的功能。
问:如何才能draw到图8中舞台下部的red_mc的形貌呢?
答:肉眼看到的red_mc的形貌,是它在stage坐标系中的形貌,因此将draw参数设置为red_mc.transform.concatenatedMatrix,这样绘制源便从初始状态变换到相对舞台的形貌。
试一下:
什么也没有?因为像素块太小了,red_mc经过矩阵变换,已经跑到了它外面去。
将像素块增大,看看:
但,假如像素块儿尺寸因为某种原因不能修改,该怎么办?那就再折磨draw()方法的matrix参数,让red_mc平移到舞台原点:
效果:
就是要这个样子。
刚才说到Step4:获取两个包围体的交叠矩形区域,用rect1存储相关信息(x,y,width,height),判断rect1区域内red_mc和green_mc是否有像素重叠。如图:
判断rect1区域内red_mc和green_mc是否有像素重叠的思路:
new出来一块儿跟rect1等大的黑色像素块。用一种colorTransform去drawrect1区域内的red_mc,再用另一种colorTransform去draw
至于如何准确的draw到rect1区域内的red_mc/green_mc的像素,在补充里已经给出思路。
现在再看tink的那个类应该很简单了。并且,个人认为他的类存在一些错误,下篇讨论