互动编程习作——表现随机行为及牛顿运动学
主题:创作一组编程习作,体现随机行为及牛顿运动学
要求:
编程语言与工具:编程工具不限;
作品:参考《代码本色》的第0~4章内容及其实例程序(自行在processing内下载),针对这5章分别编写1个习作(一共5个),每个习作都有不少于2个案例参考,且必须有一定的拓展;
报告:写一篇文章(也可以多篇文章,但最好有一个总的导航文章),发表为博文/推文等形式,描述运用的规律,若用到了数学/物理/化学等学科中的知识,要用平实易懂的语言介绍原理,尝试运用凝练的数学语言表达(公式、方程、推导等),特别要描述出这些原理如何在作品中呈现的。
第0章 引言
实现了由perlin噪声生成了随时间的变化而产生高速运动,参考了自定义的随机数和perlin噪声亮度
float tx=1;
float ty=1;
float t=1;
void setup()
{
size(600,800,P3D);
}
void draw()
{
loadPixels();
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
t++;
float bright = map(noise(tx,ty,t),0,1,0,random(0,50));
pixels[x+y*width] = color(bright);
ty+=0.01;
}
tx+=0.01;
}
updatePixels();
}
其中t代表的是时间,亮度则是通过random随机调整的
第1章 向量
实现了一个颜色随机变换的圆,在区域范围内能够利用WASD四个按钮进行相对应的移动,并且在圆遇到边界的时候会受到一个回弹的速度,参考了弹球程序,向量的速度和加速度。
class Mover
{
PVector location;
PVector velocity;
PVector acceleration;
float topspeed;
Mover()
{
location = new PVector(random(200),random(400));
velocity = new PVector(2.5,1);
topspeed = 5;
}
void update()
{
if(keyPressed)
{
if(key=='w')
{
acceleration = new PVector(0,-0.001);
acceleration.normalize();
acceleration.mult(0.2);
velocity.add(acceleration);
location.add(velocity);
}
if(key=='s')
{
acceleration = new PVector(0,0.001);
acceleration.normalize();
acceleration.mult(0.2);
velocity.add(acceleration);
location.add(velocity);
}
if(key=='a')
{
acceleration = new PVector(-0.001,0);
acceleration.normalize();
acceleration.mult(0.2);
velocity.add(acceleration);
location.add(velocity);
}
if(key=='d')
{
acceleration = new PVector(0.001,0);
acceleration.normalize();
acceleration.mult(0.2);
velocity.add(acceleration);
location.add(velocity);
}
velocity.limit(topspeed);
if ((location.x > width) || (location.x < 0)) {
velocity.x *= -10;
}
if ((location.y > height) || (location.y < 0)) {
velocity.y *= -10;
}
}
}
void display()
{
stroke(0);
fill(random(255),random(255),random(255));
ellipse(location.x,location.y,50,50);
}
}
Mover mover;
void setup()
{
size(600,800);
smooth();
mover = new Mover();
}
void draw()
{
background(100,100,100);
mover.update();
mover.display();
}
Mover类实现了这个程序的各项速度的关系,在小球碰到边界的时候速度这个时候变为反方向的,这也就造成了一种反弹的效果,各个按键按下去的时候,是在原来速度的基础之上再添加一个速度,同时实现了向量的的相加。
第2章 力和牛顿运动定律
实现了在一个空间内,一组小球做*落体运动,当接触到地面的时候小球静止,键盘上的A和D按键可以给小球添加一个向左或者向右的风力,让小球顺着方向运动,在碰到边界的时候会受到一个弹力,键盘上的W按键可以给小球一个向上的支持力,当松开W键时小球受到重力会下落,参考力的累加,质量的处理,外力的作用,地球引力和物体之间存在极小的引力。
class Mover{
PVector location;
PVector velocity;
PVector acceleration;
float mass;
float G=0.04;
Mover(float m,float x,float y){
location= new PVector(random(250,750),random(250,750));
velocity=new PVector(0,-1);
acceleration=new PVector(0,-1);
mass=m;
}
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(){
noStroke();
fill(80,80,80);
rect(0,750,1000,250);
fill(80,80,80);
rect(0,0,1000,250);
fill(80,80,80);
rect(750,0,250,1000);
stroke(0);
fill(255,0,0);
ellipse(location.x,location.y,30,30);
}
void checkEdge(){
if(location.x>735){
location.x=735;
velocity.x=-1;
}else if(location.x<15){
velocity.x=-1;
location.x=15;
}
if(location.y>735){
location.y=735;
velocity.y*=0;
}
if(location.y<265){
location.y=265;
velocity.y*=-1;
}
}
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;
}
}
Mover[] mover=new Mover[10];
void setup(){
size(1000,1000);
for(int i=0;i<mover.length;i++){
mover[i]=new Mover(random(0.1,2),random(width),random(height));
}
}
void draw(){
background(255);
for (int i=0;i<mover.length;i++){
for(int j=0;j<mover.length;j++){
if(i!=j){
PVector force=mover[j].attract(mover[i]);
mover[i].applyForce(force);
}
}
float m=mover[i].mass;
if(key=='A'){
PVector wind=new PVector(random(-1.5,0),0);
mover[i].applyForce(wind);}
if(key=='D'){
PVector wind=new PVector(random(0,1.5),0);
mover[i].applyForce(wind);}
if(mousePressed){
PVector tanli=new PVector(0,-5*m);
mover[i].applyForce(tanli);
}
PVector gravity=new PVector(0,1*m);
mover[i].applyForce(gravity);
mover[i].update();
mover[i].display();
mover[i].checkEdge();
}
}
Mover类和第二个实验中的大致相同,在碰到边界的时候小球的速度会变为反方向,同时,在落到地面的时候,小球就变为静止的样子,通过万有引力公式strength = -(Gmassm.mass) / (distance * distance);在小球之间添加了几乎可以忽略的引力
第3章 震荡
实现了两个圆在背景中间互相绕着做圆周运动,并且将波形代码进行改变,颜色随机转换成了如下图所示的图案,,同时在代码中实现了交互,通过鼠标的点击,可以在屏幕上出现一个一串绳子拉扯着一堆小球进行圆周运动,参考了波,角运动,钟摆以及弹力。
float startAngle = 0;
float angleVel = 0.1;
float r=75;
float theta=0.01;
float aVelocity = 0;
float aAcceleration = 0.001;
float angle1 = 0;
Pendulum p;
void setup() {
size(1000,1000);
p = new Pendulum(new PVector(width/2,10),125);
smooth();
}
void draw() {
background(255);
float angle = startAngle;
for(float theta=0.1;theta<=PI;theta+=0.5){
for (int x = 0; x <= width; x +=12) {
float y = map(cos(angle),-1,1,0,height);
stroke(0);
fill(random(0,255),random(0,255),random(0,255));
ellipse(x+5*sin(theta),y,48,48);
angle += angleVel;
//theta+=0.01;
if(theta>PI){
theta=0.01;
}
}
}
p.go();
fill(175);
stroke(0);
rectMode(CENTER);
translate(width/2,height/2);
rotate(angle1);
ellipse(50,0,50,50);
ellipse(-50,0,50,50);
aVelocity += aAcceleration;
angle1 += aVelocity;
}
class Pendulum {
PVector location;
PVector origin;
float r;
float angle;
float aVelocity;
float aAcceleration;
float damping;
Pendulum(PVector origin_, float r_) {
origin = origin_.get();
location = new PVector();
r = r_;
angle = PI/4;
aVelocity = 0.0;
aAcceleration = 0.0;
damping = 0.05;
}
void go() {
update();
display();
}
void update() {
float gravity = 0.4;
aAcceleration = (-1 * gravity / r)*sin(angle);
aVelocity += aAcceleration;
angle += aVelocity;
aVelocity = damping;
}
void display() {
location.set(3*r*sin(angle),7*r*cos(angle),3);
location.add(origin);
stroke(0);
if(mousePressed){
line(mouseX,mouseY,location.x,location.y+100);
fill(135,234,100);
ellipse(location.x,location.y+100,50,50);
line(mouseX,mouseY,location.x+50,location.y+100);
fill(20,23,200);
ellipse(location.x+50,location.y+100,50,50);
line(mouseX,mouseY,location.x-100,location.y-80);
fill(234,230,200);
ellipse(location.x-100,location.y-80,50,50);
line(mouseX,mouseY,location.x+150,location.y-100);
fill(60,255,200);
ellipse(location.x+150,location.y-100,50,50);
line(mouseX,mouseY,location.x-250,location.y+100);
fill(230,23,200);
ellipse(location.x-250,location.y+100,50,50);
}
}
}
位置 = 位置 + 速度
速度 = 速度 + 加速度
第4章 粒子系统
实现了在背景中将自定义的图形做成了粒子系统,并且通过鼠标的点击可以将存储的粒子系统生成,参考了ArrayList的使用,单个粒子的生成。
import java.util.Iterator;
ArrayList<Particle>particles;
ArrayList<ParticleSystem>systems;
Repeller repeller;
ParticleSystem ps;
void setup() {
size(1000,1000);
particles=new ArrayList<Particle>();
ps=new ParticleSystem(new PVector(width/2,50));
systems=new ArrayList<ParticleSystem>();
repeller = new Repeller(width/2+60,height/2);
smooth();
}
void mousePressed(){
systems.add(new ParticleSystem(new PVector(mouseX,mouseY)));
}
void draw(){
background(255);
particles.add(new Particle(new PVector(width/2,50)));
Iterator<Particle>it=particles.iterator();
PVector gravity=new PVector(0,0.5);
float dx = map(mouseX,0,width,-0.2,0.9);
PVector wind = new PVector(dx,0);
ps.applyForce(wind);
ps.applyForce(gravity);
for(int i = 0; i < 2; i++) {
ps.addParticle();
}
while(it.hasNext()){
Particle p=it.next();
p.run();
if(p.isDead()){
it.remove();
}
}
for(ParticleSystem ps:systems){
ps.run();
ps.addParticle();
}
}
class Particle{
PVector location;
PVector velocity;
PVector acceleration;
float lifespan;
float mass=1;
PShape s;
float angle=0;
float aVelocity = 0;
float aAcceleration = 0;
Particle(PVector l){
acceleration=new PVector(0,0.05);
velocity=new PVector(random(-1,1),random(-2,0));
location=l.get();
lifespan=255.0;
}
void run(){
update();
display();
}
void update(){
velocity.add(acceleration);
location.add(velocity);
lifespan-=2.0;
}
void display(){
noStroke();
float r=random(0,255);
float g=random(0,255);
float b=random(0,255);
fill(r,g,b,lifespan);
rect(location.x-30,location.y+30,60,20);
ellipse(location.x-30,location.y+40,20,20);
ellipse(location.x+30,location.y+40,20,20);
stroke(0,lifespan);
pushMatrix();
rotate(random(0,PI/4));
s=createShape();
s.beginShape();
s.vertex(location.x-10,location.y);
s.vertex(location.x,location.y);
s.vertex(location.x,location.y-10);
s.vertex(location.x+4,location.y-10);
s.vertex(location.x+4,location.y);
s.vertex(location.x+14,location.y);
s.vertex(location.x+14,location.y+4);
s.vertex(location.x+4,location.y+4);
s.vertex(location.x+4,location.y+20);
s.vertex(location.x,location.y+20);
s.vertex(location.x,location.y+4);
s.vertex(location.x-10,location.y+4);
s.vertex(location.x+50/2,location.y+18/2);
s.vertex(location.x+61/2,location.y+37/2);
s.vertex(location.x+83/2,location.y+43/2);
s.vertex(location.x+69/2,location.y+60/2);
s.vertex(location.x+71/2,location.y+82/2);
s.vertex(location.x+50/2,location.y+73/2);
s.vertex(location.x+29/2,location.y+82/2);
s.vertex(location.x+31/2,location.y+60/2);
s.vertex(location.x+17/2,location.y+43/2);
s.vertex(location.x+39/2,location.y+37/2);
s.endShape();
shape(s);
popMatrix();
}
void applyForce(PVector force){
PVector f=force.get();
f.div(mass);
acceleration.add(f);
}
boolean isDead(){
if(lifespan<0.0){
return true;
}else{
return false;
}
}
}
class ParticleSystem{
ArrayList<Particle> particles;
PVector origin;
ParticleSystem(PVector location){
origin=location.get();
particles=new ArrayList<Particle>();
}
void addParticle(){
particles.add(new Particle(origin));
}
void applyForce(PVector f){
for (Particle p: particles){
p.applyForce(f);
}
}
void applyRepeller(Repeller r){
for (Particle p: particles) {
PVector force = r.repel(p);
p.applyForce(force);
}
}
void run(){
Iterator<Particle>it=particles.iterator();
while (it.hasNext()){
Particle p=it.next();
p.run();
repeller.display();
if(p.isDead()){
it.remove();
}
}
}
}
class Repeller {
float strength = 100;
PVector location;
float r = 10;
Repeller(float x, float y) {
location = new PVector(x,y);
}
void display() {
stroke(255);
fill(255);
ellipse(location.x, location.y, r*2, r*2);
}
PVector repel(Particle p) {
PVector dir = PVector.sub(location, p.location);
float d = dir.mag();
dir.normalize();
d = constrain(d, 5, 100);
float force = -1*strength / (d*d);
dir.mult(force);
return dir;
}
}
运用createShape()自己构造了五角星与十字架这两个图案,让他们在一定的角度之内随机扩散。
ArrayList类提供了一个remove()函数,我们可以通过这个函数非常方 便地移除某个粒子对象。
ArrayList的iterator()函数会返回一个迭代器对象。