主要内容
相互吸引
希望你会发现从简单的场景开始 一个对象吸引另一个对象 ,到 一个对象吸引很多对象 对理解很有帮助。但是,你可能会发现更复杂的情况 很多对象互相吸引 。换句话说,这个系统中的每个对象都在吸引该系统中的所有对象(除了它本身)。
我们几乎已经做完这个情况的所有工作了。让我们考虑一个包含
Mover
对象数组的程序:var movers = [];
for (var i = 0; i < 5; i++) {
movers[i] = new Mover(
random(0.1, 2),
random(width),
random(height));
}
draw = function() {
background(255, 255, 255);
for (var i = 0; i < movers.length; i++) {
movers[i].update();
movers[i].display();
}
};
draw()
函数是我们需要施展一些魔术的地方。
目前,我们说:“对于每个 mover i,更新并显示自己。” 现在我们需要说的是:“对于每个mover i,被每一个mover j吸引,更新并显示自己。”for (var i = 0; i < movers.length; i++) {
// 检查每个Mover
for (var j = 0; j < movers.length; j++) {
var force = movers[j].calculateAttraction(movers[i]);
movers[i].applyForce(force);
}
}
for (var i = 0; i < movers.length; i++) {
movers[i].update();
movers[i].display();
}
注意我们在更新并显示的基础上建立了一个全新的
for
循环。这是因为我们想要确保计算 所有 吸引力 之前 更新每个mover。如果我们不小心更新了第一个
for
循环中的每个mover,那么之后的吸引力运算将会被影响,变得不再精确。我们的代码还没有完成,因为我们需要每个
Mover
对象拥有一个 calculateAttraction()
方法来计算吸引力。在之前的例子中,我们有 Attractor
对象中的 calculateAttraction()
方法。现在,因为我们的movers在吸引movers,我们要将这个方法复制到Mover
对象中:Mover.prototype.calculateAttraction = function(m) {
var force = PVector.sub(this.position, m.position);
var distance = force.mag();
distance = constrain(distance, 5.0, 25.0);
force.normalize();
var strength = (G * this.mass * m.mass) / (distance * distance);
force.mult(strength);
return force;
};
当然,这里有一个小问题。当我们在看每个mover i和每个mover j,我们考虑了i等于j的情况吗? 比如说,mover #3 应该吸引 mover #3吗?答案当然是不。如果我们有五个对象,我们只应该让mover #3吸引 0,1,2,和4号,跳过它自己。然而我们想要计算并应用mover #3作用到mover #1的力以及mover #1作用到mover #3的力。计算出来的力应该是相等的,但是作用后的加速度会根据各自的质量和不同。我们的吸引力表格应该是这样子的:
0 ⇢ 1, 2, 3, 4
1 ⇢ 0, 2, 3, 4
2 ⇢ 0, 1, 3, 4
3 ⇢ 0, 1, 2, 4
1 ⇢ 0, 2, 3, 4
2 ⇢ 0, 1, 3, 4
3 ⇢ 0, 1, 2, 4
因此,我们通过修改 for 循环来完成这个例子,以便内部的循环会防止mover吸引自己。
for (var i = 0; i < movers.length; i++) {
for (var j = 0; j < movers.length; j++) {
if (i !== j) {
var force = movers[j].calculateAttraction(movers[i]);
movers[i].applyForce(force);
}
}
}
让我们将所有内容整合起来:
“自然模拟”系列课程是由 Daniel Shiffman 的 "编程的本质" 衍生而来,基于 知识共享 著名-非商用性 3.0 本地化许可协议。