【互动媒体创意编程1&2】万千星河都涌向你:向量、速度、力与加速度

【互动媒体创意编程1&2】万千星河都涌向你——向量、速度、力与加速度

这个代码把第一章和第二章融合到一起了。在这个程序里,我赋予了一群粒子三个不同的运动状态。
本来其实并没有把这两个试验写成一个的打算,只是写着写着突然发现他们需要被集合在一起。不仅它们需要在代码中被放到一起,而且我还需要在一起讲。
这个程序的效果是一开始我并没有能够预料到的。起初只是想要实现向量的计算,没想到在里面发现了一些力和噪声的成分。
首先放上效果图。
1.状态1:噪声实现的平凡随机游走
在这里插入图片描述
2.状态2:被吸引向鼠标位置加速运动。
在这里插入图片描述
3.状态3:粒子被吸向鼠标之后继续运动
在这里插入图片描述
4.状态4:粒子按照原有速度方向保持运动
在这里插入图片描述

1.随机游走

我们首先需要一个粒子系统作为运动的载体。
粒子系统在第四章讲,现在略过。
创建一个粒子系统:

  balls = new ArrayList<Ball>();
  for (int i = 0; i< 200; i++){
    Ball b = new Ball();
    balls.add(b);
  }

接下来只要为每一个粒子添加速度,让它随机游走就可。

    for (Ball b : balls){
      b.walk();
    }

Particle.walk()函数:


  public void walk(){
    time1 += 0.01; time2 += 0.01;
    PVector offset = new PVector(sin(noise(time1) * 10),cos(noise(time2) * 10));
    position.x += offset.x;
    position.y += offset.y;
    boundaryDetect();
    ellipse(position.x, position.y, mass, mass);
  }

其中有定义

    time1 = random(0, 10);time2 = random(0,10000);

time1和time2将作为构成规定随机游走的偏移量的noise()函数的参数、把time2设置地远大于time1是为了使offsetx和offsety尽量少有相关性,否则粒子将会有向固定方向偏移的趋势。

2.粒子群向鼠标位置加速追赶

我们需要表示这样的一个运动的趋势,即距离鼠标中心最远的粒子所受到的中心的吸引力越小。而这个吸引力我们希望它只作用一次,来为粒子施加一个加速度,给粒子一个运动的方向。这样,粒子在运动的过程中速度就会逐渐增大,直到到达鼠标的位置。
这里需要注意的问题是,由于我们希望粒子在每一帧都重新计算收到的力以及当前的加速度,我们需要在更新完速度之后把加速度再恢复为0。

  public void follow(){
    PVector target = new PVector(mouseX, mouseY);
    PVector direction = PVector.sub(target, position);
    
    float force = 1;
    acceleration = force/mass;
    velocity += acceleration;
    acceleration = 0;
    PVector offset = direction.normalize();
    position.x += offset.x * velocity;
    position.y += offset.y * velocity;
    walk();
    boundaryDetect();
    ellipse(position.x, position.y, mass, mass);
  }

我们希望能够按下鼠标,让原来正在随机游走的粒子对鼠标位置进行跟随,因此我们需要在draw()函数再弄个区分当前帧的时候粒子的运动状态及行为。
我们设置一个状态变量controlled。在draw()的绘图函数之前需要对它进行一个区别,即:

void draw(){
  fill(0, 20);
  rect(0, 0, width, height);
  noStroke();
  fill(255);
  
  if (controlled == 0)//not under control
  {
    for (Ball b : balls){
      b.walk();
    }
  }
  
  if (controlled == 1)//under control and only be forced onece.
  {
    for (Ball b : balls){
      b.follow();
    }
  }
}

(这使得我们能够在不同状态的时候进行不同的运动。)同时,我们也需要在鼠标事件中进行状态切换。

void mouseClicked(){
  //switch the state
  if (controlled == 0)controlled = 1;
  else controlled = 0;
  for (Ball b : balls)
  {
    b.reset();
  }
}

3.粒子群被吸引后的运动

代码在上面介绍过了,这里介绍一下速度和加速度以及位置的计算方法。
哎。没什么好讲的。找到速度的方向、单位化并乘上速率的值,而位置是由当前的位置以及速度计算而来,不多赘述。

完整代码:

主类:

//we require a random walker to show the movement toward human mouse.
int controlled = 0;
float time1 = 0; float time2 = 10000;
ArrayList<Ball> balls;

void setup(){
  size(1600, 800);
  background(0);
  smooth();
  balls = new ArrayList<Ball>();
  for (int i = 0; i< 200; i++){
    Ball b = new Ball();
    balls.add(b);
  }
}

void draw(){
  fill(0, 20);
  rect(0, 0, width, height);
  noStroke();
  fill(255);
  
  if (controlled == 0)//not under control
  {
    for (Ball b : balls){
      b.walk();
    }
  }
  
  if (controlled == 1)//under control and only be forced onece.
  {
    for (Ball b : balls){
      b.follow();
    }
  }
}

void mouseClicked(){
  //switch the state
  if (controlled == 0)controlled = 1;
  else controlled = 0;
  for (Ball b : balls)
  {
    b.reset();
  }
}

粒子类:

class Ball{
  PVector position;
  float mass;
  float time1,time2;
  float acceleration = 0;
  float velocity = 0;
  
  Ball(){
    position = new PVector(random(width), random(height));
    time1 = random(0, 10);time2 = random(0,10000);
    mass = random(2, 10);
  }

  public void walk(){
    time1 += 0.01; time2 += 0.01;
    PVector offset = new PVector(sin(noise(time1) * 10),cos(noise(time2) * 10));
    position.x += offset.x;
    position.y += offset.y;
    boundaryDetect();
    ellipse(position.x, position.y, mass, mass);
  }
  
  public void follow(){
    PVector target = new PVector(mouseX, mouseY);
    PVector direction = PVector.sub(target, position);
    
    float force = 1;
    acceleration = force/mass;
    velocity += acceleration;
    acceleration = 0;
    PVector offset = direction.normalize();
    position.x += offset.x * velocity;
    position.y += offset.y * velocity;
    walk();
    boundaryDetect();
    ellipse(position.x, position.y, mass, mass);
  }
  
  public void boundaryDetect(){
    if (position.x < 0) position.x = 0;
    if (position.x > width)position.x = width;
    if (position.y > height)position.y = height;
    if (position.y < 0)position.y = 0;
  }

  public void reset(){
    acceleration = 0;
    velocity = 0;
  }
}

【互动媒体创意编程0】柏林噪声生成的随机地形
【互动媒体创意编程3】小球弹跳:震荡
【互动媒体创意编程4】processing中用粒子系统实现的烟花

发布了153 篇原创文章 · 获赞 184 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/Ha1f_Awake/article/details/103837101