Skip to content

Tag Archives: vertors for flash

Flash向量-12-球和圆弧

2009-09-23

现在,让我们一起研究下如何处理运动的球和圆弧。圆弧式圆的一部分,不同的是圆石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源文件。

Flash向量-11-两个高速运动的球

2009-09-22

运动的球心情肯定不错吧,因为它能动并且还能游览这个世界。但是,如果另外一个球决定不再原地不动,而也运动起来,那么会发生什么事情呢?我们很有必要研究一下这个。在这种情况下,我们之前介绍的碰撞检测方法可能会失败。让我们看看相同的例子:

球1按照红色运动向量来运动,球2按照蓝色运动向量来运动。如果要正确的进行碰撞检测的话,我们需要把每个球的运动向量考虑在内。

图中,当两球相撞时,球1到达了p2,而球2到达了p3。幸亏我们用了向量,我们可以非常容易的将2个向量相加。这样,我们就不用考虑2个运动的球,我们用球1的运动向量减去球2的运动向量,然后我们可以用学过的“一个运动的球和一个静态的球”的模型。【as4game注:这一段说的就是初中学的相对运动,把2个球的运动转化成1个球的运动】

用球1的运动向量减去球2的运动向量,就得到了向量v3:

v3={};
v3.p0=ball1.p0;
v3.vx=ball1.vx-ball2.vx;
v3.vy=ball1.vy-ball2.vy;

现在,我们可以使用上一章学习的方法来进行碰撞检测,假设球1要移动v3这么多,而v2原地不动。如果球1在p4这一点碰到球2。我们计算出新的向量v4,它是球1碰到球2时,自己的运动向量。

game.v4={p0:ball1.p0, p1:p4};

因为我们知道2个球都在运动,我们可以找到变量“t”,它的值为v4的长度除以v3的长度。

t=v4.len/v3.len;

变量“t”的值在0到1之间。当它等于1,碰撞发生在球的运动向量的终点,当它等于0,碰撞发生在球的运动向量的起点。为了计算2个球发生碰撞时的位置,我们需要将将它们的运动向量乘以t:

ball1.p1.x=ball1.p0.x+t*ball1.vx;
ball1.p1.y=ball1.p0.y+t*ball1.vy;
ball2.p1.x=ball2.p0.x+t*ball2.vx;
ball2.p1.y=ball2.p0.y+t*ball2.vy;

我制作了2个运动的球的例子:

你可以拖动球的运动向量的终点。

你可以下载fla源文件。

2个球的弹性

在找到了碰撞点之后,我们可以改变球的运动向量,可以参考章节球和球章节。但是到目前为止,我们只学过一个球运动时的反弹。当2个球都在运动,它们的运动会相互影响,使得他们的运动向量都需要重新计算。
弹性取决于2个球的质量。为了简化问题,我们假设2个球的质量相等【as4game注:如果要考虑质量不相等的情况,可以用动量守恒定理和能量守恒定律2个方程来计算】。在这种情况下,他们中心连线方向的速度会交换:

vc是球心连线向量,vcn是它的法线。现在我们将运动向量v1和v2在vc和vcn上进行投影:

v1被分解成v1a和v1b,同样v2被分解成v2a和v2b。然后v1a和v2a会交换,然后用v1b和v2a来计算球1的新运动向量,用v1a和v2b来计算球2的新运动向量。

下面的例子中,一些球在运动,他们彼此反弹:

你可以下载fla源文件。

Flash向量-10-高速运动的球

2009-09-16

在上一节里面,我们学会了如何检测2个球的碰撞,和如何找到碰撞后的运动方向。看起来非常既好用,又简单,但是其实是有问题的:球不能运动的太快,否者碰撞检测会失效。以下是这种情形的一个说明:

图中,球1(红色)位于p0,以速度v移动。在下一个运动周期里面,它会到达p1的位置(绿色)。我们在上一个周期和本次的周期都会检测球1和球2是否发生碰撞。由于不论是在起点还是在终点,球1和球2的距离足够的大,我们检测不到球1和球2的碰撞。但是从图中可以看出,事实上球1和球2确实发生了碰撞。

