互动编程习作——表现随机行为及牛顿运动学

代码本色第0章-第4章变成习作

习作1:引言(第0章)

运用到了随机游走类,构建了一个walk对象,既维持了自身数据,又能够执行某些动作。
在这个程序中实现的是随着鼠标的移动而形成的图像。
用到的高斯分布中的代码
float r = randomGaussian();
然后定义r的大小来改变位移。

效果图:
在这里插入图片描述

代码:
Walker.pde`

class Walker{
int x,y;
 Walker() {
    x = width/2;
    y = height/2;
  }
  void render() {
   stroke(255,128);
    fill(120,0,120,128);
   ellipse(x,y,30,30);
   fill(120,120,0,128);
   ellipse(x,y,15,15);
  }
  // Randomly move up, down, left, right, or stay in one place
  void step() {
   float r = randomGaussian();
    // A 50% of moving towards the mouse
    if (r < 0.5) { 
    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 {
      int xdir = int(random(-2, 2));
      int ydir = int(random(-2, 2));
      println(xdir);
      x += xdir;
      y += ydir;
    }
    x = constrain(x, 0, width-1);
    y = constrain(y, 0, height-1);
  }
}

Main.pde

Walker w;

void setup() {
  size(640,360);
  // Create a walker object
  w = new Walker();
  background(255);
}
void draw() {
  // Run the walker object
 w.step();
  w.render();
}

此代码用的是高斯函数,在高斯随机游走模型总,每次的移动长度(每次物体在指定方向的移动距离,即步长)都是根据正态分布产生的,并在我们的随机游走模型中实现这样的特性。

习作二:向量(第一章)

用PVector对象实现弹球程序
PVector location;
是用PVector对象表示速度,代替之前的浮点数
PVector velocity:
指我们现在有两个PVector变量
通过向量的使用,实现了鼠标和Mover之间的交互

效果图:
在这里插入图片描述
代码:
Mover.pde

class Mover{
// The Mover tracks position, velocity, and acceleration 
  PVector position;
  PVector velocity;
  PVector acceleration;
  // The Mover's maximum speed
  float topspeed;
  Mover() {
    // Start in the center
    position = new PVector(random(width),random(height));
 velocity = new PVector(0,0);
    topspeed = 5;
  }
   void update() {
    
    // Compute a vector that points from position to mouse
    PVector mouse = new PVector(mouseX,mouseY);
    acceleration = PVector.sub(mouse,position);
    // Set magnitude of acceleration
      PVector mouse = new PVector(mouseX,mouseY);
    acceleration = PVector.sub(mouse,position);
    // Set magnitude of acceleration
    // Velocity changes according to acceleration
    velocity.add(acceleration);
    // Limit the velocity by topspeed
     velocity.limit(topspeed);
    // position changes by velocity
    position.add(velocity);
     if ((position.x > width) || (position.x < 0)) {
      velocity.x = velocity.x * -1;
    }
     if ((position.y > height) || (position.y < 0)) {
      velocity.y = velocity.y * -1;
    }
  }
  void display() {
    stroke(0);
    strokeWeight(2);
     fill(127,200);
    ellipse(position.x,position.y,16,16);
  }

Main.pde

Mover[] movers=new Mover[20];
void setup() {
  size(640,360);
  for (int i = 0; i < movers.length; i++) {
   movers[i] = new Mover(); 
  }
}
void draw() {
  
  background(255);
  for (int i = 0; i < movers.length; i++) {
    movers[i].update();
    movers[i].display(); 
    }
}

Mover对象的功能也很简单。它需要能够移动,还需要被显示出来。我们将这两个功能实现为update()函数和display()函数。所有的运动逻辑代码都放在update() 函数中,而显示代码放在display()函数中。

习作三:力(第二章)

小球会向着鼠标的地方慢慢聚在一起,然后慢慢散开。使球同时拥有位置,方向和加速度。

效果图:
在这里插入图片描述
Mover.pde
代码:

class Mover{
PVector position;
  PVector velocity;
  PVector acceleration;
  float mass;
  Mover(float m, float x, float y) {
    mass = m;
    position = new PVector(x, y);
     velocity = new PVector(0, 0);
    acceleration = new PVector(0, 0);
  }
   void applyForce(PVector force) {
    PVector f = PVector.div(force, mass);
    acceleration.add(f);
  }
   void update() {
    velocity.add(acceleration);
    position.add(velocity);
     acceleration.mult(0);
     if ((position.x > width) || (position.x < 0)) {
      velocity.x = velocity.x * -1;
    }
     if ((position.y > height) || (position.y < 0)) {
      velocity.y = velocity.y * -1;
    }
  }
  void display() {
    stroke(0);
    strokeWeight(2);
     fill(0, 100);
    ellipse(position.x, position.y, mass*24, mass*24);
  }
   PVector attract(Mover m) {
    PVector force = PVector.sub(position, m.position);             // Calculate direction of force
    float distance = force.mag();                                 // Distance between objects
    distance = constrain(distance, 5.0, 25.0);                             // Limiting the distance to eliminate "extreme" results for very close or very far objects
    force.normalize();                                            // Normalize vector (distance doesn't matter here, we just want this vector for direction
 float strength = (g * mass * m.mass) / (distance * distance); // Calculate gravitional force magnitude
    force.mult(strength);                                         // Get force vector --> magnitude * direction
    return force;
  }
  }

Main.pde

Mover[] movers=new Mover[20];
float g = 0.4;
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)); 
  }
}
void draw() {
  background(255);
   for (int i = 0; i < movers.length; i++) {
    for (int j = 0; j < movers.length; j++) {
      if (i != j) {
      PVector force = movers[j].attract(movers[i]);
        movers[i].applyForce(force);
      }
    }
    PVector force = movers[j].attract(movers[i]);
        movers[i].applyForce(force);
      }
    }
    }
    

在代码中,每个Mover对象的初始值都是相同的。但我们应该创建质量不同、初 始位置也不相同的Mover对象。为了解决这个问题,我们可以在构造函数中添加几个 参数,让它变得更灵活。
物体的质量和初始位置就不再是硬性编码的数值了,我们可以通过构造函数来 确定它们。这样一来,我们就可以创建各种各样的Mover对象,它们的质量有大有 小,可以从屏幕左边开始运动,也可以从右边开始。

习作四:振荡(第三章)

小球一中间的球为定点来回匀速振荡,中间对小球进行吸引Attractor。

效果图:
在这里插入图片描述
代码:

attractor.pde

class Attractor{
 float mass;    // Mass, tied to size
  float G;       // Gravitational Constant
  PVector position;   // position
   boolean dragging = false; // Is the object being dragged?
  boolean rollover = false; // Is the mouse over the ellipse?
  PVector dragOffset;  // holds the offset for when object is clicked on
  Attractor() {
    position = new PVector(width/2,height/2);
    mass = 20;
     G = 1;
    dragOffset = new PVector(0.0,0.0);
  }
  // Method to display
  void display() {
    float y = 100*sin(angle);
    angle += 0.02;
    float x = 100*sin(angle);
    angle += 0.02;
    ellipseMode(CENTER);
    strokeWeight(4);
    stroke(0);
    if (dragging) fill (50);
    else if (rollover) fill(100);
    else fill(175,200);
     ellipse(position.x,position.y,mass,mass);
    fill(127);
    float xx=position.x+x;
    float yy=position.x+y;
    line(position.x,position.y,xx,yy);
    ellipse(xx,yy,16,16);
  }
  // The methods below are for mouse interaction
  void clicked(int mx, int my) {
    float d = dist(mx,my,position.x,position.y);
     if (d < mass) {
      dragging = true;
      dragOffset.x = position.x-mx;
      dragOffset.y = position.y-my;
    }
  }
  void hover(int mx, int my) {
    float d = dist(mx,my,position.x,position.y);
    if (d < mass) {
    rollover = true;
    } 
    else {
    rollover = false;
    }
  }
   void stopDragging() {
    dragging = false;
  }
   void drag() {
    if (dragging) {
      position.x = mouseX + dragOffset.x;
      position.y = mouseY + dragOffset.y;
    }
  }
}

Main.pde

Attractor a;
float angle = 0;
void setup() {
  size(400,400); 
  a = new Attractor();
}
void draw() {
background(255);
a.drag();
  a.hover(mouseX,mouseY);
  a.display();
  }
  void mousePressed() {
  a.clicked(mouseX,mouseY); 
}
void mouseReleased() {
  a.stopDragging(); 
}

我们可以把与角运动相关的 变量加入到Mover类中。
我们知道正切的计算公式:

在这里插入图片描述

我们知道速度向量,不知道这个夹角,因此需要通过某种方式计算这个夹 角。有一个专门的函数用于求解这个问题,这个函数就是反正切函数,用arctan或者 tan-1表示(此外还存在反正弦和反余弦函数)。

习作五:粒子系统(第四章)

一些彩色的小球在里面做无规则的运动,在实现过程中,我们会更深 入地使用面向对象方法。

效果图:
在这里插入图片描述
代码:

Particle.pde:

class Particle{
PVector position;
  PVector velocity;
  PVector acceleration;
  float lifespan;
  float r = 6;
   Particle(float x, float y) {
    acceleration = new PVector();
    velocity = PVector.random2D();
     position = new PVector(x, y);
    lifespan = 255.0;
  }
   void run() {
    update();
    display();
  }
   void intersects(ArrayList<Particle> particles) {
    for (Particle other : particles) {
      if (other != this) {
       PVector dir = PVector.sub(position, other.position);
        if (dir.mag() < r*2) {
          dir.setMag(0.5); 
          applyForce(dir);
        }
      }
    }
  }
  void applyForce(PVector f) {
    acceleration.add(f);
  }
  // Method to update position
  void update() {
    velocity.add(acceleration);
     position.add(velocity);
    acceleration.mult(0);
    lifespan -= 0.25;
    if ((position.x > width) || (position.x < 0)) {
      velocity.x = velocity.x * -1;
    }
     if ((position.y > height) || (position.y < 0)) {
      velocity.y = velocity.y * -1;
    }
  }
  // Method to display
  void display() {
    float x,y,z;
     x=random(255);
    y=random(255);
    z=random(255);
    stroke(0, lifespan);
    strokeWeight(2);
    fill(x,y,z, lifespan);
     ellipse(position.x, position.y, r*2, r*2);
  }
  // Is the particle still useful?
  boolean isDead() {
    if (lifespan < 0.0) {
     return true;
    } 
    else {
    return false;
    }
  }
}

ParticleSystem.pde

class ParticleSystem{
ArrayList<Particle> particles;
ParticleSystem(PVector position) {
    particles = new ArrayList<Particle>();
  }
   void addParticle(float x, float y) {
    particles.add(new Particle(x, y));
  }
  void display() {
    for (Particle p : particles) {
      p.display();
    }
    }
 void applyForce(PVector f) {
    for (Particle p : particles) {
      p.applyForce(f);    
       }
  }
   void intersection() {
    for (Particle p : particles) {
      p.intersects(particles);
       }
  }
   void update() {
    for (int i = particles.size()-1; i >= 0; i--) {
      Particle p = particles.get(i);
      p.update();
      if (p.isDead()) {
        particles.remove(i);
      }
      }
  }
}

Main.pde

ParticleSystem ps;
void setup() {
  size(640,360);
  ps = new ParticleSystem(new PVector(width/2,50));
}
void draw() {
  background(255);
  ps.addParticle(random(width),random(height));
  //PVector gravity = new PVector(0,0.1);
  //ps.applyForce(gravity);
  ps.update();
   ps.intersection();
  ps.display();
}

粒子就是在屏 幕中移动的对象,它有位置、速度和加速度变量,有构造函数用于内部变量的初始 化,有display()函数用于绘制自身,还有update()函数用于更新位置。
在粒子类中添加applyForce()函数,让粒子可以 受力的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值