Part1 实现效果以及扩展
研究不同质量物体(按照sin函数分布),在弹簧系统下的运动规律:整体呈现sin曲线。
同时单个小球颜色变换,在整体画面呈现sin曲线运动。
操作说明:
1、点击鼠标重置;
2、键盘上/下键进行帧率的增/减。
Part2 振荡
sin()函数的结果是一条介于-1到1的平滑曲线。这条曲线符合振荡的效果, 振荡是两点之间的周期性运动。
简谐运动即是物体按照正弦曲线周期性振荡。
振幅:离开运动中心的最大距离。
周期:完成一次往复运动所花费的时间。
在Processing中振荡的周期应当用帧数表示,需要通过frameRate获取当前帧率、通过frameCount获取当前帧数。
如果有需要的话,可以使用map函数将三角函数的结果映射到指定范围。
《代码本色》参考实例:
1、简谐运动
2、弹簧
在弹簧模型中,物体悬挂在弹簧上进行上下摆动的简谐运动。弹簧的弹力可以通过胡克定律计算得到:
k为常量,影响弹力大小。
x代表弹簧形变程度。
模拟物体运动必要的几个变量:位置、速度、加速度。
在弹簧模型中,钟摆受力有重力和弹力。根据上一章的关于力的知识,可知由已知力可以改变物体的加速度、速度、位置。所以首先需要计算出距离,再由胡克定律计算出弹力,最后通过弹力改变上述三个变量值。
Part3 设计思路
通过上述的知识点和两个案例,我想运用(Processing模拟的)弹力系统,研究不同重力物体的运动情况,其重力分布是按照sin函数进行分配,其整体运动状态也应该呈现sin曲线模式。因为其所受弹力与形变长度有关,形变长度又与重力相关,重力又影响了位置。于是设计了本实验。
同时,摆钟小球的颜色根据逐一变化,与整体运动结合,形成了视觉上的运动体验,也间接地绘制出了sin曲线。
此外设计了键盘上下键来调节帧率,以方便用户观察其中规律。鼠标点击进行复原。
Part4 代码实现
①主函数
Bob[] bob=new Bob[30];
Spring[] spring=new Spring[30];
boolean isColor;
float nowFrameRate;
void setup(){
frameRate(20);
size(900,300);
isColor=false;
for(int i=0;i<bob.length;i++)
{
spring[i] = new Spring(15+30*i,10,100);
bob[i] = new Bob(15+30*i,100,10+2*sin(i));
}
}
void draw() {
background(250);
for(int i=0;i<bob.length;i++)
{
if(frameCount%30==i)
isColor=true;
else
isColor=false;
bob[i].setColor(isColor);
PVector gravity = new PVector(0,9.8);
bob[i].applyForce(gravity);
spring[i].connect(bob[i]);
spring[i].constrainLength(bob[i],30,200);
bob[i].update();
bob[i].drag(mouseX,mouseY);
spring[i].displayLine(bob[i]);
bob[i].display();
spring[i].display();
}
fill(0);
text("frameRate:",10,height-20);
text(int(frameRate),70,height-20);
text("1.Click to reset. 2.Press UP/DOWN to add/sub frameRate. ",10,height-5);
}
void keyReleased(){
if(keyCode==UP)
{
frameRate(frameRate++);
}
if(keyCode==DOWN)
{
if(frameRate>=2)
frameRate(frameRate--);
}
}
void mousePressed() {
reset();
}
void reset() {
for (int i = 0; i < bob.length; i++) {
spring[i] = new Spring(15+30*i,10,100);
bob[i] = new Bob(15+30*i,100,10+2*sin(i));
}
}
②Mover类
class Bob {
PVector position;
PVector velocity;
PVector acceleration;
float mass;
float damping = 0.98;
PVector dragOffset;
boolean dragging = false;
boolean isColor=false;
Bob(float x, float y,float m) {
position = new PVector(x,y);
velocity = new PVector();
acceleration = new PVector();
dragOffset = new PVector();
mass=m;
}
void update() {
velocity.add(acceleration);
velocity.mult(damping);
position.add(velocity);
acceleration.mult(0);
}
void applyForce(PVector force) {
PVector f = force.get();
f.div(mass);
acceleration.add(f);
}
void setColor(boolean c){
isColor=c;
}
void display() {
stroke(0);
strokeWeight(2);
if(position.y>=158&&position.y<=162)
fill(240);
else
{
if(isColor)
fill(115,214,97);
else
fill(240);
}
//fill(position.y/200*255,position.y/200*200,position.y/200*255);
if (dragging) {
fill(50);
}
ellipse(position.x,position.y,25,25);
}
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 stopDragging() {
dragging = false;
}
void drag(int mx, int my) {
if (dragging) {
position.x = mx + dragOffset.x;
position.y = my + dragOffset.y;
}
}
}
③Spring类
class Spring {
PVector anchor;
float len;
float k = 0.2;
Spring(float x, float y, int l) {
anchor = new PVector(x, y);
len = l;
}
void connect(Bob b) {
PVector force = PVector.sub(b.position, anchor);
float d = force.mag();
float stretch = d - len;
force.normalize();
force.mult(-1 * k * stretch);
b.applyForce(force);
}
void constrainLength(Bob b, float minlen, float maxlen) {
PVector dir = PVector.sub(b.position, anchor);
float d = dir.mag();
if (d < minlen) {
dir.normalize();
dir.mult(minlen);
b.position = PVector.add(anchor, dir);
b.velocity.mult(0);
}
else if (d > maxlen) {
dir.normalize();
dir.mult(maxlen);
b.position = PVector.add(anchor, dir);
b.velocity.mult(0);
}
}
void display() {
stroke(0);
fill(175);
strokeWeight(2);
rectMode(CENTER);
rect(anchor.x, anchor.y, 2, 2);
}
void displayLine(Bob b) {
strokeWeight(2);
stroke(0);
line(b.position.x, b.position.y, anchor.x, anchor.y);
}
}