赞
踩
Chapter 1为我们介绍了向量的相关概念,并且增进了我们对物体运动的相关矢量(速度、加速度)的理解,下面就让我们来好好的了解下这些有关向量的名词以及向量的相关运算,然后再让我们来发挥想象进行这些知识的运用创作。
“我们可以把向量当作两点之间的差异,也就是从一个点到另一个点所发生的移动。”这是笔者给向量的定义,在我们的学习当中,向量是带有方向的物理量,与标量不同的是,它不止有大小的数值概念,同样具有二维(或是多维)空间上的概念。
在Processing中我们用PVector类来创建向量实例。
让我们再来复习下之后我们创作有可能用到的向量运算:
向量的加法
向量的加法非常简单,在二维坐标系中,我们只需要将向量的x与y分别对应相加,即可获得结果。
设有两个向量u(u1,u2),v(v1,v2) ,则两个向量相加:u+v=(u1+v1,u2+v2)。
在Processing中,我们只需使用PVector.add(PVector)。
向量的减法
类比于向量的加法,不难获得向量减法的算法。
设有两个向量u(u1,u2),v(v1,v2) ,则两个向量相减:u+v=(u1-v1,u2-v2)。
在Processing中,可以使用使用PVector.sub(PVector)。
向量长度的计算及改变
向量的长度即模长,写作||x||,在数学当中我们一般这样求解:
向量x=(x1,y1),则||x||2=x12+y12。再开方即可。
而在Processing中就不必这么麻烦了,只需使用PVector.mag()获取返回值就好。
对于向量长度的改变,我们可以采用PVector.mult(value)、PVector.div(value)来对向量的长度进行放缩,或是直接通过PVector.setMag(value) 来设置。
向量中角度的计算及改变
在以往我们计算一个向量的角度需要通过三角函数再进一步求解,在Processing中,我们只需要PVector.heading2D()就可以求解出角度,改变的话使用rotate()函数即可。
而计算两个向量的夹角时,则不再需要用点乘结果除以模长乘积,而是直接用angleBetween() 就可以获得夹角。
如果一个物体在运动时,它的状态时时改变,那么我们就把这种运动叫做变速运动,这可能是速度大小的改变,也可能是速度方向的改变。因而我们引入加速度这一向量,来对速度进行改变。
以往速度更新公式为:v=v0+at,由于Processing中t可以用每帧的更新取代,我们只需要考虑加速度对速度的影响。
通过对向量的进一步巩固,我有了这样的创作想法,我把它画了一下:
点击画布上的一个位置,便形成了这个点与画布4个顶点构成的四个向量,延伸至画布边缘,在这样一条直线上是一会我们要绘制的主体Mover的最终到达位置。为了增加效果我们可以将矩形条状作为Mover的形状。这四个区域分不同的时间前后出发,表现层次感觉,直到绘制完成。
(emmmm,但是后来我算点坐标算的有些眩晕,所以改成了精简版,不让Mover斜着运动了改为沿坐标轴方向运动)
来看看最后的效果:
_
下面我们来说说,是怎样的制作经过。其实,如果仔细看的话,不难发现,每个边出来的彩条顶端处的斜率不太相同,这是因为每个边的顶点到我们点击点的向量方向不同。如果有靠近边缘的点击点,会有彩条的边缘斜率非常大,看起来会很尖锐。
在整个计算点的过程中,我基本上是利用几何关系求解的点坐标(相似三角形),算的整个人都怀疑人生了,四个边获取的坐标不尽相同。结合着Mover类的代码看一下:(我给每个边定义了一个Mover类,以下以x轴出发方向的做范例)
class Mover { PVector position; PVector velocity; PVector acceleration; PVector point; int order=0; float oriy=0; float orix=0; Mover(float x,float y,int i) { position = new PVector(40*i-20, 0); velocity = new PVector(0,5); point=new PVector(x,y); order=i; oriy=y; orix=x; } void update() { position.add(velocity); } void display() { stroke(0); strokeWeight(2); fill(color(0,71,79)); quad(40*(order-1),position.y-20*oriy/orix,40*order,position.y+20*oriy/orix,40*order,0,40*(order-1),0); } //最关键就是上面四边形顶点计算以及规律化了 void checkEdges() { if (position.y > 40*oriy*order/orix) { velocity = new PVector(0,-5); } else if (position.y < 0) { velocity = new PVector(0,5); } } }
分别定义位置变量、速度变量,因为用的是匀速运动的公式 s=s+vt。最关键的地方其实不是向量的运算,而是几何的推导。
这样子四边形的点的位置就被规律化了,而之后剩下三边的点的位置推断也是如上一样的方法,下面给出Mover2类、Mover3类、Mover4类的代码:
Mover2:
class Mover2 { PVector position; PVector velocity; PVector acceleration; PVector point; int order=0; float oriy=0; float orix=0; Mover2(float x,float y,int i) { position = new PVector(600, 40*i-20); velocity = new PVector(-4,0); point=new PVector(x,y); order=i; oriy=y; orix=x; } void update() { position.add(velocity); } void display() { stroke(color(0)); strokeWeight(2); fill(color(255,169,135)); quad(position.x+20*(width-orix)/oriy,40*(order-1),position.x-20*(width-orix)/oriy,40*order,width,40*order,width,40*(order-1)); } void checkEdges() { if (position.x < width-40*(width-orix)*order/oriy) { velocity = new PVector(4,0); } else if (position.x > width) { velocity = new PVector(-4,0); } } }
Mover3:
class Mover3 { PVector position; PVector velocity; PVector acceleration; PVector point; int order=0; float oriy=0; float orix=0; Mover3(float x,float y,int i) { position = new PVector(width-(40*i-20), 600); velocity = new PVector(0,-3); point=new PVector(x,y); order=i; oriy=y; orix=x; } void update() { position.add(velocity); } void display() { stroke(color(0)); strokeWeight(2); fill(color(255,202,79)); quad(width-40*(order-1),position.y+(40*(height-oriy)/(width-orix))/2,width-40*order,position.y-(40*(height-oriy)/(width-orix))/2,width-40*order,height,width-40*(order-1),height); } void checkEdges() { if (position.y < height-(40*(height-oriy)/(width-orix))*order) { velocity = new PVector(0,3); } else if (position.y > height) { velocity = new PVector(0,-3); } } }
Mover4:
class Mover4 { PVector position; PVector velocity; PVector acceleration; PVector point; int order=0; float oriy=0; float orix=0; Mover4(float x,float y,int i) { position = new PVector(0, (height-(40*i-20))); velocity = new PVector(2,0); point=new PVector(x,y); order=i; oriy=y; orix=x; } void update() { position.add(velocity); } void display() { stroke(color(0)); strokeWeight(2); fill(color(255,250,221)); quad(position.x-20*orix/(height-oriy),height-40*(order-1),position.x+20*orix/(height-oriy),height-40*order,0,height-40*order,0,height-40*(order-1)); } void checkEdges() { if (position.x >(40*orix/(height-oriy))*order) { velocity = new PVector(-2,0); } else if (position.x < 0) { velocity = new PVector(2,0); } } }
然后就是去调用我们的Mover类们,因为之前已经算好了距离,所以我们每个类实例化15个对象,在点击之后加入到分别为每个类准备的列表当中,然后去draw函数中调用,我根据刷新的帧数,设定了每个边出现的次序(刷新了多少帧之后再开始绘制哪个边),放出最后的代码:
ArrayList<Mover>mover=new ArrayList(); ArrayList<Mover2>mover2=new ArrayList(); ArrayList<Mover3>mover3=new ArrayList(); ArrayList<Mover4>mover4=new ArrayList(); int count=0; float x=0; float y=0; void setup() { size(600,600); } void draw() { background(color(240)); count++; for (Mover move:mover){ move.update(); move.display(); move.checkEdges(); } if(count>100) { for (Mover2 move2 : mover2) { move2.update(); move2.display(); move2.checkEdges(); } } if(count>200) { for (Mover3 move3 : mover3) { move3.update(); move3.display(); move3.checkEdges(); } } if(count>300) { for (Mover4 move4 : mover4) { move4.update(); move4.display(); move4.checkEdges(); } } } void mousePressed(){ x=mouseX; y=mouseY; for(int j=0;j<15;j++) { Mover move=new Mover(x,y,j+1); mover.add(move); Mover2 move2=new Mover2(x,y,j+1); mover2.add(move2); Mover3 move3=new Mover3(x,y,j+1); mover3.add(move3); Mover4 move4=new Mover4(x,y,j+1); mover4.add(move4); } count++; }
再来看看效果吧:
天呢,这个小实验做的太久了,以至于跨过了小律老师的ddl,呜呜,还得再努把力。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。