基于processing的海洋场景模拟
前言
正如《代码本色》一书所言,用程序编写自然现象本身就是很有趣的事情。编程不仅能处理网页请求、计算账目、储存数据,还可以创造出富含自然现象的虚拟世界。在这个世界里,你是整个世界的造物者,你可以凭借一行行代码绘制出广袤的草原、波澜壮阔的大海、唯美浪漫的雪天等等等等。在这次的作业中,我以海洋为背景,尝试模拟相关的场景,并且可以通过鼠标的操作进行交互。话不多说,一起来看看这个模拟场景都有哪些部分组成吧!
整体介绍
海洋模拟场景共由波浪、海洋植物、海洋生物三部分组成。波浪可随着时间的变化实现波动;共出现三种海洋生物:会吐泡泡的小丑鱼、会喷墨汁的墨鱼以及“瞬移”的章鱼。小鱼们吐出的泡泡均由粒子系统生成。如下图所示,每次画面会随机出现一种生物,点击左键可吸引生物向鼠标所在位置移动,点击右键可触发生物所特有的动作。(注意看鼠标的位置)
部分功能及类介绍
1、海洋生物类
父类
海洋小鱼千万条,使用继承第一条。继承不规范,程序员两行泪。这是一个由各种海洋生物构成的世界,这些生物都有着一些相同的属性,例如他们都是有质量的,他们在运动过程中都需要速度和加速度,以及在画面中他们需要有一个用坐标表示的位置。如果每种海洋生物都要写这样一段重复的代码看起来效率实在太低。但还好我们有类的继承可以使用,用来帮助我们把代码变得更加简洁且美观。我们首先写一个泛型的海洋生物类,它包括海洋生物的一些共有属性以及共有动作。这里的代码可能需要一点java语言的基础,因为重点在于介绍整个场景的模拟,所以语法就不多进行解释了。
PImage img; //每一种生物的外观图片
int classfy; //分类标识
PVector location;
PVector velocity;
PVector acceleration;
float mass;
//构造函数
Animal(){
location=new PVector(1200,400);
}
void run() {
update();
drawanimal();
}
//绘制海洋生物
void drawanimal(){
image(img, location.x,location.y);
}
//更新海洋生物状态
void update(){
if(this.location.y<300|this.location.y>550){
this.velocity.y=this.velocity.y*(-1);
}
velocity.add(acceleration);
location.add(velocity);
acceleration.mult(0);
}
//受到力的作用
void applyforce(PVector force){
PVector f=force.get();
f.div(mass);
acceleration.add(f);
}
子类
1.小丑鱼
会吐泡泡的小丑鱼拥有父类所没有的“吐泡泡”方法。这里的粒子系统会在后文中进行解释,在这里你只需要知道它可以在指定位置新产生一串泡泡。
void fishblue(){
now=location.get();
systems.add(new ParticleSystem(now.sub(new PVector(60,-15)),255));
}
2.墨鱼
像小丑鱼一样,墨鱼的独特本领是可以喷出黑色的墨汁并在力的作用下向上移动。在这里的粒子系统与小丑鱼有些不同,总体结构一致,但由于吐出的泡泡受到较大的浮力,而墨汁有一个向下的很大的速度,因此两种粒子的颜色及运动状态有所差别。
void dolphinpump(){
now=location.get();
fill(255);
system1s.add(new ParticleSystem1(now.add(new PVector(0,50)),0));
location.add(new PVector(0,-20));
}
3.章鱼
章鱼通过喷射水流形成反作用力推动身体前进,当遇到袭击时,章鱼可以迅速移动,放出“闪现”大招。
void jump(){
now=location.get();
location.add(new PVector(0,-50));
}
2.粒子系统类
不管是一连串的泡泡还是喷涌而出的墨汁,其本质都是由一个个小的圆圈组成,而若干个小圆圈组成了一个粒子系统类。在每次点击鼠标触发动效时,我们都需要创建一个粒子系统,我们可以建立一个列表用来储存这样由点击而生成的例子系统。首先,我们从最简单的一个粒子开始入手。
1.单个粒子类 class Particle
(1)粒子的构造函数
我们在前面提到过墨汁和泡泡有些许差异,那在最开始对粒子进行初始化的时候就应该有所体现。我们将粒子的位置、颜色、速度作为参数以获得不同种类的粒子。为了使粒子的出现更加真实,我们使用随机函数将其位置进行些许改变。
Particle(PVector l,int colorbom,PVector speed){
colorboom=colorbom;
radis=random(10,25);
location=l.get();
location.add(new PVector(random(-10,10),random(-20,10)));
acceleration=new PVector(0,0);
velocity = speed;
lifespan=500+random(-100,100);
}
(2)粒子的受力情况
既然是一个造物主,那必然少不了用力控制物体的运动。物理学的运动公式在这里不展开叙述,我们所知道的是当物体受力时的速度变化情况与力的大小及物体本身质量相关。而在我们模拟引力过程中,引力的大小也受到距离、物体质量的影响。
泡泡在水中受到浮力,因此我们可以看到,大泡泡以更快的速度上升(因其体积大所受浮力大),小泡泡的速度则慢一些。
而墨汁在喷射的一瞬间会有很大的速度,但之后会受浮力作用向上漂浮,最终消失。
在这里我们用 f 获得力的大小,防止出现所施加的力不断累积的情况。
void applyforce(PVector force){
PVector f=force.get();
f.div(mass);
acceleration.add(f);
}
(3)粒子的消亡
如果一个粒子系统只产生粒子而没有粒子消亡,势必会影响整个代码运行的流畅性,最直观的感受就是运动卡顿。我们设置粒子消亡的条件,当满足这个条件时我们便让其移除。在变化过程中,我们逐渐增加透明度使其随着存在时间的增长而逐渐消失。
boolean isDead(){
if (location.y < 200.0){
return true;
}else {
return false; }
}
2.粒子系统类 ParticleSystem
(1)粒子的增加
所谓的粒子系统,实质上是若干个粒子组成的ArrayList,如果你对ArrayList感到些许陌生,你可把它看成另一个版本(语法不相同)的数组。它储存了若干个Particle类型的粒子,通过addParticle()函数增加粒子。
void addParticle(){
if(paticlenum<15){
particles.add(new Particle(origin,colorboom,new PVector(random(-1,1),random(0,-1))));
paticlenum=paticlenum+1;
}
}
(2)粒子系统的运行
储存粒子的ArrayList已经准备好了,接下来就是如何把一个个的粒子拿出来“大展身手”了。在这里我们用到了迭代器遍历并删除已经被判处“死刑”的粒子。
void run(){
Iterator<Particle> it = particles.iterator();
while (it.hasNext()) {
Particle p = it.next();
float gravity=0.9*PI*p.radis*p.radis*3/4;
p.applyforce(new PVector(0,gravity));
float fuli=PI*p.radis*p.radis*3/4*-1;
p.applyforce(new PVector(0,fuli));
p.run();
if (p.isDead()) {
it.remove();
}
}
}
3.波浪的变换
随机出现的波浪变化莫测,而实现它只需要一个简单的函数noise(),noise()函数可以有1~3个参 数,分别代表一维、二维和三维的随机数。在这里我们需要它根据时间的变化生成不同的海水高度,也就是一个二维随机数。noise()函数实质上是Perlin噪声算法的实现,而Perlin噪声算法可用于生成各种自然特效, 包括云层、地形和大理石的纹理。这样就可以让海平面看起来更加真实。
stroke(color(50,117,185));
float x = 0;
while (x < width) {
line(x, 200 + 50 * noise(x / 100, time), x, height);
x = x + 1;
}
time = time + 0.02;
总结
在这次的场景模拟中,我使用粒子系统模拟墨汁及泡泡的生成,其中涉及到引力、重力、浮力等向量的相互作用。与此同时,为了使场景更加真实,使用Perlin噪声生成起伏的海面。作为一个交互系统,鼠标的左右键是主要的交互工具,针对不同生物鼠标的右键可触发与生物特性相匹配的交互效果。
希望我的博文可以给你带来一点参考,感谢阅读!
参考资料
1.https://github.com/nature-of-code/noc-examples-processing
2.http://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=海洋生物图片