互动媒体编程习作——表现随机行为及牛顿运动学————参考学习《代码本色》书籍
【互动媒体编程习作————使用processing来编写】
使用processing来编写并拓展《代码本色》中的0~4章节程序
(1)第0章 随机游走
主要学习的知识点:
随机游走类;随机数(非均匀分布,均匀分布,自定义分布);Perlin噪声。
实现结果:(PS:第一个有些晃眼)
这个的实现是在noiseWalk例子的基础上,增加了对R,G,B的随机数取值,以及constrain函数,利用鼠标限制它的运动。
跟随鼠标指引的随机数Walks,是由紫色画点,并以生成的点为圆心画的圆为开头来游走;在写这个文章的时候突然想到,圆的半径可以利用随机数来形成:就出现了下图线描圈就好看一些了。
这些都是简单地将可更改的部分代码拼接在了一起,现在来看看示例代码中体现的原理:
第0章——随机游走模型引入了贯穿《代码本色》的两个关键问题:1.如何定义对象的行为规则,2.如何用 Processing模拟这些行为规则。
首先构建随机游走类;类要具有的特征 1】维持自身数据,在屏幕中的位置;2】执行某些动作(进行绘制和移动)。其次,介绍本章中主要的函数:Perlin噪声函数,processing的map函数。
Perlin函数:noise()函数的结果范围是固定的,它总是会返回一个介于 0~1的结果。并且是随着时间推移而发生变化的。例如,一维noise()中:
想让其在代码中变换数值我们就要改变noise()中的参数值,在一维中就是时间t;让t改变后我们得到的数值就会变化。
noise()的值只界定在(0,1)间,不满足变化;map函数来帮忙~map总共五个参数
如下,就将我们得到的数值映射到屏幕大小。
float n = noise(t);
float x = map(n, 0,1, 0,width) ;//用map()函数定制Perl in噪声的范围
指引画圈程序小结:
蓝色数值的改变,使用高斯随机数生成,只改变了G的数值,还用到constrain函数来限制随机数在0到255之间,
【constrain 函数的作用是限制一个值不超过最大值和最小值,可以用于防止物体越界。constrain(amt被约束值, low最小极限, high最大极限)】
float g = randomGaussian();//设置g值
sd = 20; mean = 200;
g = constrain((g * sd) + mean,0,255);
stroke(123,g,255);//颜色的使用
render()结束,是控制点跟随鼠标运动:
void step() {
float r = random(1);
if (r < 0.5) {//自定义概率有50%的几率朝着鼠标前进
int xdir = (mouseX-x);
int ydir = (mouseY-y);
if (xdir != 0) {
xdir /= abs(xdir);}
if (ydir != 0) {
ydir /= abs(ydir);}
x += xdir;
y += ydir;
} else {//剩余50%产生-2到2间的随机数
int xdir = int(random(-2, 2));
int ydir = int(random(-2, 2));
x += xdir;
y += ydir;}
x = constrain(x, 0, width-1);
y = constrain(y, 0, height-1);
}
}
炫彩小球小结:
这里用到了下一章节的向量思想,将我们之前定义的x,y用PVector position;来代替。主要代码块:
//Walker类中
noff = new PVector(random(1000),random(1000));//随机生成方向
position.x=constrain(position.x,mouseX,width);
position.y=constrain(position.y,mouseY,height);//用鼠标限制运动范围
ellipse(position.x, position.y, 48, 48);
void walk() {
position.x = map(noise(noff.x),0,1,0,width);
position.y = map(noise(noff.y),0,1,0,height);
noff.x += 0.01;
noff.y += 0.01;
}
//主函数中创立了多个对象;
w = new Walker[20];
for (int i = 0; i < w.length; i++) {
w[i] = new Walker(); }//间断生成
另外还有一个新的函数:
noiseDetail()——调整由Perlin噪声功能产生的细节的特征和水平。 类似于物理学中的谐波,噪声是在几个八度计算的。
int o = int(map(mouseX,mouseY,width,1,8));//八音度调节
noiseDetail(o,0.3);//调整由Perlin噪声功能产生的细节的特征和水平。
全部代码:0随机游走
(2)第一章 向量
主要学习的知识点:
- 向量的表示,碰撞小球,向量的的运算,加速度。
这一章主要是掌握利用向量来简化我们的代码,向量可以表示方向。在向量的基础我们可以对其增加力,给予其速度,感受小球的动态效果。程序的实现主要是体现加速度的变化——“朝着鼠标所在方向的加速度”。和随机游走一样,我们确立一个Mover类,用于在主函数中实例化。
class Mover {
PVector position;
PVector velocity;
PVector acceleration;
float topspeed;}
void update() {
PVector mouse = new PVector(mouseX,mouseY);
acceleration = PVector.sub(mouse,position);
acceleration.normalize();
acceleration.mult(0.2);
velocity.add(acceleration);
velocity.limit(topspeed);
position.add(velocity);}
实现结果:
实现鼠标所指方向给到Movers的加速度,同时通过画线来表示出从屏幕中心点处,到新的运动点位置,形成发散状烟花小球。其中加入了边缘弹回的机制,不让小球流失在外。
再加些附带值:屏幕四个顶角的牵扯线;不断更新颜色的刷新。
全部代码:第1章向量
(3)第二章 力
get 学习套路:
●理解力背后的原理。
●将力的公式分解成以下两部分:
如何计算力的方向?
如何计算力的大小?
主要学习的知识点:
牛顿第三运动定律,风力,质量;引力斥力,阻力,摩擦力。
1.力的累加:在忽略质量的前提下,“加速度=力”符合牛顿第二运 动定律。
mover.applyForce(wind);//风力
mover.applyForce(gravity);//重力
我们不需要在程序中记录加速度,因为它是根据当时的外力计算出来的。在每一帧中对加速度清零,以达到我们在每一次作用时,达到期望变化——最简单的方式,在update()函数的最后将加速度向量乘以0。
void update() {
velocity.add(acceleration);
location.add(velocity);
acceleration.mult(0); }
2.质量:对于实例化的多个物体,设定不同的质量
for (int i = 0; i < movers.length; i++) {
movers[i] = new Mover(random(0.8,6),0,0);//mass=random(0.1,8)质量随机 }
3.重力:加强模拟——根据质量改变重力大小
float m = mover2s[i].mass;
PVector gravity = new PVector(0,0.1*m);//模拟更准确
4.摩擦力:摩擦力的方向和物体运动的方向相反。要先将速度向量单位化,再将单位向量乘以-1。
PVector friction=velocity.get() ;
friction. normalize() ://向量单位化
friction.mult(-1) ;
5.流体阻力:
我们需要在Mover类中加入两个额外的函数:isInside()函 数用于判断Mover对象是否在流体对象内部,drag()函数计算并将流体阻力作用 在Mover对象上
实现结果:
根据力的累加、风力,质量,重力知识实现的结果为:
粉色小球在1/4区域运行;蓝色小球占满整个屏幕;wind风力的施加是利用Perlin噪声生成;并且点击鼠标产生风,释放鼠标后风力消失;会看到按下鼠标时,小球运动加剧。
if (mousePressed) {
PVector wind = new PVector(0.01,noise(t));
movers[i].applyForce(wind);
t+=0.1; }
全部代码:第2章 力
(4)第三章 振荡
主要学习的知识点:
角度,角运动,极坐标系和笛卡儿坐标系,指向运动的方向,波,三角函数。
1.弧度:用弧度表示一个角,弧度 = 2π × (角度 / 360);利用radian()函数,来转换你想要的角度:float angle = radians(60); rotate(angle);
2.角运动:本章中后续程序的展开都要依靠这个基础,
1>角度 = 角度 + 角速度
2>角速度 = 角速度 + 角加速度
**实现角度运动的加入只需三步:
①把与角运动相关的 变量加入到Mover类中——
class Mover {
float angle = 0;
float avelocity=0;
float aAcceleration=0;
②在update()函数中,用相同的算法同时更新Mover对象的位置和角度——
void update() (
velocity . add(acceleration);//常规的运动
location. add(velocity);
aVelocity +=aAcceleration;
angle +=aVelocity;//新的角运动
acceleration. mult(0);
③在display()函数中旋转对象——并且要给它一个角加速度!在代码中设置一个初始加速度。float aAcceleration = 0.01;
void display() {
pushMatrix(); //pushMatrix()和popMatrix()使图形的旋转不会影响程序的其他部分
translate(location.x,location.y); //将原点设为图形所在的位置
rotate(angle); //转过一定角度
rect(0,0,mass*16,mass*16);
popMatrix();}
在我最终实现的程序中,主要运用到的知识有:
1】spaceship控制转向时的“极坐标系和笛卡儿坐标系”
void turn(float a) {
heading += a;}//获得我们输入的数值
void thrust() {
float angle = heading - PI/2;
PVector force = new PVector(cos(angle),sin(angle));……………………
float theta = PI / 4;
float x = r cos(theta); //将极坐标(r,θ)转化为笛卡儿坐标
(x,y) float y = r sin(theta);
2】波:确立角度,角速度,振幅;根据角速度递增角度
例如:
for (int x = 0; x <= width; x += 24) {
float y = map(sin(angle),-1,1,height*4/5,height);
noStroke();
fill(238,233,233,120);
ellipse(x,y,30,30);
angle += angleVel;
}
总结为三步:
1.根据振幅和角度的正弦值计算y坐标; 2.在(x,y)位置画一个圆; 3.根据角速度递增角度。
3】弹力:主要是spring类;确立枢轴点
4】最后是将上一章的Attractor类改成弹力的写法。
全部代码为:第3章 振荡
(5)粒子系统
主要学习的知识点:
1.认识粒子系统:
粒子系统就是一系列独立对象的集合,这些对象通常用简单的图形或者点来表示。粒子系统可以用于模拟各种自然现象(比如 爆炸)。典型的粒子系统中都有一个发射器,发射器是粒子的源头,它控制粒子的初始属性, 包括位置、速度等。发射器发射的粒子可能是一股粒子,也可能是连续的粒子流,或 是同时包含这两种发射方式。**关键点:在一个典型的粒子系统中,粒子在发 射器中诞生,但并不会永远存在。**简言之就是“粒子会消亡。”加入生存期(lifespan)变量。
2.使用数组管理这些粒子对象:使用 Java的ArrayList类
ArrayList的使用,结合数组来关联的学习:
数组实现的:
ArrayList实现的:
《processing》中可以使用更简洁的方式:
一个典型的粒子系统会发射连续的 粒子流,因此每个draw()循环都会把新的粒子对象加入ArrayList。
利用remove()函数,可以非常方便地移除某个粒子对象(通过对象的下标)。
3.由单个粒子变为粒子系统:
用多态实现粒子系统:
假设没有多态类:
有了继承和多态就可以进行改进:
这一点也应该利用于编程实践中,之前有一些就是重复性操作后续可以进行调整。
实现结果:
(彩色喷雾粒子)对单个粒子进行更改做出特别组合。
全部代码:第4章 粒子系统
总结:
这几次实验探索下来,觉得可以将代码转变成美丽图案,是一件神奇之事。看似复杂,难懂的公式却可以组合出意想不到的图案,在于鼠标,键盘进行交互结合,又是一种奇妙的探索。最后,对于自己的编程实践,仍需要改进,对于这些概念只是了解了皮毛,没有深入探索。