27.运用物理知识创建动画(2)

3、添加边界

在继续介绍相关内容之前,为了防止某些极端的小行星运动到画布之外,我们可以在画布上添加一个边界。在动画循环中添加以下代码,防止小行星飞出画布之外:

 
if (tmpAsteroid.x-tmpAsteroid.radius < 0) { 
        tmpAsteroid.x = tmpAsteroid.radius; 
        tmpAsteroid.vX *= -1; 
} else if (tmpAsteroid.x+tmpAsteroid.radius > canvasWidth) { 
        tmpAsteroid.x = canvasWidth-tmpAsteroid.radius; 
        tmpAsteroid.vX *= -1; 
}; 
 
if (tmpAsteroid.y-tmpAsteroid.radius < 0) { 
        tmpAsteroid.y = tmpAsteroid.radius; 
        tmpAsteroid.vY *= -1; 
} else if (tmpAsteroid.y+tmpAsteroid.radius > canvasHeight) { 
        tmpAsteroid.y = canvasHeight-tmpAsteroid.radius; 
        tmpAsteroid.vY *= -1; 
}; 

在画布上绘制小行星之前,以上代码中的两个条件语句用于检查每颗小行星的位置。如果小行星的边界位于某个边界之外,那么它将向边界内部运动,并且其速度也改变为相反的方向。如果不改变小行星的运动方向,那么它要么停下来,要么完全飞出边界之外。因为这里用圆来代表小行星,因此(x,y)坐标位于圆形中心点。为此,你需要加上或减去圆的半径来计算边界处的x或y位置。

刷新该页面(Animating with physics_3.html),你应该会看到一群小行星在四处飘荡,并在浏览器的边缘处弹回。

4、加速度

加速度是速度在一段时间内的变化,也称为速率的增加。在小行星动画中添加加速度非常简单。实际上,这和添加速度几乎完全相同,因为加速度也包含大小和方向,大小指加速小行星的像素数目,方向指加速度沿x轴或y轴方向。

你需要让每个小行星拥有不同的加速度,因此第一步需要在Asteroid类中创建所需的属性,然后在构建每颗小行星时位用这些属性。在Asteroid类中添加以下代码:

this.aX = aX;
this.aY = aY; 

就像前面对速度参数所做的操作一样,请务必向类函数中添加aX和aY参数。以下是Asteroid类最终的代码:

 
var Asteroid = function(x, y, radius, vX, vY, aX, aY) { 
        this.x = x; 
        this.y = y; 
        this.radius = radius; 
 
        this.vX = vX; 
        this.vY = vY; 
        this.aX = aX; 
        this.aY = aY; 
}; 

下一步是在创建小行星时使用这些新属性,因此在循环中创建小行星,并在速度变量之后添加以下代码:

var aX = Math.random()*0.2-0.1;
var aY = Math.random()*0.2-0.1; 

通过以上两行代码,小行星将获得一个介于-0.1到0.1之间的加速度。

在循环中所做的最后一件事,是在new Asteroid调用中添加新的aX和aY变量作为最后面的参数,代码如下所示:

asteroids.push(new Asteroid(x, y, radius, vX, vY, aX, aY)); 

仅对代码做这些修改,还无法看到加速度的效果,因为你还需要将加速度应用到每个具体的小行星。应用加速度就和把加速度添加到物体的当前速度一样,非常简单。毕竟,加速度是物体速度的变化情况,也就是说,它是先前速度与当前速度之间的差值。通过在动画循环中添加以下代码,将加速度应用到每个小行星。以下代码需要放在每颗小行星的速度代码(x和y位置)之后:

tmpAsteroid.vX += tmpAsteroid.aX; 
tmpAsteroid.vY += tmpAsteroid.aY; 

所有这些步骤都是通过加速度为每颗小行星增加速度,单位为像素。这并不会影响小行星的当前动画循环,但这意味着小行星在随后的循环中将会改变速度。

在让小行星加速之前,还需要在边界检查中添加几行代码。这样,当小行星碰到窗口的边缘时,边界检查将改变速度的方向,使物体沿着相反的方向运动。但加速度没有改变,因此当某颗小行星改变方向时,其加速度将逐步使小行星恢复为原来的方向。如果现在刷新浏览器,你就会明白我的意思。浏览器上显示的场景非常神奇,但并不是我们所期望的结果。

所幸,这个问题并不难解决,只需在改变速度方向的同时也改变加速度的方向就可以了。这将产生一系列边界检查,代码如下所示:

if (tmpAsteroid.x-tmpAsteroid.radius < 0) { 
        tmpAsteroid.x = tmpAsteroid.radius; 
        tmpAsteroid.vX *= -1; 
        tmpAsteroid.aX *= -1; 
} else if (tmpAsteroid.x+tmpAsteroid.radius > canvasWidth) { 
        tmpAsteroid.x = canvasWidth-tmpAsteroid.radius; 
        tmpAsteroid.vX *= -1; 
        tmpAsteroid.aX *= -1; 
}; 
 