上图中,球1和球2会在位置p3发生碰撞。可以这样来计算p3:

首先我们找到移动之前2个球的中心连线的向量:

vc={};
vc.p0=ball1.p0;
vc.p1=ball2.p0;

现在,我们计算出p2,它是运动向量上与球2距离最小的点。这个点很容易找到,只需要将向量vc在运动向量上进行投影,如果你已经不记得如何计算投影,可以在基础知识章节中查找。

我们绘制一个向量vn,从点p2到球2的中心点。这个向量和运动向量的法线方向相同。

vp=projectVector(vc, v.dx, v.dy);
p2={x:v.p0.x+vp.vx, y:v.p0.y+vp.vy};
vn={};
vn.p0=p2;
vn.p1=ball2.p0;

现在,我们可以比较这个向量的长度和两个球的半径之和。如果vn比半径之和大,那么不会发生碰撞。如果vn的长度和半径之和相等,那么刚好插肩而过。如果vn的长度小于半径之和,那么碰撞在到达p2这一点之前发生了。

totalRadius=ball1.r+ball2.r;
var diff=totalRadius-vn.len;
if(diff>0){
//collision
}else{
//no collision
}

当检测到球发生了碰撞,应该将球1从点p2移回点p3。但是怎么计算p3呢?如果你仔细看看上面的图片,很可能会发现,球2的中心点,p2和p3构成了一个三角形。我们对三角形非常的熟悉了,虽然还不足以让我们爱上她,但是已经足以让我们找到p3。首先,我们知道点p2到球心的长度,也就是向量vn的长度。然后,我们可以求得点p3到球2中心的长度,等于球的半径之和。现在,就可以使用古老而好用的勾股定理,来计算第三边(从p2到p3)的长度。

moveBack=Math.sqrt(totalRadius*totalRadius-vn.len*vn.len);
p3={x:p2.x-moveBack*v.dx, y:p2.y-moveBack*v.dy};
v3={p0:v.p0, p1:p3};

所以,我们将运动向量v从p2反向移动moveBack这么长的距离。有可能p3在向量v的外面,此时意味着碰撞不在本次运动循环中发生,但是但是有可能是在过去或者未来发生。我们只处理此刻的碰撞,我们要求p3必须落在向量v上面:

if(game.v3.len0){
//collision
game.ob1.p0=game.p3;
}

首先,从球1中心到p3的长度必须小于向量v的长度。同时2个向量必须放心相同,这一点可以通过计算点乘来确定。

这种检测方法的前提是,球在最开始的时候没有发生碰撞,如果遇到这种情况的话,在计算碰撞之前要小心哦。

我制作了一个例子,运动的球碰撞其他的球:

你可以拖动那些球,也可以拖动运动向量的终点。红色的圆代表球1的开始运动的时候,绿色是球1的运动完成的时候,蓝色是球2。

你可以下载fla源文件。

Flash向量-9-球和球

2009-09-10

首先,我们看看如何判断2个球发生碰撞。然后,再思考碰撞发生之后,球该怎么运动。

图中有球1(红色)和球2(蓝色)。2个球的球心之间的向量为v(绿色)。只有当v的长度小于两个球的半径只和时,两个球才发生了碰撞。我们需要做的是让2个球刚刚紧挨着,为了达到这个目的,我们需要将球1向v的方向移动一段距离:

pen=v.len-(b1.r+b2.r)

现在,2个球刚好紧贴,我们需要研究下运动向量如何变化。想象一下在两个球之间有一个无形的墙壁,墙壁的方式和球心连线向量的法线方向相同。

图中,黑色向量是向量v的法线,将它作为墙壁向量,用之前的方法计算球1的反弹运动向量。

以下是一个例子,一个球在舞台上移动,另外有几个静态的球。

尝试拖动那些静态的球。

你可以下载fla源文件。

把它装起来
你可能想让一个球在另外一个球里面。

假设,b2是大球,b1是小球。判断小球是否移出的条件是:

b2.r