【互動編程作業】粒子系統——粒子系統的實現

前言

在《代碼本色》的第4章 粒子系統 中,主要講到了粒子系統的實現、多態和繼承實現面向對象以及通過力的作用體現自然系統。以下爲第4章的內容目錄:
在這裏插入圖片描述
針對粒子系統的實現、多態和繼承實現面向對象以及通過力的作用體現自然系統,我展開了自己的習作。

關於習作

學習了《代碼本色》第4章 粒子系統 的內容之後,我想要在我的習作中表現的元素有:

  1. 鼠標的交互
  2. 粒子系統的生成
  3. 隨機點的生成
  4. 排斥力的體現

其中,鼠標的交互和粒子系統的生成,體現在我鼠標在界面中移動即在我鼠標位置生成粒子系統;隨機點的生成體現在界面中隨機生成點圈圈;排斥力體現在界面中的大圓,所有的點(包括隨機生成的和粒子系統生成的)經過界面時都會繞開大圓(排斥)。
下面是效果圖和具體代碼實現:
在這裏插入圖片描述
可以看到,排斥力很明顯。

Particle.pde

class Particle {
  PVector position;
  PVector velocity;
  PVector acceleration;
  float lifespan;
  
  float r = 6;
  float mass = 1; // Let's do something better here!

  Particle(PVector l) {
    acceleration = new PVector(0,0);
    velocity = new PVector(random(-1,1),random(-2,0));
    position = l.get();
    lifespan = 255.0;
  }
  
  Particle(float x, float y) {
    acceleration = new PVector();
    velocity = PVector.random2D();
    position = new PVector(x, y);
    lifespan = 255.0;
  }

  void run() {
    update();
    display();
  }

  void applyForce(PVector force) {
    PVector f = force.get();
    f.div(mass);   
    acceleration.add(f);
  }

  // Method to update position
  void update() {
    velocity.add(acceleration);
    position.add(velocity);
    acceleration.mult(0);
    lifespan -= 2.0;
  }

  // Method to display
  void display() {
    stroke(0,lifespan);
    strokeWeight(2);
    fill(127,lifespan);
    ellipse(position.x,position.y,12,12);
  }

  // Is the particle still useful?
  boolean isDead() {
    if (lifespan < 0.0) {
      return true;
    } else {
      return false;
    }
  }
  
  void intersects(ArrayList<Particle> particles) {
    for (Particle other : particles) {
      if (other != this) {
        PVector dir = PVector.sub(position, other.position);
        if (dir.mag() < r*2) {
          dir.setMag(0.5); 
          applyForce(dir);
        }
      }
    }
  }
}

ParticleSystem.pde

class ParticleSystem {
  ArrayList<Particle> particles;
  PVector origin;

  ParticleSystem(PVector position) {
    origin = position.get();
    particles = new ArrayList<Particle>();
  }

  void addParticle() {
    particles.add(new Particle(origin));
  }
  void addParticle(float x, float y) {
    particles.add(new Particle(x, y));
  }

  // A function to apply a force to all Particles
  void applyForce(PVector f) {
    for (Particle p: particles) {
      p.applyForce(f);
    }
  }

  void applyRepeller(Repeller r) {
    for (Particle p: particles) {
      PVector force = r.repel(p);        
      p.applyForce(force);
    }
  }


  void run() {
    for (int i = particles.size()-1; i >= 0; i--) {
      Particle p = particles.get(i);
      p.run();
      if (p.isDead()) {
        particles.remove(i);
      }
    }
  }
  
  void intersection() {
    for (Particle p : particles) {
      p.intersects(particles);
    }
  }
  
  void display() {
    for (Particle p : particles) {
      p.display();
    }
  }
  
  void update() {
    for (int i = particles.size()-1; i >= 0; i--) {
      Particle p = particles.get(i);
      p.update();
      if (p.isDead()) {
        particles.remove(i);
      }
    }
  }
}

Repeller.pde

class Repeller {
  
  // Gravitational Constant
  float G = 100;
  // position
  PVector position;
  float r = 20;

  Repeller(float x, float y)  {
    position = new PVector(x,y);
  }

  void display() {
    stroke(0);
    strokeWeight(2);
    fill(175);
    ellipse(position.x,position.y,48,48);
  }

  // Calculate a force to push particle away from repeller
  PVector repel(Particle p) {
    PVector dir = PVector.sub(position,p.position);      // Calculate direction of force
    float d = dir.mag();                       // Distance between objects
    dir.normalize();                           // Normalize vector (distance doesn't matter here, we just want this vector for direction)
    d = constrain(d,5,100);                    // Keep distance within a reasonable range
    float force = -1 * G / (d * d);            // Repelling force is inversely proportional to distance
    dir.mult(force);                           // Get force vector --> magnitude * direction
    return dir;
  }  
}

sketch_4.pde

ParticleSystem[] parsys = new ParticleSystem[2];
Repeller[] repellers = new Repeller[12];

void setup() {
  size(800,600);
  for (int i = 0; i < parsys.length; i++){
    parsys[i] = new ParticleSystem(new PVector(width/2,50));
  }
  for (int i = 0; i < repellers.length; i++){
    repellers[i] = new Repeller(25+75*i,height/3);
    i++;
    repellers[i] = new Repeller(25+75*i,height/3*2);
  }
}

void draw() {
  background(200);
  parsys[0].addParticle(mouseX,mouseY);
  
  parsys[1].addParticle(random(width),random(height));
  // Apply gravity force to all Particles
  //PVector gravity = new PVector(0,0.2);
  //parsys[0].applyForce(gravity);
  
  for (int i = 0; i < repellers.length; i++){
    parsys[0].applyRepeller(repellers[i]);
    repellers[i].display();
    parsys[1].applyRepeller(repellers[i]);
    repellers[i].display();
  }
  parsys[0].run();
  
  parsys[1].update();
  parsys[1].intersection();
  parsys[1].display();
}

關於代碼

本次習作利用了面向編程的繼承性和多態性。

在Particle類和ParticleSystem類中實現了粒子系統的定點生成與隨機生成;在Repeller類中實現了排斥物的實現。

主程序sketch_4.pde實現了界面的繪製,在程序中生成多個repeller和particle以及particleSystem。

其中,移動的鼠標點生成粒子系統其實就是在定點生成粒子的基礎上,加上了一個鼠標座標的mouseX和mouseY即可。

比較想說一下的是排斥力的實現,排斥力是在引力的基礎上,將引力的大小乘以-1,公式是:force = -1 * G / (d * d);這樣就實現了排斥力,在圖中效果比較明顯。

發佈了27 篇原創文章 · 獲贊 22 · 訪問量 5230
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章