你的意图:所需速度
2022-07-03 本文已影响0人
大龙10
书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
第6章目录
6.5 你的意图:所需速度
1、行为的模拟
- 前面我们学会了两种行为的模拟——寻找和到达。
- 在模拟过程中,我们要分别针对这两种行为计算一个向量:所需速度。
- 实际上,Reynolds提出的所有转向行为都基于这个公式,本章会涵盖其他行为——流场、路径跟随和群集。
- 我还是要强调:它们只是示例,只是为了展示动画中常用的转向行为;它们并不是全部行为,你能做的远远不止这些。
- 只要设计一种新的所需速度计算方式,就相当于创造了新的转向行为。
2、游走(wandering)行为
- 在游走(wandering)行为中,Reynolds是这么定义所需速度的:
“游走是一种随机性转向,它有一种远期秩序——下一帧的转向角度和当前帧的转向角度相关。这种移动方式比单纯为每一帧产生随机方向更有趣。” - 在Reynolds看来,游走的目标并不是随机运动,而是在某一小段时间内朝着一个方向运动,在下一小段时间朝着另一个方向运动,如此往复
- 这里有一个问题,Reynolds如何计算游走行为的所需速度?
-
在图6-12中,小车把自己前方某处当作未来位置,在这个未来位置上画一个半径为r的圆圈,并在圆上随机选择一个点,在每一帧动画中,这个点都是随机确定的。我们可以把这个点当做目标位置,并由此计算所需速度。
-
你可能会觉得这种做法不是很合理,因为它看起来有些随意。实际上,这是一种很巧妙的方案:它利用随机性驱动小车的转向,还利用圆圈的轨迹限制随机性。
-
这种随机的方案解释了我之前提出的观点——这些虚构的行为源自现实世界的运动。你可以计算自己的所需速度,并由此构建更复杂的模拟场景。
3、“留在墙内”的转向行为
-
假设我们想创建一种名为“留在墙内”的转向行为,它的所需速度如下:
如果小车和墙之间的距离小于d,它应该以最大的速度朝着墙的反方向运动。
图6-13 -
我们把Processing的窗口边缘当做墙,让d等于25像素,就可以简单地用示例代码6-3中的代码模拟这种行为:
4、示例
Vehicle v;
boolean debug = true;
float d = 25;
void setup() {
size(640, 360);
v = new Vehicle(width/2, height/2);
}
void draw() {
background(255);
if (debug) {
stroke(175);
noFill();
rectMode(CENTER);
rect(width/2, height/2, width-d*2, height-d*2);
}
v.boundaries();
v.run();
}
void mousePressed() {
debug = !debug;
}
Vehicle.pde
class Vehicle {
PVector position;
PVector velocity;
PVector acceleration;
float r;
float maxspeed;
float maxforce;
Vehicle(float x, float y) {
acceleration = new PVector(0, 0);
velocity = new PVector(3, -2);
velocity.mult(5);
position = new PVector(x, y);
r = 6;
maxspeed = 3;
maxforce = 0.15;
}
void run() {
update();
display();
}
// Method to update position
void update() {
// Update velocity
velocity.add(acceleration);
// Limit speed
velocity.limit(maxspeed);
position.add(velocity);
// Reset accelertion to 0 each cycle
acceleration.mult(0);
}
void boundaries() {
PVector desired = null;
if (position.x < d) {
desired = new PVector(maxspeed, velocity.y);
}
else if (position.x > width -d) {
desired = new PVector(-maxspeed, velocity.y);
}
if (position.y < d) {
desired = new PVector(velocity.x, maxspeed);
}
else if (position.y > height-d) {
desired = new PVector(velocity.x, -maxspeed);
}
if (desired != null) {
desired.normalize();
desired.mult(maxspeed);
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxforce);
applyForce(steer);
}
}
void applyForce(PVector force) {
// We could add mass here if we want A = F / M
acceleration.add(force);
}
void display() {
// Draw a triangle rotated in the direction of velocity
float theta = velocity.heading2D() + radians(90);
fill(127);
stroke(0);
pushMatrix();
translate(position.x, position.y);
rotate(theta);
beginShape(TRIANGLES);
vertex(0, -r*2);
vertex(-r, r*2);
vertex(r, r*2);
endShape();
popMatrix();
}
}