【互动编程作业】粒子系统——粒子系统的实现

落花浮王杯 提交于 2019-12-16 02:00:01

前言

在《代码本色》的第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);这样就实现了排斥力,在图中效果比较明显。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!