书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
目录
2.10 万有引(斥)力
我们从最简单的例子开始,也就是一个物体吸引另一个物体的模型,之后扩展到一个物体吸引多个物体的模型。
下面,我们将研究更复杂的模型:多个物体相互吸引。换句话说,在新的系统中,每个对象对其他任何对象(系统本身除外)都有吸引作用。
1、draw()函数的逻辑变化
我们已经完成了其中的大部分工作。请思考下面的场景,有一个由Mover对象组成的数组:
Mover[] movers = new Mover[10];
void setup() {
size(400,400);
for (int i = 0; i < movers.length; i++) {
movers[i] = new Mover(random(0.1,2),random(width),random(height));
}
}
void draw() {
background(255);
for (int i = 0; i < movers.length; i++) {
movers[i].update();
movers[i].display();
}
}
我们需要在draw()函数上做些修改,
- 之前,我们的实现逻辑是:
对每个Mover i,先更新其位置,并在屏幕上绘制出来。 - 现在我们要把它实现成:
对每个Mover i,都受到其他Mover j的吸引,更新i的位置,并在屏幕上绘制出来。
2、嵌套一个循环
为了实现这个逻辑,我们需要再嵌套一个循环。
for (int i = 0; i < movers.length; i++) {
for (int j = 0; j < movers.length; j++) { 每个Mover对象都要检查所有其他Mover对象
PVector force = movers[j].attract(movers[i]);
movers[i].applyForce(force);
}
movers[i].update();
movers[i].display();
}
3、attract()函数
- 在前面的例子中,Attractor对象有一个attract()函数。
- 在这里,Mover对象也能产生引力,因此我们需要将attract()函数复制到Mover类中。
class Mover {
//此处加上前面写过的代码
PVector attract(Mover m) { 现在,Mover对象知道如何吸引其他Mover对象
PVector force = PVector.sub(location,m.location);
float distance = force.mag();
distance = constrain(distance,5.0,25.0);
force.normalize();
float strength = (G mass m.mass) / (distance * distance);
force.mult(strength);
return force;
}
}
4、小问题
当然,这里还有一个小问题。
- 用i和j遍历Mover数组时,碰到i等于j的情况该怎么办?
- 比如,Mover3对Mover3是否有吸引作用?
当然,Mover对自身是没有引力的。 - 如果同时有5个Mover,Mover3只对0、1、2、4有吸引作用,对自身并没有吸引作用。
- 因此,为了完成这个模型,我们需要加入一个简单的条件判断语句,在遍历时跳过i等于j的场景。
5、示例代码
示例代码2-8 万有引力
Mover[] movers = new Mover[20];
float g = 0.4;
void setup() {
size(640,360);
for (int i = 0; i < movers.length; i++) {
movers[i] = new Mover(random(0.1,2),random(width),random(height));
}
}
void draw() {
background(255);
for (int i = 0; i < movers.length; i++) {
for (int j = 0; j < movers.length; j++) {
if (i != j) {
PVector force = movers[j].attract(movers[i]);
movers[i].applyForce(force);
}
}
movers[i].update();
movers[i].display();
}
}
mover.pde
class Mover {
PVector position;
PVector velocity;
PVector acceleration;
float mass;
color c;
Mover(float m, float x, float y) {
mass = m;
position = new PVector(x, y);
velocity = new PVector(0, 0);
acceleration = new PVector(0, 0);
c = color(random(255),random(255),random(255));
}
void applyForce(PVector force) {
PVector f = PVector.div(force, mass);
acceleration.add(f);
}
void update() {
velocity.add(acceleration);
position.add(velocity);
acceleration.mult(0);
}
void display() {
stroke(0);
strokeWeight(2);
//fill(0, 100);
fill(c);
ellipse(position.x, position.y, mass*24, mass*24);
}
PVector attract(Mover m) {
PVector force = PVector.sub(position, m.position); // Calculate direction of force
float distance = force.mag(); // Distance between objects
distance = constrain(distance, 5.0, 25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects
force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction
float strength = (g * mass * m.mass) / (distance * distance); // Calculate gravitional force magnitude
force.mult(strength); // Get force vector --> magnitude * direction
return force;
}
}
网友评论