简单动画实现与类的使用(一)
无摘要。...
所谓动画,无论是通过Flash实现,还是通过Processing编程实现,本质都是相同的:图像或者形状按照一定的频率在移动。我们着重关注形状而先不管图像。那么反推学习动画的步骤可以知道两个基本任务:控制形状移动—绘制形状。那么这两个基本任务牵涉的东西主要有:首先从一个简单动画开始,我们将一步一步实现更复杂的效果组合。在实现简单动画的过程中,我会慢慢展开类的使用以及关于Processing的一些语法使用需要注意的细节。
- 时间控制
- 移动轨迹计算
- 形状组合
时间控制
关于时间控制,我们主要用的是帧数。比如帧频率是60,那么为了让轨迹运动1秒,只需要控制帧数为60即可。而设定帧频率的函数是frameRate(x),x是一个
int型的数值,但是自己测试输出可以发现是
float型,当然这无关紧要,一般指定
int型数据即可。而得到当前是多少帧数的方法是用
frameCount,得到当前帧频率的方法是直接读取
frameRate。注意到这里前面是一个函数,后两者就是全局变量,从运行起,
frameCount不断递增。且增长速度是由帧频率指定的。一般写作时不指定就默认为60帧每秒。也即在Processing运行的过程中,全局基本参数常见的有
width,
height,
frameCount,
frameRate等。为了改变一个参数,才会调用方法或者函数。而想知晓当先的运行中的一些参数,直接用名字即可。这些由Processing提供的函数,全局变量基本上都是很直接的,偶尔你想用什么功能,只用想到对应的英文差不多就是对的,或许这也是Processing的人性之处吧。以上这些,基本就足够我们控制时间了。
运动轨迹
自然会想到借助强大的坐标系+数学方程。这里的数学,绝不是考试中的数学,故意被老师挖坑设题,考察你的逆向思维居多。当我们寻求数学方法辅助我们进行动画绘制时,可以说多数都很直接易懂。且基本上是正向思维。那么回到刚才的话题,现在我们在二维世界里,用什么坐标系呢?一般来说,两种选择:那么运动轨迹如何掌控?
- 直角坐标系
- 极坐标系。
现在我们看一个最常用的:圆形轨迹的实现。那么,就将引出本篇的主角:三角函数。
x = a+r*cos(x); //a是圆心x坐标轴位置,r是半径
y = b+r*sin(x);// b是圆心y坐标轴位置
很熟悉的一个参数方程对吧。
在Processing中三角函数接受的是弧度制。一般提供的数值默认是角度值,为了完成这个转化自然可以自己写:
x*PI/180,或者直接用
radians(x)完成这个过程。代码的可读性会更好。如果想把一个弧度值转化为角度值,贴心的函数是
degrees(x)。
上面的参数方程如果已经明白是怎么来的就不用多说,如果并不熟悉,只啰嗦一句,圆形方程是:联想到:,可以看到:,就是上面的方程了。
说这么些东西,就是为了引出今天想分享的两个简单动画。从这次开始,我将中断翻译一段时间,先写动画的基础设计系列,毕竟时间真的有限,希望这个系列对大家真的有一点点启发。第一篇相关的,觉得已经深入掌握的,可以忽略不计,如果有兴趣一起学习的朋友,欢迎邮件分享你的作品。可以发到我的邮箱:873918065@qq.com。
又跑偏了,回到这次的简单动画来。主要是两个动画:
- 线动成圆
- 同心圆扩大与缩小
class LineToCircle这里首先定义的是线动成圆的动画示例,首先需要的数据有圆心位置以及半径,为了控制运动的角度,定义一个角度。那么接下来的操作主要是针对这四个数据值进行。
{
float x, y; //start of line
float r,theta; // radius of circle and angle
LineToCircle(float xin, float yin,float rin,float thetain)
{
x = xin;
y = yin;
r = rin;
theta = thetain;
}
public void drawCircle()
{
strokeWeight(3);//设置为3是为了完整覆盖,默认为1时,线条间会有缝隙
line(x+r*cos(radians(theta)),y+r*sin(radians(theta)),x+r*cos(PI+radians(theta)),y+r*sin(PI+radians(theta)));
if(theta >= 180)//线转动180度时即可绘制完毕,此时可以开始覆盖原图形
{
stroke(255);
strokeWeight(3);
line(x+r*cos(radians(theta)),y+r*sin(radians(theta)),x+r*cos(PI+radians(theta)),y+r*sin(PI+radians(theta)));
}
}
public void move()//动态增加转动角度
{
theta += 1;
}
}
数据的初始化通过构造函数进行,在外部实例化类对象时,根据传进来的参数初始化。既然是通过线的运动来实现圆形绘制,假设圆心在(x,y),当前线相对于水平轴顺时针角度是
theta,那么直径的两端坐标分别是:
(x+r*cos(radians(theta)),y+r*sin(radians(theta))),
(x+r*cos(PI+radians(theta)),y+r*sin(PI+radians(theta)));
这里的
theta是角度值,从0到360度。绘制时颜色指定为黑色,当完成一个圆形时,为了覆盖整个颜色,需要用背景色的线条继续绘制,就可以实现圆形的消失。线条的两个点坐标与绘制时相同。注意到这里的转动角度是通过
move函数改变的。在主调函数中,进行实例化以及类的方法调用。
LineToCircle ltc;绘制同心圆相对简单一些,反向覆盖同心圆时,注意调节
void setup()
{
size(400,400);
background(255);
frameRate(60);//默认就是60
smooth();
ltc = new LineToCircle(width/2, height/2,100,PI/2);
}
void draw()
{
smooth();
ltc.drawCircle(); //调用对象的函数绘制
ltc.move();
}
stroke(255),因为背景色是白色,所以同样设置为白色。
class Circle这个没有用到三角函数,主要是用
{
float x,y,r;
float angle;
Circle(float xin, float yin,float rin)
{
x = xin;
y = yin;
r = rin;
angle = 0;
}
public void drawCircle()
{
fill(0);
ellipse(x,y,r,r);
}
public void addRadius()
{
r += 1;//增加半径
}
public void minusRadius()
{
if(r >= 0)
{
stroke(255);//调成背景色
strokeWeight(4);
r -= 1;
}
}
}
}
ellipse绘制,并通过
addRadius和
minusRadius两个函数来增加或者缩小半径。
上面的两个例子都用到的是
draw()函数每帧执行一次。也因此,写在
draw函数中的函数,每帧会被调用一次。
background(255)写在
setup函数中,整个执行过程就执行一次,如果写在
draw函数中,将每帧都会更新背景,所以绘制在背景上的东西全被覆盖,达不到线动成圆和同心圆扩大的效果。实现效果如下:
关注 Processing学习部落
微信扫一扫关注公众号