创意编程——雪花与力

基于processing实现

效果演示

包含重力,风力,吸引力与水的浮力
在这里插入图片描述

Processing实现

主体逻辑

在这里插入图片描述

重力

加速度和力成正比, 和质量成反比。 这意味着如果你受一个推力作用产生运动, 那么推力越大, 运动越快( 加速度越大) ; 质量越大, 运动越慢。
重量和质量:

  • 质量是物质量的度量( 以千克为单位) 。
  • 重量, 通常被误认为质量, 实际上指的是物体所受重力的大小。 根据牛顿第二运动定律, 重量等于质量乘以重力加速度( w = m ∗ g w =m*g w=mg) 。 重量以“牛顿”为单位。
  • 密度等于质量除以物体的体积( 例如以“克/立方厘米”为单位) 。

加速度是一切运动的起因。而在程序中力变成了运动的起因。
因此直接将重力定义为:

PVector gravity;
gravity = new PVector(0, 0.3);

风力

风是一个具有方向、大小随机性的力,因此在此我通过一个噪声进行模拟风力。

float wAngle = noise(xOff, yOff, zOff) * TWO_PI;
PVector wind = PVector.fromAngle(wAngle);

吸引力

模仿万有引力的概念,吸引力由两个物体之间的一个相互作用力形成,但在此我不需要将此力同时作用于两个物体,只需将其作用与需要被吸引的物体,也就是我们的雪花。

引力主要由两方面因素决定:

  • 物体间的距离
  • 物体的质量

引力的计算主要在attract函数内实现。

完整代码如下所示:

float g = 1;

class Attractor {
  float mass;    // Mass, tied to size
  PVector location;   // Location
  boolean dragging = false; // Is the object being dragged?
  boolean rollover = false; // Is the mouse over the ellipse?
  PVector drag;  // holds the offset for when object is clicked on

  Attractor(int x,int y) {
    //location = new PVector(width/2,height/2);
    location = new PVector(x,y);
    mass = 10;
    drag = new PVector(0.0,0.0);
  }

  PVector attract(Snowflake m) {
    PVector force = PVector.sub(location,m.pos);   // Calculate direction of force
    float d = force.mag();                              // Distance between objects
    d = constrain(d,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) / (d * d);      // Calculate gravitional force magnitude
    force.mult(strength);                                  // Get force vector --> magnitude * direction
    return force;
  }

  // Method to display
  void display() {
    ellipseMode(CENTER);
    stroke(0);
    if (dragging) fill (50);
    else if (rollover) fill(100);
    else fill(0);
    ellipse(location.x,location.y,mass*6,mass*6);
  }

  // The methods below are for mouse interaction
  void clicked(int mx, int my) {
    float d = dist(mx,my,location.x,location.y);
    if (d < mass) {
      dragging = true;
      drag.x = location.x-mx;
      drag.y = location.y-my;
    }
  }

  void rollover(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 + drag.x;
      location.y = mouseY + drag.y;
    }
  }
}

液体浮力

液体提供的浮力计算为:
F = c ∗ v 2 F=c*v^2 F=cv2
其中 F F F为液体施加浮力,c为液体的系数,v为物体的运动速度。
完整代码:

class Liquid {

  // Liquid is a rectangle
  float x,y,w,h;
  // Coefficient of drag
  float c;

  Liquid(float x_, float y_, float w_, float h_, float c_) {
    x = x_;
    y = y_;
    w = w_;
    h = h_;
    c = c_;
  }
  
  // Is the Mover in the Liquid?
  boolean contains(Snowflake m) {
    PVector l = m.pos;
    if (l.x > x && l.x < x + w && l.y > y && l.y < y + h) {
      return true;
    }  
    else {
      return false;
    }
  }
  
  // Calculate drag force
  PVector drag(Snowflake m) {
    // Magnitude is coefficient * speed squared
    float speed = m.vel.mag() * 0.3;
    float dragMagnitude = c * speed * speed;

    // Direction is inverse of velocity
    PVector dragForce = m.vel.get();
    dragForce.mult(-1);
    
    // Scale according to magnitude
    // dragForce.setMag(dragMagnitude);
    dragForce.normalize();
    dragForce.mult(dragMagnitude);
    return dragForce;
  }
  
