简单动画实现与类的使用(一)

 

无摘要。...



首先从一个简单动画开始,我们将一步一步实现更复杂的效果组合。在实现简单动画的过程中,我会慢慢展开类的使用以及关于Processing的一些语法使用需要注意的细节。

所谓动画,无论是通过Flash实现,还是通过Processing编程实现,本质都是相同的:图像或者形状按照一定的频率在移动。我们着重关注形状而先不管图像。那么反推学习动画的步骤可以知道两个基本任务:控制形状移动—绘制形状。那么这两个基本任务牵涉的东西主要有:

  • 时间控制
  • 移动轨迹计算
  • 形状组合

时间控制

关于时间控制,我们主要用的是帧数。比如帧频率是60,那么为了让轨迹运动1秒,只需要控制帧数为60即可。而设定帧频率的函数是
frameRate(x)
,x是一个
int
型的数值,但是自己测试输出可以发现是
float
型,当然这无关紧要,一般指定
int
型数据即可。而得到当前是多少帧数的方法是用
frameCount
,得到当前帧频率的方法是直接读取
frameRate
。注意到这里前面是一个函数,后两者就是全局变量,从运行起,
frameCount
不断递增。且增长速度是由帧频率指定的。一般写作时不指定就默认为60帧每秒。也即在Processing运行的过程中,全局基本参数常见的有
width
,
height
frameCount
frameRate
等。为了改变一个参数,才会调用方法或者函数。而想知晓当先的运行中的一些参数,直接用名字即可。这些由Processing提供的函数,全局变量基本上都是很直接的,偶尔你想用什么功能,只用想到对应的英文差不多就是对的,或许这也是Processing的人性之处吧。以上这些,基本就足够我们控制时间了。

运动轨迹

那么运动轨迹如何掌控?

自然会想到借助强大的坐标系+数学方程。这里的数学,绝不是考试中的数学,故意被老师挖坑设题,考察你的逆向思维居多。当我们寻求数学方法辅助我们进行动画绘制时,可以说多数都很直接易懂。且基本上是正向思维。那么回到刚才的话题,现在我们在二维世界里,用什么坐标系呢?一般来说,两种选择:

  • 直角坐标系
  • 极坐标系。
关于极坐标系,用到时候的再展开,我们先关注直角坐标系。在你的屏幕上,最左上方的那一点是坐标原点。从左往右,可以认为是x轴,从上往下是y轴。也就是说,我们用的是坐标系中的一个象限,只不过和平时画的稍稍不同。有了坐标系,就能精准控制点的位置。但仅仅知道这些还不足够。形状除了基础的矩形,圆形,椭圆等,其他的形状基本由线条组合而成。而绘制线条有很多种方法,这里暂时不一一展开,陆续在实例中用到再具体详解。

现在我们看一个最常用的:圆形轨迹的实现。那么,就将引出本篇的主角:三角函数

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学习部落


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册