第0章(引言)
本章主要讲解了如何实现随机游走。
传统的随机游走用random()生成一定范围内的随机数来实现,而本章中则引进了一个新的生成随机的方法:Perlin噪声。
柏林噪声被称为自然噪声生成算法,因为它可以很好的模拟一些自然效果,如云啊雾啊。因为它产生的效果是平滑的,因此非常自然,而用random()生成的呢,可能最大值接着最小值,整体来说数值变化相对跳跃。
本次实验中,简单地实现了一下随机游走:用一维的柏林噪声随机生成前进方向,用二维的柏林噪声随机生成小球颜色。
不进行刷新,保留轨迹:
class Walker{
float x;
float y;
float t1=3;
float t2=3;
float t3=3;
Walker(){
t1=3;
t2=12;
}
void display(){
//RGB分量随机生成
float bright=map(noise(t1,t2),0,1,0,255);
float bright1=map(noise(t2,t3),0,1,0,255);
float bright2=map(noise(t3,t1),0,1,0,255);
stroke(color(bright,bright1,bright2));
fill(color(bright,bright1,bright2));
//ellipse(mouseX, mouseY, 20, 20);
ellipse(x, y, 40, 40);
}
void step(){
//位置随机生成
x=map(noise(t1),0,1,0,width);
y=map(noise(t2),0,1,0,height);
t1=t1+0.01;
t2=t2+0.013;
t3=t2+0.016;
}
}
//调用上面的类实现随机游走
Walker w;
float t1=3;
float t2=3;
void setup(){
size(640,360);
w=new Walker();
background(255);
}
void draw(){
//background(255);
w.step();
w.display();
}
第1章(向量)
本章主要引入了数学中向量的概念,并演示了如何通过使用向量来改变物体的位置。具体操作主要是通过封装PVector类及其方法来实现。
本次实验中,尝试了通过使用向量的方法来使物体运动,并且物体碰到边界之后,向量反向,造成碰撞的效果。
主程序:
Mover[] movers = new Mover[20];
void setup() {
size(500,500);
//生成很多个小球
for (int i = 0; i < movers.length; i++) {
movers[i] = new Mover();
}
}
void draw() {
background(222);
for (int i = 0; i < movers.length; i++) {
movers[i].update();
movers[i].display();
}
}
Mover类:
class Mover {
PVector location;
PVector velocity;
PVector acceleration;
float topspeed;
float color1;
float color2;
float color3;
float size;
Mover() {
//大小、颜色、位置、速度随机生成
size=random(20,40);
color1=random(0,255);
color2=random(0,255);
color3=random(0,255);
location = new PVector(random(width),random(height));
velocity = new PVector(random(0,2),random(0,2));
topspeed = 5;
}
void update() {
PVector mouse = new PVector(mouseX,mouseY);
acceleration = PVector.sub(mouse,location);
acceleration.normalize();
acceleration.mult(0.04);
velocity.add(acceleration);
velocity.limit(topspeed);
location.add(velocity);
//实现边界碰撞效果
if ((location.x > width) || (location.x < 0)) {
velocity.x = velocity.x * -1;
}
if ((location.y > height) || (location.y < 0)) {
velocity.y = velocity.y * -1;
}
}
void display() {
noStroke();
fill(color1,color2,color3);
ellipse(location.x,location.y,size,size);
}
}
第2章(力)
本章主要讲述了如何通过代码来展现力的效果。
这里引入了速度、加速度、施加力等概念和方法。
这里主要实现了中心球体的万有引力效果,并且鼠标左键可拖拽,右键则是另一种与距离成正比的引力效果。
主程序:
Mover[] movers = new Mover[10];
Attractor a;
boolean choose;
void setup() {
size(640, 360);
for (int i = 0; i < movers.length; i++) {
movers[i] = new Mover(random(0.1, 2), random(width), random(height));
}
choose=true;
a = new Attractor();
}
void draw() {
background(255);
a.display();
a.drag();
a.hover(mouseX, mouseY);
for (int i = 0; i < movers.length; i++) {
//如果鼠标按下
if(mousePressed){
if(mouseButton==LEFT){
//如果左键单击,中心物体拖动
a.clicked(mouseX, mouseY);
}
//如果右键单击,另一种效果的力
if(mouseButton==RIGHT){
choose=false;
PVector force = a.bounce(movers[i]);
movers[i].applyForce(force);
}
}
//如果没有鼠标时间,那么万有引力
if(choose==true){
PVector force = a.attract(movers[i]);
movers[i].applyForce(force);
}
movers[i].update();
movers[i].display();
}
}
void mouseReleased() {
a.stopDragging();
choose=true;
}
Attractor类:
class Attractor {
float mass;
float G;
PVector location;
boolean dragging = false;
boolean rollover = false;
PVector dragOffset;
Attractor() {
location = new PVector(width/2,height/2);
mass = 20;
G = 1;
dragOffset = new PVector(0.0,0.0);
}
//计算万有引力
PVector attract(Mover m) {
PVector force = PVector.sub(location,m.location);
float d = force.mag();
d = constrain(d,5.0,25.0);
force.normalize();
float strength = (G * mass * m.mass) / (d * d);
force.mult(strength);
return force;
}
//计算另一种效果力
PVector bounce(Mover m){
PVector force=new PVector(0,0);
//float d = dist(m.location.x,m.location.y,location.x,location.y);
//if (d <=mass) {
force = PVector.sub(location,m.location);
force.mult(0.001);
//}
return force;
}
//中心物体对于光标位置改变的响应
void display() {
ellipseMode(CENTER);
strokeWeight(1);
stroke(0);
if (dragging) fill (255,1,100);
else if (rollover) fill(100);
else fill(127,255,11);
ellipse(location.x,location.y,mass*2,mass*2);
}
//实现中心物体鼠标拖拽
void clicked(int mx, int my) {
float d = dist(mx,my,location.x,location.y);
if (d < mass) {
dragging = true;
dragOffset.x = location.x-mx;
dragOffset.y = location.y-my;
}
}
void hover(int mx, int my) {
float d = dist(mx,my,location.x,location.y);
if (d < mass) {
rollover = true;
}
else {
rollover = false;
}
}
void stopDragging() {
dragging = false;
}
void drag() {
if (dragging) {
location.x = mouseX + dragOffset.x;
location.y = mouseY + dragOffset.y;
}
}
}
Mover类:
class Mover {
PVector location;
PVector velocity;
PVector acceleration;
float mass;
float color1;
float color2;
float color3;
//随机颜色
Mover(float m, float x, float y) {
mass = m;
color1=random(0,255);
color2=random(0,255);
color3=random(0,255);
location = new PVector(x, y);
velocity = new PVector(1, 0);
acceleration = new PVector(0, 0);
}
void applyForce(PVector force) {
PVector f = PVector.div(force, mass);
acceleration.add(f);
}
void update() {
velocity.add(acceleration);
location.add(velocity);
acceleration.mult(0);
}
void display() {
stroke(0);
strokeWeight(1);
fill(color1,color2,color3);
ellipse(location.x, location.y, mass*25, mass*25);
}
}
第3章(振荡)
本章设计到的内容比较多,有角速度、角加速度、正弦函数等。
这类主要在上一章引力效果的基础上进行改进。围绕中心物体旋转的小物体如今也可以旋转了,中心物体用鼠标左键拖拽,右键点击小物体则会停下旋转,同时按下“UP”键的话会统一顺时针旋转,按下“DOWN”键的话则会统一逆时针旋转。
在主程序中调用Attract类和Mover类:
Mover[] movers = new Mover[20];
Attractor a;
boolean choose;
void setup() {
choose=true;
size(640,360);
background(255);
//生成小物体
for (int i = 0; i < movers.length; i++) {
movers[i] = new Mover(random(0.1,2),random(width),random(height));
}
a = new Attractor();
}
void draw() {
background(255);
for (int i = 0; i < movers.length; i++) {
PVector force = a.attract(movers[i]);
movers[i].applyForce(force);
if(mousePressed){
if(mouseButton==LEFT){
a.clicked(mouseX,mouseY);
}
if(mouseButton==RIGHT){
choose=false;
movers[i].update1();
if(keyPressed){
if(keyCode==UP){
movers[i].turn(0.1);
}else if(keyCode==DOWN){
movers[i].turn(-0.1);
}
}
a.drag();
a.hover(mouseX,mouseY);
a.display();
movers[i].display1();
}
}
if(choose==true){
movers[i].update();
a.drag();
a.hover(mouseX,mouseY);
a.display();
movers[i].display();
}
}
}
void mouseReleased() {
a.stopDragging();
choose=true;
}
Attractor类:
class Attractor {
float mass;
PVector location;
float g;
boolean dragging = false;
boolean rollover = false;
PVector dragOffset;
Attractor() {
location = new PVector(width/2, height/2);
mass = 20;
g = 0.4;
dragOffset = new PVector(0.0,0.0);
}
PVector attract(Mover m) {
PVector force = PVector.sub(location, m.location);
float distance = force.mag();
distance = constrain(distance, 5.0, 25.0);
force.normalize();
float strength = (g * mass * m.mass) / (distance * distance);
force.mult(strength);
return force;
}
// Method to display
void display() {
stroke(33,1,1);
strokeWeight(2);
//noStroke();
if (dragging) fill(255,1,100);
else if (rollover) fill(100);
else fill(127,255,11);
ellipse(location.x, location.y, mass*2,mass*2);
}
void clicked(int mx, int my) {
float d = dist(mx,my,location.x,location.y);
if (d < mass) {
dragging = true;
dragOffset.x = location.x-mx;
dragOffset.y = location.y-my;
}
}
void hover(int mx, int my) {
float d = dist(mx,my,location.x,location.y);
if (d < mass) {
rollover = true;
}
else {
rollover = false;
}
}
void stopDragging() {
dragging = false;
}
void drag() {
if (dragging) {
location.x = mouseX + dragOffset.x;
location.y = mouseY + dragOffset.y;
}
}
}
第4章(粒子系统)
粒子系统首先要有单个的粒子类,用于生成粒子。然后在构造函数中对它的位置,加速度,速度等参数进行初始化,这里采用了随机范围内的速度和加速度。并且设置了两种粒子类型,通过随机数n的大小范围确定种类。
构造函数初始化:
Particle(PVector l,float n) {
choose=n;
acceleration = new PVector(random(-0.015,0.015),random(-0.01,0.01));
velocity = new PVector(random(-1,1),random(-1,1));
location = l.get();
lifespan = 255.0;
}
给与粒子速度和加速度:
void update() {
velocity.add(acceleration);
location.add(velocity);
lifespan -= 2.0;
}
粒子类型随机确定,choose是传进来的随机数
void display() {
stroke(0,lifespan);
strokeWeight(2);
fill(127,lifespan,255);
if(choose<0.6){
ellipse(location.x,location.y,20,20);
}else{
rect(location.x,location.y,10,10);
}
}
粒子是否消亡判断:
boolean isDead() {
if (lifespan < 0.0) {
return true;
} else {
return false;
}
}
}
单一的粒子类之后,要继续构造一个ParticleSystem类,用来统一生成粒子
class ParticleSystem {
ArrayList<Particle> particles;
PVector origin;
ParticleSystem(PVector location) {
origin = location.get();
particles = new ArrayList<Particle>();
}
void addParticle() {
particles.add(new Particle(origin,random(0,1)));
}
void addParticle(float x, float y) {
particles.add(new Particle(new PVector(x, y),random(0,1)));
}
void run() {
for (int i = particles.size()-1; i >= 0; i--) {
Particle p = particles.get(i);
p.run();
if (p.isDead()) {
particles.remove(i);
}
}
}
}
最后在主函数中调用粒子系统类就可以啦。