【创意编程】弹簧震荡

你说的曾经没有我的故事 提交于 2020-01-06 20:29:32

不知道这一章写什么。
前面的写累了,这个没有心思想了,就写一个简单的弹簧和小球的模拟吧。
结果是这样的:
在这里插入图片描述
它的实现也非常清晰可见。把小球和弹簧分别考虑,小球的运动按照速度、加速度的不同其实可以分为四个阶段:自由下落阶段、接触到弹簧之后受到弹力而减速的阶段、速度减为零之后受到弹簧向上的弹力加速上升的阶段、离开弹簧之后的减速运动。
在这里插入图片描述
我们先什么都不要管,定义一个小球和一个弹簧:
由于我们要求弹簧是可以压缩的,显然我们每一帧重新绘制它是不现实的。我们需要把弹簧首先做成一个固定的、可以调整高度的形状。我们使用PShape类。我们将仅仅通过一个可变的长度lenght的值来构造一个弹簧。由于我们弹簧的高度是不停地变化的,所以这样做是必要的,能够允许我们在弹簧长度变化的时候仅向一个弹簧绘图函数传入一个长度作为参数来生成一个我们需要的弹簧。

PShape spring;

构造弹簧:

void drawSpring(PVector position, int springLength){
  stroke(0);
  strokeWeight(2);
  noFill();
  
  pushMatrix();
  translate(position.x, position.y);
  beginShape();
  vertex(-25,0);
  vertex(25,0);
  vertex(-25,-1*springLength/10);
  vertex(25,-2*springLength/10);
  vertex(-25,-3*springLength/10);
  vertex(25,-4*springLength/10);
  vertex(-25,-5*springLength/10);
  vertex(25,-6*springLength/10);
  vertex(-25,-7*springLength/10);
  vertex(25,-8*springLength/10);
  vertex(-25,-9*springLength/10);
  vertex(25,-springLength);
  vertex(-25,-springLength);
  endShape();
  popMatrix();
}

这将使得我们的弹簧具有十个环,且高度可变,每一个环在整个弹簧中的位置随着弹簧长度改变,保持了弹簧形状的稳定。
我们需要的小球的参数:

int mass = 80;
float nForce;
PVector position;
PVector velocity;
PVector acceleration;
float g = 1;
float k = 10;
int state = 1;
float delta = 0;

运动过程

一开始,受高中物理的影响我以为需要对小球分四个阶段来考虑(如上图),但后来我才发现其实不必要。我们只需要把velocity、force、cceleration和acceleration用PVector来表示,就可以忽略这些量方向的问题,只需要考虑弹簧的力是否在,也就是只需要分两种情况就好了。
为了方便理解我还是定义了三个状态:
下落、受到弹簧力作用阶段、离开弹簧上升的阶段。
现在我们需要寻找这三种状态之间的切换点。很显然,状态1到状态2的关键节点是小球落到弹簧上的时候,状态2到状态3 的关键节点是小球速度变为0的时候,而状态3到状态1的节点是小球离开弹簧时。也就是:

  if (state == 1 && ((position.y+mass) >= height/2 + 150)){//collision happend
    state = 2;
  }
  if (state == 2 && ((position.y+mass) <= height/2 + 150)){
    state = 3;
  }
  if (state == 3 && position.y <= 50){
    state = 1;
  }

各个阶段的Update函数中对速度的更新处理方式是不同的。
在没有弹力值、只受重力影响的状态下,加速度即g,我们只需要每一帧更新将加速度赋给速度、速度加到位置上去就可。

    acceleration = new PVector(0, g);//g = a.
    velocity = PVector.add(velocity, acceleration);
    position = PVector.add(position, velocity);
    acceleration.mult(0);

另一个状态下小球受到的力是重力和弹力的矢量和。根据胡克定律,弹簧弹力与弹簧的形变量成正比。于是们也需要先计算形变量。

    delta = position.y+mass-height/2-150;
    nForce = k * delta;
    acceleration = new PVector(0, (mass*g - nForce)/mass);
    velocity.add(acceleration);
    position.add(velocity);
    acceleration.mult(0);

完整代码

PShape spring;
int mass = 80;
float nForce;
PVector position;
PVector velocity;
PVector acceleration;
float g = 1;
float k = 10;
int state = 1;
float delta = 0;

void setup(){
  size(900,600);
  background(255);
  position = new PVector(width/2, 0);
  velocity = new PVector(0, 0);
  acceleration = new PVector(0, 0);
}

void draw(){
  background(255);
  fill(0);
  ellipse(position.x, position.y, mass, mass);
  int springLength = floor(100 - delta);
  drawSpring(new PVector(width/2, 550), springLength);
  applyForce();
  
  //if dropped on spring
  if (state == 1 && ((position.y+mass) >= height/2 + 150)){//collision happend
    state = 2;
  }
  if (state == 2 && ((position.y+mass) <= height/2 + 150)){
    state = 3;
  }
  if (state == 3 && position.y <= 50){
    state = 1;
  }
}

void applyForce(){
  if (state == 1){
    acceleration = new PVector(0, g);//g = a.
    velocity = PVector.add(velocity, acceleration);
    position = PVector.add(position, velocity);
    acceleration.mult(0);
  }
  if (state == 2){
    delta = position.y+mass-height/2-150;
    nForce = k * delta;
    acceleration = new PVector(0, (mass*g - nForce)/mass);
    velocity.add(acceleration);
    position.add(velocity);
    acceleration.mult(0);
  }
  if (state == 3){
    acceleration = new PVector(0, g);//g = a.
    velocity = PVector.add(velocity, acceleration);
    position = PVector.add(position, velocity);
    acceleration.mult(0);
  }
}




void drawSpring(PVector position, int springLength){
  stroke(0);
  strokeWeight(2);
  noFill();
  
  pushMatrix();
  translate(position.x, position.y);
  beginShape();
  vertex(-25,0);
  vertex(25,0);
  vertex(-25,-1*springLength/10);
  vertex(25,-2*springLength/10);
  vertex(-25,-3*springLength/10);
  vertex(25,-4*springLength/10);
  vertex(-25,-5*springLength/10);
  vertex(25,-6*springLength/10);
  vertex(-25,-7*springLength/10);
  vertex(25,-8*springLength/10);
  vertex(-25,-9*springLength/10);
  vertex(25,-springLength);
  vertex(-25,-springLength);
  endShape();
  popMatrix();
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!