力
出自FlashWiki
目录 |
牛顿运动定律
牛顿运动定律是伊萨克·牛顿提出的物理学的三个运动定律的总称,被誉为是经典物理学的基础。
第一运动定律
一切物体在任何情况下,在不受外力的作用时,总保持静止或匀速直线运动状态。
第二运动定律
物体的加速度跟物体所受的合外力成正比,跟物体的质量成反比,加速度的方向跟合外力的方向相同。
第三运动定律
两个物体之间的作用力和反作用力,在同一条直线上,大小相等,方向相反。
对于我们来说,最重要的定律就是第2条了,下面我们有一个例子:
我们假设一个物体有下列属性:
- 位置(点,这里用矢量替代)
- 速度(矢量)
- 加速度(矢量)
- 质量(数量)
class Thing {
// Instance variables for the class
PVector loc;
PVector vel;
PVector acc;
float mass;
float max_vel;
float bounce = 1.0; // How "elastic" is the object
// Constructor
Thing(PVector a, PVector v, PVector l, float m_) {
acc = a.get();
vel = v.get();
loc = l.get();
mass = m_;
}
}
运动函数的作用方式就像我们在上一篇矢量例子里介绍的一样。对于程序来说是有别于真实的物理世界的,在真实世界里,物体的运动是连续的,因为每一个时间点都是连续的无限接近的,并且时间是自动向前的。但是在程序世界里,却不是这样的,物体的运动是一帧接着一帧的,时间点不是连续的,并且时间点之间的间隔是可以控制的。我们的函数会在每一个时间点被执行一次,计算只基于当前这个时间点发生了什么。
- 给速度加上加速度
- 给位置加上速度
- 把加速度重置为零 < --- *新*
- 在新位置绘制物体
void update() {
vel.add(acc);
loc.add(vel);
acc.mult(0); // new!
}
我们将加速度重置为0是因为我们在每一个时间点都要重新计算物体受的合外力,并计算出新的加速度。这里我们用数量0乘以矢量来达到重置的目的(因为:x*0=0, y*0=0)
对于一个物体,我们要把它受到的力全部加起来,形成一个合外力,再用牛顿第二定律计算它的加速度。下面我们假设:
- 一个物体的位置 = (10,20) 质量 = 5, 并且初速度 = (-3,2)
- 受到一个风力 = (5,0)
- 受到一个重力 = (0,10)
记住这公式 (因为 F = M * A, 所以 A = F / M):
对于每一个时间点就有:
风力产生的加速度 = 风力 / 质量 = (5,0) / 5 = (1,0)
重力产生的加速度 = 重力 / 质量 = (0,10) / 5 = (0,2)
合力产生的加速度 = (1,0) + (0,2) = (1,2)
速度 = 速度 + 加速度 = (-3,2) + (1,2) = (-2,4)
位置 = 位置 + 速度 = (10,20) + (-2,4) = (8,24)
在我们的代码里,我们还需要一个函数来处理物体受到的力,把力作为一个参数传入,并且计算出受这个力影响后的总加速度:
void applyForce(PVector force) {
force.div(mass); // Newton's second law
acc.add(force); // Accumulate acceleration
}
值得注意的是:这里为物体引入质量的概念是为了对应牛顿第二定律并减少误差。但是,如果你的目的只是希望在视觉上模拟(物体与物体之间没有相互作用)。那么这里的质量其实就没有那么重要了,事实上,你可以简化你的代码,假设物体的质量为1,根据牛顿第二定律(A = F / M)使得 加速度 = 力。
上面的代码中涉及到的力,我们是假设已经知道了力的大小并直接给出的值(比如风力,重力),下面我们来看看一些力的具体计算方式。
阻力
当一个物体在运动的时候,受到的妨碍物体运动的作用力,称为阻力。一般来说,只要物体在运动就会受到阻力,即便是在空气中运动也会受到来自空气的阻力。阻力由多种力组成,其中一些比较常见的有摩擦力,黏着力,空气阻力,流体阻力,其计算我们这里都不讨论,为了简化计算,我们将所有阻力统一在一起,他的大小和速度成正比,方向和速度相反:
阻力 = -c * 速度
这里的c 可以理解为阻力系数。
下面假设我们有一个物体“t”,比如在水中运动,阻力系数为-0.03,那么在程序中表示方法就如下所示:
float c = -0.03; // Drag coefficient PVector thingVel = t.getVel(); // Velocity of our thing PVector force = PVector.mult(thingVel,c); // Following the formula above t.applyForce(force); // Adding the force to our object, which will ultimately affect its acceleration
万有引力
两个具有质量的物体间相互吸引的作用力称做万有引力,它们大小相等,方向相反(参考牛顿第三定律)。要计算万有引力,我们需要:
- G –> 万有引力常数,注意此常数并非重力加速度。
- M1, M2 –> 相互作用的2个物体的各自质量
- D –> 2个物体的质心间的距离
- L1, L2 –> 相互作用的2个物体的各自位置(计算方向用)
万有引力的大小 = (G * M1 * M2) / (D * D)
万有引力的方向 (相对物体1) = (L2 – L1) / ||L2 – L1||
为了在代码中实现万有引力,我们需要准备另一个函数,当把另一个物体作为参数传入的时候,就能计算出它所产生的万有引力。比如:
PVector calcGravForce(Thing t) {
PVector dir = PVector.sub(loc,t.getLoc()); // Calculate direction of force
float d = dir.mag(); // Distance between objects
dir.normalize(); // Normalize vector (distance doesn't matter, we just want direction)
float force = (G * mass * t.getMass()) / (d * d); // Calculate gravitional force magnitude
dir.mult(force); // Get force vector --> magnitude * direction
return dir;
}
现在,在我们的程序中假设有5个物体:
final int MAX = 5; Thing[] t = new Thing[MAX];
下一步要在我们的代码中用程序实现如下功能:
- 对于每一个 Thing t, 用循环计算出所有其他 Thing 作用在自己身上的万有引力
void draw() {
for (int i = 0; i < t.length; i++) { // For every Thing t[i]
for (int j = 0; j < t.length; j++) { // For every Thing t[j]
if (i != j) { // Make sure we are not calculating gravtional pull on oneself
PVector f = t[i].calcGravForce(t[j]); // Use the function we wrote above
t[i].applyForce(f); // Add the force to the object to affect its acceleration
}
}
t[i].go(); // Implement the rest of the object's functionality
}
}
真实世界 vs. 数字世界
到这里,我们的程序还是有问题的,要知道真实世界和数字世界是不一样的,比如下面的例子:
物体 T1: LOC = (10.2,10.0), MASS = 5 物体 T2: LOC = (10.3,9.9), MASS = 5 G = 1.0 距离 = SQRT((10.2-10.3)*(10.2-10.3)+(10.0-9.9)*(10.0-9.9)) = SQRT(0.01 + 0.01) = ~0.14 万有引力 = (1.0 * 5 * 5) / (0.14 * 0.14) = 1250.0
这个地方因为我们为了让万有引力的作用在程序表现的视觉中明显一点,将引力系数 G 设置为1了,这个值远大于真实世界的引力系数,直接导致了这2个物体间的引力有1250,而这个力显然太大了,为了让我们的程序运转的更正常,看起来更像真的,我们要人为的约束一下2个物体间的计算距离。在下面的代码中,我将告诉你如何在程序中实现这个目标,让它看起来“更真一点”。
下面是更改过的calcGravForce 万有引力计算函数:
PVector calcGravForce(Thing t) {
PVector dir = PVector.sub(loc,t.getLoc()); // Calculate direction of force
float d = dir.mag(); // Distance between objects
d = constrain(d,5.0,25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects
dir.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction)
float force = (G * mass * t.getMass()) / (d * d); // Calculate gravitional force magnitude
dir.mult(force); // Get force vector --> magnitude * direction
return dir;
}
参考阅读
- Newtonian Physics, An Online Textbook (This is long, you may find Chapter 4 to be particularly relevant to this week’s discussion.)
- The Physics Classroom — Newton’s Laws
- Mathematics and Physics for Programmers, Chapters 12 and 14, Danny Kodicek (suggested)
