如何在粒子系统处理中制作滑动构件

时间:2015-08-20 22:34:12

标签: spring processing simulation particle-system

我在Processing中模拟粒子系统。基于丹尼尔希夫曼的“本质的代码”一书,我做了一个弹簧,然后我开始尝试使用滑块做一个基于滑块的长度更长或更短的滑块。

现在,我试图制作一个滑块滑动,两个粒子移动到两个粒子的相同方向。 我使用PVector添加,找到新位置并绘制节点,但是当我有多个成员且一个受其他成员影响时,它不起作用。 我需要使用一个力来执行此操作:请参阅applyForce()函数。

void update(float distance) {
  PVector force = PVector.sub(b.location, a.location); 
  float d = force.mag();
  float x = d - distance;
 //direction of the force
  force.normalize();
  force.mult(-1 * k* x/mass);
 //apply to one node
  b.applyForce(force); 
  force.mult(-1);
 //apply opposite to the other node
  a.applyForce(force);
}

//Newton's law: F = M * A
void applyForce(PVector force) {
  PVector f = force.get();
  f.div(mass);
  acceleration.add(f);
}

检查下图:

diagram

(a)是我想要的,(b)就是现在这样做的。

在第一个例子中,长度相同,成员滑动(两个粒子)。

在第二个长度更大但不滑动

如果您知道如何施加滑动会员的力量,请告诉我。

谢谢

1 个答案:

答案 0 :(得分:3)

