书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
目录
5.18 相连的系统I:绳子
下面这个可爱的卡通模型也可以用相连的粒子进行模拟,这些粒子都通过弹簧相连。
(使用上例的Particle类)
ArrayList<Particle> particles = new ArrayList<Particle>();
假如我们需要20个粒子,它们之间的间隔是10个像素。
float len = 10;
float numParticles = 20;
for (int i=0; i < numPoints; i++) {
Particle particle=new Particle(i*len, 10); 沿着x轴摆放粒子
physics.addParticle(particle); 将粒子加入列表
particles.add(particle); 将粒子加入物理世界
}
除了将粒子对象加入toxiclibs的物理世界,我们还将它放入自己的列表中。尽管这有些多余,但后面可能会有很多条绳子,到时候我们可以方便地获知粒子被连在哪一条绳子上。
下面要做一件有趣的事:将所有的粒子连接在一起。粒子1和粒子0相连,粒子2和粒子1相连,粒子3和粒子2相连……
也就是:粒子i和粒子i - 1相连(除去i等于0的情况)。
if (i != 0) {
Particle previous = particles.get(i-1); 首先,我们需要前一个粒子的引用
VerletSpring2D spring = new VerletSpring2D(particle,previous,len,strength);
之后,我们需要在两个粒子之间创建弹簧连接,并指定弹簧的静止长度和强度(都是浮点数)
physics.addSpring(spring); 不要忘记将弹簧加入物理世界
}
Particle head=particles.get(0);
head.lock();
示例代码5-11 柔软的钟摆
import toxi.physics2d.*;
import toxi.physics2d.behaviors.*;
import toxi.geom.*;
// Reference to physics "world" (2D)
VerletPhysics2D physics;
// Our "Chain" object
Chain chain;
void setup() {
size(640, 360);
// Initialize the physics world
physics=new VerletPhysics2D();
physics.addBehavior(new GravityBehavior(new Vec2D(0, 0.1)));
physics.setWorldBounds(new Rect(0, 0, width, height));
// Initialize the chain
chain = new Chain(180, 20, 16, 0.2);
}
void draw() {
background(255);
// Update physics
physics.update();
// Update chain's tail according to mouse position
chain.updateTail(mouseX, mouseY);
// Display chain
chain.display();
}
void mousePressed() {
// Check to see if we're grabbing the chain
chain.contains(mouseX, mouseY);
}
void mouseReleased() {
// Release the chain
chain.release();
}
Chain.pde
class Chain {
// Chain properties
float totalLength; // How long
int numPoints; // How many points
float strength; // Strength of springs
float radius; // Radius of ball at tail
// This list is redundant since we can ask for physics.particles, but in case we have many of these
// it's a convenient to keep track of our own list
ArrayList<Particle> particles;
// Let's keep an extra reference to the tail particle
// This is just the last particle in the ArrayList
Particle tail;
// Some variables for mouse dragging
PVector offset = new PVector();
boolean dragged = false;
// Chain constructor
Chain(float l, int n, float r, float s) {
particles = new ArrayList<Particle>();
totalLength = l;
numPoints = n;
radius = r;
strength = s;
float len = totalLength / numPoints;
// Here is the real work, go through and add particles to the chain itself
for(int i=0; i < numPoints; i++) {
// Make a new particle with an initial starting position
Particle particle=new Particle(width/2,i*len);
// Redundancy, we put the particles both in physics and in our own ArrayList
physics.addParticle(particle);
particles.add(particle);
// Connect the particles with a Spring (except for the head)
if (i != 0) {
Particle previous = particles.get(i-1);
VerletSpring2D spring = new VerletSpring2D(particle,previous,len,strength);
// Add the spring to the physics world
physics.addSpring(spring);
}
}
// Keep the top fixed
Particle head=particles.get(0);
head.lock();
// Store reference to the tail
tail = particles.get(numPoints-1);
tail.radius = radius;
}
// Check if a point is within the ball at the end of the chain
// If so, set dragged = true;
void contains(int x, int y) {
float d = dist(x,y,tail.x,tail.y);
if (d < radius) {
offset.x = tail.x - x;
offset.y = tail.y - y;
tail.lock();
dragged = true;
}
}
// Release the ball
void release() {
tail.unlock();
dragged = false;
}
// Update tail position if being dragged
void updateTail(int x, int y) {
if (dragged) {
tail.set(x+offset.x,y+offset.y);
}
}
// Draw the chain
void display() {
// Draw line connecting all points
beginShape();
stroke(0);
strokeWeight(2);
noFill();
for (Particle p : particles) {
vertex(p.x,p.y);
}
endShape();
tail.display();
}
}
Particle.pde
class Particle extends VerletParticle2D {
float radius = 4; // Adding a radius for each particle
Particle(float x, float y) {
super(x,y);
}
// All we're doing really is adding a display() function to a VerletParticle
void display() {
fill(127);
stroke(0);
strokeWeight(2);
ellipse(x,y,radius*2,radius*2);
}
}