书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
第6章目录
6.11 群/体行为(不要碰到对方)
ArrayList<Vehicle> vehicles; 声明由小车对象组成的ArrayList
void setup() {
vehicles = new ArrayList<Vehicle>; 用一系列小车对象填充ArrayList
for (int i = 0; i < 100; i++) {
vehicles.add(new Vehicle(random(width),random(height)));
}
}
void draw(){
for (Vehicle v : vehicles) {
v.update();
v.display();
}
}
v.seek(mouseX, mouseY);
v.separate();
v.separate(vehicles);
ArrayList<Vehicle> vehicles;
void setup() {
size(320,240);
vehicles = new ArrayList<Vehicle>();
for (int i = 0; i < 100; i++) {
vehicles.add(new Vehicle(random(width),random(height)));
}
}
void draw() {
background(255);
for (Vehicle v : vehicles) {
v.separate(vehicles); 这是本节加入的新东西,小车在计算分离转向力时需要检查其他所有对
v.update();
v.display();
}
}
这只是一个开头,真正的操作在separate()函数中实现。我们先思考这个函数的实现方式。Reynolds提到:“用转向避免拥堵”,也就是说,如果某辆小车和你的距离太近,你应该转向以远离它。对此你是否觉得很熟悉?“寻找行为”指的是朝着目标转向,将“寻找行为”的转向力反转,就能得到躲避行为的转向力。
但如果同时有多辆小车的距离都很近,这时候该怎么做?在这种情况下,我们可以对所有远离小车的向量求平均值,用平均向量计算分离行为的转向力。
float desiredseparation = 20; 这个变量指定最短距离
for (Vehicle other : vehicles) {
float d = PVector.dist(location, other.location); 当前小车和其他小车之间的距离
if ((d > 0) && (d < desiredseparation)) { 如果小车的距离小于20像素,这里的代码就会执行
}
}
注意:在上面的代码中,我们不只检查距离是否小于desiredseparation(过于接近!),还要检查距离是否大于0。这么做是为了确保小车不会意图和自身分离。所有小车对象都在ArrayList中,一不小心你就会让一辆小车与自身发生比较。
if ((d > 0) && (d < desiredseparation)) {
PVector diff = PVector.sub(location, other.location); 一个指向远离其他小车方向的向量
diff.normalize();
}
PVector sum = new PVector(); 从一个空向量开始
int count = 0;
for (Vehicle other : vehicles) { 我们还要记录有多少辆小车的距离过近
float d = PVector.dist(location, other.location);
if ((d > 0) && (d < desiredseparation)) {
PVector diff = PVector.sub(location, other.location);
diff.normalize();
sum.add(diff); 将所有向量加在一起,并递增计数器
count++;
}
}
if (count > 0) { 必须确保至少找到一辆距离过近的小车,然后才执行除法操作(避免除零的情况!)
sum.div(count);
}
if (count > 0) {
sum.div(count);
sum.setMag(maxspeed); 延伸至最大速率(使其成为所需速度)
PVector steer = PVector.sub(sum,vel); Reynolds的转向力公式
steer.limit(maxforce);
applyForce(steer); 将力转化为小车的加速度
}
示例代码6-7 群集行为:分离
void separate (ArrayList<Vehicle> vehicles) {
float desiredseparation = r*2; 分离的距离取决于小车的尺寸
PVector sum = new PVector();
int count = 0;
for (Vehicle other : vehicles) {
float d = PVector.dist(location, other.location);
if ((d > 0) && (d < desiredseparation)) {
PVector diff = PVector.sub(location, other.location);
diff.normalize();
diff.div(d); 计算小车和其他小车之间的距离:距离越近,分离的幅度越大;距离越远,分离sum.add(diff);
count++;
}
}
if (count > 0) {
sum.div(count);
sum.normalize();
sum.mult(maxspeed);
PVector steer = PVector.sub(sum, vel);
steer.limit(maxforce);
applyForce(steer);
}
}