使用PVectors吸引粒子吸引力

时间:2015-12-03 19:44:27

标签: vector graphics processing particles

我在Processing 3.0中制作了一个粒子吸引子,当我添加多个我认为是'Nodes'的东西时,我遇到了困难;在没有鼠标输入的情况下自动吸引或排斥粒子的物体。通常左键单击鼠标会吸引这些粒子并右键单击它们。我制作节点,以便我可以同时吸引/排斥多个位置。

我遇到的主要问题是当我添加多个节点时,只有最后添加的节点才有效;所有其他人什么都不做。

以下是我的所有代码,包括其他两个类(粒子和节点)。这是很多代码,但如果有人可以指出我的错误,我真的很感激。

http://pastebin.com/iKELuVJ7

我认为问题出在Node for循环的Particle类中,我在设置acc = d,但我不知道一个好的解决方法。

作为一个额外的问题,有没有人知道一个好的方法来使吸引力的强度与吸引物体的距离成反比?我尝试了一个具有任意上限/下限的向后map()函数,现在可以使用,但我不想对它进行硬编码。任何其他一般改进/建议表示赞赏。

1 个答案:

答案 0 :(得分:1)

这是一幅漂亮的草图。你完全正确acc = d。 这部分:

for (Node n: nodes) {
     PVector d = PVector.sub(n.loc, loc);
     d.normalize();
     d.mult(n.strength);
     acc = d;
    }

意味着你要覆盖d的acc向量。 由于您运行循环,最后acc将等于列表中的最后一个节点。 如果您希望每个节点都有一定的影响力,只需将基于节点的向量添加到acc

for (Node n: nodes) {
     PVector d = PVector.sub(n.loc, loc);
     d.normalize();
     d.mult(n.strength);
     acc.add(d);
    }

你已经在鼠标互动中做到了这一点。

就其他建议而言,您可以尝试更频繁地缓存PVector实例。 Bellow我提供了一个如何缓存mousePosition的基本示例(作为单个顶级变量,而不是每个粒子,每帧多个实例)。 mag()使用sqrt(),费用可能很高。请尝试使用magSq()代替(并使用平方范围)。您可以通过Daniel Shiffman在chapter 6.15 A Few Last Notes: Optimization Tricks of Nature of Code中发现这些。我热烈推荐这本书。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
PVector m = new PVector(mouseX, mouseY); 

ArrayList<Particle> parts = new ArrayList<Particle>();
ArrayList<Node> nodes = new ArrayList<Node>();
float speed = 2;
float grav = 4;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup() {
  size(800, 800, P2D);
//  fullScreen(P2D);
  noStroke();
  smooth(4);
  blendMode(ADD);
  frameRate(60);
  for (int i = 0; i < 1000; i++) {
    parts.add(new Particle(new PVector(random(width), random(height)), (int)random(1, 25)));
  }
  nodes.add(new Node(new PVector(200, 400), 0.75));
  nodes.add(new Node(new PVector(400, 400), 0.50));
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void draw() {
  background(0);

  if(mousePressed){
    m.set(mouseX, mouseY);
  }

  for (Node n: nodes) {
    n.draw();
  }
  for (int i = 0; i < parts.size(); i++) {
     Particle p = (Particle) parts.get(i);
     p.draw();
     p.boundary();
  }
} 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class Particle {
  PVector loc, vel, acc;
  int size = 5;

  Particle(PVector loc, int size) {
    this.loc = loc;
    vel = new PVector();
    acc = new PVector();
    this.size = size;
  }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  void draw() {
    acc.mult(0);

    for (Node n: nodes) {
     PVector d = PVector.sub(n.loc, loc);
     d.normalize();
     d.mult(n.strength);
     //acc = d;
     acc.add(d);
    }


    if (mousePressed && mouseButton == LEFT) {
      PVector d = PVector.sub(m, loc);
      //d.normalize();
      d.setMag(map(d.mag(), 0, 2200, speed, 0));
      d.mult(speed);
      //acc = d;
      acc.add(d);
    } else if (mousePressed && mouseButton == RIGHT) {
      PVector d = PVector.sub(m, loc);
      d.normalize();
      d.mult(-1*speed);
      //acc = d;
      acc.add(d);
    }

    acc.set(acc);
    acc.mult(acc.mag());
    vel.add(acc);
    //vel.add(new PVector(0, grav));
    loc.add(vel);
    acc.mult(0);
    //vel.mult(pow(0.90, 0.1*size));
    vel.mult(0.97);

    colorScheme(0);//"RedYellow"
    ellipse(loc.x, loc.y, size, size);
  }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  void boundary() {
    if(loc.x < 0)
      vel.x *= -1;
    if(loc.x > width)
      vel.x *= -1;
    if(loc.y < 0)
      vel.y *= -1;
    if(loc.y > height)
      vel.y *= -1;
  }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 String[] patterns = {"RedYellow","RedMagenta","GreenYellow","GreenCyan","BlueMagenta","BlueCyan","Cyclic","BWCyclic","PROTOTYPE"};
  //void colorScheme(String pattern) {
  void colorScheme(int pattern) {
    //compute this once, rather than multiple times per case
    //also check out magSq() https://processing.org/reference/PVector_magSq_.html  
    float mag = vel.mag();
    switch (pattern) {
      case 0:
        fill(255, map(mag, 0, 20, 0, 255), map(mag - 20, 0, 20, 0, 255)); //Red Yellow White
        break;
      case 1:
        fill(255, map(mag - 20, 0, 20, 0, 255), map(mag, 0, 20, 0, 255)); //Red Magenta White
        break;
      case 2:
        fill(map(mag, 0, 20, 0, 255), 255, map(mag - 20, 0, 20, 0, 255)); //Green Yellow White
        break;
      case 3:
        fill(map(mag - 20, 0, 20, 0, 255), 255, map(mag, 0, 20, 0, 255)); //Green Cyan White
        break;
      case 4:
        fill(map(mag, 0, 20, 0, 255), map(mag - 20, 0, 20, 0, 255), 255); //Blue Magenta White
        break;
      case 5:
        fill(map(mag - 20, 0, 20, 0, 255), map(mag, 0, 20, 0, 255), 255); //Blue Cyan White
        break;
      case 6:
        fill(cos(map(mag, 0, 20, 0, 360))*255, cos(map(mag + 20/3, 0, 20, 0, 360))*255, cos(map(mag + 40/3, 0, 20, 0, 360))*255); //Cyclic
        break;
      case 7:
        fill(cos(map(mag, 0, 20, 0, 360))*255, cos(map(mag, 0, 20, 0, 360))*255, cos(map(mag, 0, 20, 0, 360))*255); //B&W Cyclic
        break;
      case 8:
        fill(0, 0, 0); //Cyclic
        break;
      default:
        stroke(255, 255, 255);
        fill(255, 255, 255);
        break;
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class Node {

  PVector loc;
  float strength;

  Node(PVector loc, float strength) {
    this.loc = loc;
    this.strength = strength;
  }

  void draw() {
    fill(255, 255, 255,64);
    ellipse(loc.x, loc.y, 50, 50);
  }
}

particles 1

particles 2

particles 3