  void display() {
    noStroke();
    fill(50);
    rect(x,y,w,h);
  }

}

雪花粒子

初始定义

雪花粒子为同时拥有位置( location) 、 速度( velocity) 和加速度( acceleration) 的Snowflake类。
在初始化雪花时需通过图片进行加载,

class Snowflake {

  PImage img;
  PVector pos;
  PVector vel;
  PVector acc;
  float angle;
  float dir;
  float xOff;
  float r;
  float mass;
  
  Snowflake(float m,float sx, float sy, PImage simg) {
    mass = m;
    float x = sx;
    float y = sy;
    img = simg;
    pos = new PVector(x, y);
    vel = new PVector(0, 0);
    acc = new PVector();
    angle = random(TWO_PI);
    dir = (random(1) > 0.5) ? 1 : -1;
    xOff = 0;
    r = getRandomSize();
  }
  ...
 }
float getRandomSize() {

  float r = pow(random(0, 1), 3);
  return constrain(r * 32, 2, 32);
}

力的累加

力的累加通过applyForce函数实现:

  void applyForce(PVector force) {
    PVector f = force.copy();
    f.mult(r);
    acc.add(f);
  }

举个例子,在屏幕上创建一个雪花对象, 这个雪花受风力和重力的作用,则代码如下所示:

Snowflake.applyForce(wind);
Snowflake.applyForce(gravity);
Snowflake.update();

其中update函数用于更新雪花的位置与偏移信息:

  void update() {
    xOff = sin(angle * 2) * 2 * r;

    vel.add(acc);
    vel.limit(r * 0.2);

    if (vel.mag() < 1) {
      vel.normalize();
    }

    pos.add(vel);
    acc.mult(0);

    if (pos.y > height + r) {
      randomize();
    }

    if (pos.x < -r) {
      pos.x = width + r;
    }
    if (pos.x > width + r) {
      pos.x = -r;
    }

    angle += dir * vel.mag() / 200;
  }

主程序

完全按照主题逻辑进行书写。
完整代码:

ArrayList<Snowflake> snow;
PVector gravity;
Attractor a;
Liquid liquid;
float zOff = 0;

PImage spritesheet;
ArrayList<PImage> textures;

void setup() {
  size(800,600);
  spritesheet = loadImage("flakes32.png");
  
  snow = new ArrayList<Snowflake>();
  textures = new ArrayList<PImage>();
  
  a = new Attractor(width/2,height/2);
  gravity = new PVector(0, 0.3);
  for (int x = 0; x < spritesheet.width; x += 32) {
    for (int y = 0; y < spritesheet.height; y += 32) {
      PImage img = spritesheet.get(x, y, 32, 32);
      image(img, x, y);
      textures.add(img);
    }
  }


  for (int i = 0; i < 600; i++) {
    float x = random(width);
    float y = random(height);
    float mass = random(4,12);
    int designIndex = floor(random(textures.size()));
    PImage design = textures.get(designIndex);
    snow.add(new Snowflake(mass,x, y/2, design));
  }


  // Create liquid object
  liquid = new Liquid(0, height*3/4, width, height/2, 0.1);


}

void draw() {
  background(0);
  
  // Draw water
  liquid.display();
  
  a = new Attractor(mouseX,mouseY);
  //snow.add(new Snowflake());

  zOff += 0.1;

  for (int i = 0; i < snow.size(); i++) {
    Snowflake flake = snow.get(i);
    float xOff = flake.pos.x / width;
    float yOff = flake.pos.y / height;
    float wAngle = noise(xOff, yOff, zOff) * TWO_PI;
    PVector wind = PVector.fromAngle(wAngle);
    wind.mult(0.1);
    PVector force = a.attract(flake);
    
    
    
    if (liquid.contains(flake)) {
      // Calculate drag force
      PVector dragForce = liquid.drag(flake);
      // Apply drag force to Mover
      flake.applyForce(dragForce);
      gravity = new PVector(0, 0.01);
      flake.applyForce(gravity);
    }
    else{
      flake.applyForce(force);
      flake.applyForce(wind);
      gravity = new PVector(0, 0.3);
      flake.applyForce(gravity);
    }
    
    flake.update();
    flake.render();
  }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值