5.9 模拟粒子物理学
现在,我们已经介绍了经典物理学的基础,让我们把它们贯穿起来。本节,我们将通过模拟重力、边界条件、碰撞阻尼、地面摩擦力来模拟粒子物理运动。
操作步骤
按照以下步骤,在画布中发射一个粒子,并观察其运动路径,先碰墙反弹,再在重力作用下渐渐落到地面,然后由于地面摩擦力的作用而慢慢停下来。
1. 链接到Animation类:
<head>
<script src="animation.js"> </script>
2. 定义applyPhysics()函数,该函数把粒子作为输入,并根据物理变量,如重力、碰撞阻尼、地面摩擦力,更新其位置和速度:
function applyPhysics(anim, particle){
// 物理学全局变量
var gravity = 1500; // pixels / second^2
var collisionDamper = 0.8; // 发生碰撞后速度将损失80%
var floorFriction = 100; // pixels / second^2
var timeInterval = anim.getTimeInterval();
var canvas = anim.getCanvas();
//重力
particle.vy += gravity * timeInterval / 1000;
//位置
particle.y += particle.vy * timeInterval / 1000;
particle.x += particle.vx * timeInterval / 1000;
//地面情况下
if (particle.y > (canvas.height - particle.radius)) {
particle.y = canvas.height - particle.radius;
particle.vy *= -1;
particle.vy *= collisionDamper;
}
//地面摩擦力
if (particle.y == canvas.height - particle.radius) {
if (particle.vx > 0.1) {
particle.vx -= floorFriction * timeInterval / 1000;
}
else if (particle.vx < -0.1) {
particle.vx += floorFriction * timeInterval /1000;
}
else {
particle.vx = 0;
}
}
//天花板情况下
if (particle.y < (particle.radius)) {
particle.y = particle.radius;
particle.vy *= -1;
particle.vy *= collisionDamper;
}
//右墙情况下
if (particle.x > (canvas.width - particle.radius)) {
particle.x = canvas.width - particle.radius;
particle.vx *= -1;
particle.vx *= collisionDamper;
}
//左墙情况下
if (particle.x < (particle.radius)) {
particle.x = particle.radius;
particle.vx *= -1;
particle.vx *= collisionDamper;
}
}
3. 实例化一个Animation对象,并获取画布上下文:
window.onload = function(){
var anim = new Animation("myCanvas");
var canvas = anim.getCanvas();
var context = anim.getContext();
4. 使用位置,x、y方向上速度,半径初始化一个粒子对象:
var particle = {
x: 10,
y: canvas.height - 10,
vx: 600, // px / second
vy: -900, // px / second radius: 10
};
5. 设置stage()函数,该函数把粒子对象传递给applyPhysics()函数来更新粒子的状态,清除画布,再绘制粒子:
anim.setStage(function(){
// update
applyPhysics(this, particle);
// clear
this.clear();
// draw
context.beginPath();
context.arc(particle.x, particle.y, particle.radius, 0, 2 * Math.PI, false);
context.fillStyle = "blue";
context.fill();
});
6. 启动动画:
anim.start();
};
</script>
</head>
7. 在HTML文档的body部分嵌入canvas标签:
<body>
<canvas id="myCanvas" width="600" height="250" style="border:1px solid black;">
</canvas>
</body>
工作原理
要模拟粒子物理学,我们需要处理粒子在每一帧时的x、y位置,及x、y方向上的速度。理解粒子物理学的关键是要记住,粒子在一个系统中的运动,是由作用在该粒子上的所有力的合力决定的。在本例中,重力会把粒子往下拉;撞击到墙壁、天花板、地板时,会根据碰撞阻尼常数较低粒子的速度;当在地面上滚动时,地面摩擦力会较低粒子在水平方向上的速度。
一开始,在页面加载完成后,我们实例化一个Animation对象,并得到画布及其上下文对象。接下来,我们使用位置、初始速度、尺寸来初始化一个粒子。舞台上的演员(粒子)初始化完成后,我们可以设置stage()函数,该函数将更新粒子,清除画布,再在每个动画帧绘制粒子。
更新的逻辑发生在applyPhysics()函数中,该函数的参数是一个Animation对象(即particle对象)的引用。applyPhysics()遍历不同情况的列表来更新粒子的位置和速度。
调用applyPhysics()函数,并且粒子被更新之后,我们可以清除画布,然后简单绘制一个圆来绘制粒子,该圆的半径与粒子的半径相等。
最后,stage()函数被设置完成后,我们便可以调用start()方法启动动画了。
了解更多
如果你真的想弄点花样,你甚至可以外加其它的力,如空气阻力。根据普遍的经验,你给模拟粒子增加的力越多,其结果越逼真。你可以使用不同的初始位置和速度,看看不同的发射路径。
相关参考
- 第2章 绘制圆