如果我理解正确,你会尝试做一些事情:

  1. 改变弹簧的长度
  2. 在春天的方向翻译春天的终点
  3. 使用滑块控制上述参数
  4. 第一部分是微不足道的,因为Spring对象具有len属性。 第二个涉及一点vector math

    1. 线的方向是减去它的两个端点
    2. 通过首先对矢量进行归一化(将其减小,使其长度等于1.0),然后乘以标量值,可以轻松地将矢量缩放到任意长度。
    3. 可以通过简单地向自身添加另一个向量来翻译向量
    4. 这是一个评论草图,实现了以上几点:

      //sliders to control spring rest length and translation
      Slider rlength = new Slider("rest length", 5, 5, 200, 20, 50, 250, 100, false);
      Slider translate = new Slider("translate", 5, 30, 200, 20, -10, 10, 0, false);
      
      Spring spring = new Spring(new Bob(75,350),new Bob(350,75),(int)rlength.value);
      
      void setup(){
        size(400,400);
        spring.k = 0.01;//tweak elasticity
      }
      void draw(){
        //  update
        //update sliders
        rlength.update(mouseX,mouseY,mousePressed);
        translate.update(mouseX,mouseY,mousePressed);
        //update spring
        spring.a.update();
        spring.b.update();
        spring.update();
        //make both points draggable
        spring.a.drag(mouseX, mouseY);
        spring.b.drag(mouseX, mouseY);
        //draw
        background(255);
        rlength.draw();
        translate.draw();
        spring.display();
      }
      //handle mouse events for spring points dragging
      void mousePressed() {
        spring.a.clicked(mouseX, mouseY);
        spring.b.clicked(mouseX, mouseY);
      }
      void mouseReleased() {
        spring.a.stopDragging();
        spring.b.stopDragging();
      }
      //handle slider events
      void onSliderUpdate(Slider s){
        if(s == rlength) spring.len = rlength.value;
        if(s == translate){
          //compute the direction of the spring by subtracting the two points
          PVector direction = PVector.sub(spring.a.location,spring.b.location);
          //normalize the vector -> it will not have a length/magnitude of 1.0, but will still point in the line direction
          direction.normalize();
          //scale or multiply the normalized vector to the translation amount
          direction.mult(translate.value);
          //finally, add the result to each spring point, essentially offsetting/translating
          spring.a.location.add(direction);
          spring.b.location.add(direction);
        } 
      }
      //Slider
      class GUIElement{
        float w,h,x,y;//width, height and position
        color bg = color(200);//background colour
        color fg = color(0);//foreground colour
        String label;
        GUIElement(String label,float x,float y,float w,float h){
          this.x = x;
          this.y = y;
          this.w = w;
          this.h = h;
          this.label = label;
        }
        void update(int mx,int my,boolean md){}
        void draw(){}
      }
      class Slider extends GUIElement{
        float min,max,value,pvalue;//slider values: minimum, maximum and current
        float cx,pw = 20;//current slider picker position, picker width
      
        boolean updating,liveDrag = true,isInt = false;
        //label to display on slider, it's position(x,y), size(w,h) and values(min, max and default/current)
        Slider(String label,float x,float y,float w,float h,float min,float max,float value,boolean isInt){
          super(label,x,y,w,h);
          this.min = min;
          this.max = max;
          this.value = value;
          this.isInt = isInt;
          cx = map(value,min,max,x,x+w);
        }
        void update(int mx,int my,boolean md){
          if(md){
            if((mx >= x && mx <= (x+w)) &&
               (my >= y && my <= (y+h))){
              cx = mx;
              value = map(cx,x,x+w,min,max);
              updating = true;
              if(liveDrag){
                boolean updated = (isInt ? ((int)value != (int)pvalue) : (value != pvalue));
                if(updated){
                  pvalue = value;
                  onSliderUpdate(this);
                }
              }
            }else updating = false;
          }else{
            if(updating){
              updating = false;
              onSliderUpdate(this);
            }  
          }
        }
        void draw(){
          pushStyle();
          noStroke();
          fill(bg);
          rect(x,y,w,h);
          fill(fg,64);
          rect(x,y,cx-x,h);//this displays a rect that stretches based on the value
          fill(0);
          text(label+": "+(isInt ? (int)value : value),x+pw,y+h*.75);
          popStyle();
        }
        String toString(){
          return label + ":" + value;
        }
      }
      
      // The Nature of Code
      // Daniel Shiffman
      // http://natureofcode.com
      
      // Bob class, just like our regular Mover (location, velocity, acceleration, mass)
      
      class Bob { 
        PVector location;
        PVector velocity;
        PVector acceleration;
        float mass = 12;
      
        // Arbitrary damping to simulate friction / drag 
        float damping = 0.95;
      
        // For mouse interaction
        PVector dragOffset;
        boolean dragging = false;
      
        // Constructor
        Bob(float x, float y) {
          location = new PVector(x,y);
          velocity = new PVector();
          acceleration = new PVector();
          dragOffset = new PVector();
        } 
      
        // Standard Euler integration
        void update() { 
          velocity.add(acceleration);
          velocity.mult(damping);
          location.add(velocity);
          acceleration.mult(0);
        }
      
        // Newton's law: F = M * A
        void applyForce(PVector force) {
          PVector f = force.get();
          f.div(mass);
          acceleration.add(f);
        }
      
      
        // Draw the bob
        void display() { 
          stroke(0);
          strokeWeight(2);
          fill(175);
          if (dragging) {
            fill(50);
          }
          ellipse(location.x,location.y,mass*2,mass*2);
        } 
      
        // The methods below are for mouse interaction
      
        // This checks to see if we clicked on the mover
        void clicked(int mx, int my) {
          float d = dist(mx,my,location.x,location.y);
          if (d < mass) {
            dragging = true;
            dragOffset.x = location.x-mx;
            dragOffset.y = location.y-my;
          }
        }
      
        void stopDragging() {
          dragging = false;
        }
      
        void drag(int mx, int my) {
          if (dragging) {
            location.x = mx + dragOffset.x;
            location.y = my + dragOffset.y;
          }
        }
      }
      
      // Nature of Code 2011
      // Daniel Shiffman
      // Chapter 3: Oscillation
      
      // Class to describe an anchor point that can connect to "Bob" objects via a spring
      // Thank you: http://www.myphysicslab.com/spring2d.html
      
      class Spring { 
      
        // Location
        PVector anchor;
      
        // Rest length and spring constant
        float len;
        float k = 0.2;
      
        Bob a;
        Bob b;
      
        // Constructor
        Spring(Bob a_, Bob b_, int l) {
          a = a_;
          b = b_;
          len = l;
        } 
      
        // Calculate spring force
        void update() {
          // Vector pointing from anchor to bob location
          PVector force = PVector.sub(a.location, b.location);
          // What is distance
          float d = force.mag();
          // Stretch is difference between current distance and rest length
          float stretch = d - len;
      
          // Calculate force according to Hooke's Law
          // F = k * stretch
          force.normalize();
          force.mult(-1 * k * stretch);
          a.applyForce(force);
          force.mult(-1);
          b.applyForce(force);
        }
      
      
        void display() {
          strokeWeight(3);
          stroke(0);
          line(a.location.x, a.location.y, b.location.x, b.location.y);
          ellipse(a.location.x, a.location.y,10,10);
          ellipse(b.location.x, b.location.y,10,10);
        }
      }
      

      Slider controlled Spring