现在,让我们一起研究下如何处理运动的球和圆弧。圆弧式圆的一部分,不同的是圆石360度的,而圆弧不足360度。对于球和球的碰撞,之可能存在一个碰撞点。对于球和圆弧的碰撞,可能有……不是1个,也不是2个,而是4个碰撞点。
图中,左边,运动的球从原画的外面碰撞到圆弧,中间,球从圆弧的里面碰撞到圆弧,右边,球碰到了圆弧的端点(圆弧有2个端点,球可能同时碰到这2个端点)
为了定义一个圆,我们需要中心点和半径。为了定义一个圆弧,除了需要中心点和半径,还需要它的起始端点的角度和终终止端点的角度。
例如,我们可以这样定义圆弧:
arc={p0:{x:170, y:90}, r:30, ang1:135, ang2:315};
圆弧的中心点在x=170,,y=90,它的半径为30,起点角度为135度,终点角度为315度。知道了这些,我们可以计算出圆弧的起点和终点的坐标:
ang1rad=ang1*Math.PI/180;
ang2rad=ang2*Math.PI/180;
v1.p0={
x:p0.x+r*Math.cos(ang1rad),
y:p0.y+r*Math.sin(ang1rad)
};
v1.p1={
x:p0.x+r*Math.cos(ang2rad),
y:p0.y+r*Math.sin(ang2rad)
};
向量1是圆弧的起点到终点连线向量。
碰撞
可以使用球和球章节介绍的方法,检测球和圆弧外面的碰撞。当碰撞发生的时候,我们再来检测这个碰撞的位置是否在圆弧上存在。
我们需要找到球和圆弧相切的点p3。我们知道了发生碰撞时球心的位置,所以我们可以画一个向量v2,从圆弧中心到碰撞时球的中心。
v2={p0:arc.p0, p1:ball.p3};
点p3在在这个向量上,它和圆弧中心的距离为圆弧的半径(它和球的中心的距离为球的半径):
p3={
x:arc.p0.x+v2.dx*arc.r,
y:arc.p0.y+v2.dy*arc.r
};
然后我们画一个向量,从圆弧的起点到点p3:
v3={p0:v1.p0, p1:p3};
只有当v3和v1的左法线的点乘大于0时,p3才在圆弧上。
if(dotP(v3, v1LeftNormal)>=0){
//collision
}else{
//not on the arc
}
如果碰撞发生在圆弧的外侧,我们可以忽略其他3种情况。然而,如果碰撞点p3,不在圆弧上面,我们就要考虑球是否碰到圆弧的端点,还是碰到了圆弧的内侧。
对于端点,我们可以继续使用球和球的系统,假设端点是看不见的球,半径为0,坐落在端点坐标。和球碰撞的圆弧是:
ballvsBall(ball, arc.p0, arc.r);
我们可以这样检测端点碰撞:
ballvsBall(ball, v1.p0, 0);
ballvsBall(ball, v1.p1, 0);
对于球和圆弧内部碰撞,我们使用外部碰撞系统的略加修改版。外部碰撞检测方法是:
r=arc.r+ball.r;
moveBack=Math.sqrt(r*r-vn.len*vn.len);
ball.p3={
x:ball.p2.x-moveBack*v.dx,
y:ball.p2.y-moveBack*v.dy};
内部碰撞检测方法:
r=arc.r-ball.r;
moveBack=Math.sqrt(r*r-vn.len*vn.len);
ball.p3={
x:ball.p2.x+moveBack*v.dx,
y:ball.p2.y+moveBack*v.dy};
由于球可能和圆弧的多个点碰撞,我们可以取最短路径。
下面的例子中展示了球和圆弧的碰撞,你可以体验下:
你可以下载fla源文件。
