【互动媒体创意编程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中用粒子系统实现的烟花