相连的系统I:绳子

书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
目录

5.18 相连的系统I:绳子

1、模拟柔软物体

  • 在上例中,两个粒子对象通过一根弹簧相连。
  • toxiclibs物理库尤其适用于模拟柔软物体,
  • 比如可以用连接成一条线的粒子模拟绳子,
  • 可以用连接在一起的粒子网格模拟毯子。
  • 下面这个可爱的卡通模型也可以用相连的粒子进行模拟,这些粒子都通过弹簧相连。


    图5-14

2、模拟一个“柔软的钟摆”模型

  • 下面我们要模拟一个“柔软的钟摆”模型——将摆球挂在绳子的底端,这里的摆臂不再是第3章里使用的刚性摆臂,而是图5-14所示的“绳子”。

1)首先,我们需要一个粒子列表

(使用上例的Particle类)

ArrayList<Particle> particles = new ArrayList<Particle>();
  • 假如我们需要20个粒子,它们之间的间隔是10个像素。


    图5-15
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相连……


    图5-16
  • 也就是:粒子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" 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);
  }
}

4、运行结果

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容