if (tmpAsteroid.y-tmpAsteroid.radius < 0) { 
        tmpAsteroid.y = tmpAsteroid.radius; 
        tmpAsteroid.vY *= -1; 
        tmpAsteroid.aY *= -1; 
} else if (tmpAsteroid.y+tmpAsteroid.radius > canvasHeight) { 
        tmpAsteroid.y = canvasHeight-tmpAsteroid.radius; 
        tmpAsteroid.vY *= -1; 
        tmpAsteroid.aY *= -1; 
}; 

再次刷新页面,你就会看到期望的加速效果了。实际上,如果代码运行正常,小行星将永远处于加速状态,最终它们将以近似于光速的速度在屏幕上飞行。这太不现实了!要想改变小行星一直处于加速的状态,需要为每个小行星设置一个最大速度——限制为某种宇宙速度。用以下代码替换前面的代码(把加速度添加到速度中的那段代码):

if (Math.abs(tmpAsteroid.vX) < 10) { 
        tmpAsteroid.vX += tmpAsteroid.aX; 
}; 
 
if (Math.abs(tmpAsteroid.vY) < 10) { 
        tmpAsteroid.vY += tmpAsteroid.aY; 
}; 

以上代码的功能是,如果每个循环中小行星的速度小于10像素,就把加速度应用于该小行星。这种简单的检查可以限制小行星实际可以达到的速度,使小行星变得更易于控制。还需要重点注意的是,Math.abs方法将一个数转化成了绝对值数,这种方法主要用于删除数值前面的符号,例如,删除负数前面的符号。使用绝对值数意味着你仅处理正数,这样可以减少条件语句中的判断次数。

最后一次刷新页面(Animating with physics_4.html),你应该看到一群小行星最终变得非常听话,它们的速度将逐步达到最大值。

注意:力实质上是沿特定方向的加速度,例如,如果需要模拟重力,你可以沿y轴的正向(向下)创建均匀的加速度。

5、摩擦力

从技术上说,摩擦为也是一种力,可以非常精确地计算摩擦力,然后将它作用于物体,使物体降低速度。但是,这里我将透露一个运用物理学制作动画的小技巧:如果精确的计算非常复杂且需要耗费一些不必要的时间,那么我们可以模仿摩擦力!显然,如果你对动画的仿真度要求很高,那么这种方法就不太适用了。但是在多数情况下,尤其是对游戏而言,模仿的摩擦力产生的效果和实际效果几乎看不出差别来。模仿物理量的优点在于计算时间更少且易于理解。

就摩擦力而言,你需要用它来降低物体的运动速度。正常情况下,必须根据物体及其经过的物体表面来计算真实的摩擦力,但是如果你采用模仿摩擦力的方法,就可以仅用物体的速度乘以一个摩擦系数来实现。对非专业人员来说,这两种方法产生的效果是相同的:计算正确的摩擦力并将它作用于物体,将会使物体减速,通过速度乘以一个摩擦系数来模仿摩擦力也会使物体减速。例如,如果物体的速度是2个像素,摩擦系数为0.9.最后的速度将会等于当前的速度乘以该系数,即等于1.8。在每个循环中使用相同的摩擦系数,物体的速度将很快趋近于0(假设该摩擦力使速度降低的幅度大于加速度使速度增加的幅度)。

如果需要在小行星示例中演示这种摩擦力,那么只需要在加速度代码后面添加以下代码即可:

 
if (Math.abs(tmpAsteroid.vX) > 0.1) { 
        tmpAsteroid.vX *= 0.9; 
} else { 
        tmpAsteroid.vX = 0; 
}; 
 
if (Math.abs(tmpAsteroid.vY) > 0.1) { 
        tmpAsteroid.vY *= 0.9; 
} else { 
        tmpAsteroid.vY = 0; 
}; 

以上代码把每颗小行星的速度都乘以0.9,其结果作为一个全局变量值。摩擦力将使每颗小行星逐渐减速,它们就好像在沿着台球桌往高处运动。当物体的速度降低到一定值时,条件语句用于取消摩擦力,防止摩擦力占用系统资源。为此,当速度取非常小的数值时(速度非常小,看上去好像处于静止状态),可以将速度值设置为0(使小行星停止运动)。

刷新页面查看结果(Animating with physics_5.html),你会发现小行星的运动速度比先前更慢了。但是,由于加速度仍然在起作用,小行星永远不会完全停止下来。当然,也可以让小行星完全停止运动,但必须完全删除代码中的加速度。

文件下载(已下载 2599 次)

发布时间:2013/3/21 15:11:21  阅读次数:6150

2006 - 2024,推荐分辨率1024*768以上,推荐浏览器Chrome、Edge等现代浏览器,截止2021年12月5日的访问次数:1872万9823 站长邮箱

沪ICP备18037240号-1

沪公网安备 31011002002865号