书名:代码本色:用编程模拟天然体系
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
目次
5.18 相连的体系I:绳子
1、模拟柔软物体
- 在上例中,两个粒子对象通过一根弹簧相连。
- toxiclibs物理库尤其实用于模拟柔软物体,
- 好比可以用毗连成一条线的粒子模拟绳子,
- 可以用毗连在一起的粒子网格模拟毯子。
- 下面这个可爱的卡通模子也可以用相连的粒子举行模拟,这些粒子都通过弹簧相连。
2、模拟一个“柔软的钟摆”模子
- 下面我们要模拟一个“柔软的钟摆”模子——将摆球挂在绳子的底端,这里的摆臂不再是第3章里使用的刚性摆臂,而是图5-14所示的“绳子”。
1)起首,我们须要一个粒子列表
(使用上例的Particle类)
ArrayList< article> particles = new ArrayList< article>();
- 假如我们须要20个粒子,它们之间的隔断是10个像素。
float len = 10;float numParticles = 20;
- 我们可以将下标i从0递增到20,将每个粒子的y坐标设置成i * 10,如许一来,第1个粒子位于坐标(0,10),第2个粒子位于(0,20),第3个粒子位于(0,30)……
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();
- 假如想要绘制绳子上的全部粒子,我们可以从ArrayList获取全部的粒子位置,再调用beginShape()函数、endShape()函数和vertex()函数绘制它们。
3、示例
示例代码5-11 柔软的钟摆
import toxi.physics2d.*;import toxi.physics2d.behaviors.*;import toxi.geom.*;// Reference to physics "world" (2D)VerletPhysics2D physics;// Our "Chain" objectChain 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< article> 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< article>(); 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); }}4、运行效果
|