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

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

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

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

时间控制###

关于时间控制,我们主要用的是帧数。比如帧频率是60,那么为了让轨迹运动1秒,只需要控制帧数为60即可。 而设定帧频率的函数是frameRate(x),x是一个int型的数值,但是自己测试输出可以发现是float型,当然这无关紧要,一般指定int型数据即可。而得到当前是多少帧数的方法是用frameCount,得到当前帧频率的方法是直接读取frameRate。注意到这里前面是一个函数,后两者就是全局变量,从运行起,frameCount不断递增。且增长速度是由帧频率指定的。一般写作时不指定就默认为60帧每秒。也即在Processing运行的过程中,全局基本参数常见的有width,heightframeCountframeRate等。为了改变一个参数,才会调用方法或者函数。而想知晓当先的运行中的一些参数,直接用名字即可。这些由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)
上面的参数方程如果已经明白是怎么来的就不用多说,如果并不熟悉,只啰嗦一句,圆形方程是:联想到: ,可以看到:,就是上面的方程了。 说这么些东西,就是为了引出今天想分享的两个简单动画。从这次开始,我将中断翻译一段时间,先写动画的基础设计系列,毕竟时间真的有限,希望这个系列对大家真的有一点点启发。
第一篇相关的,觉得已经深入掌握的,可以忽略不计,如果有兴趣一起学习的朋友,欢迎邮件分享你的作品。可以发到我的邮箱:[email protected].

又跑偏了,回到这次的简单动画来。
主要是两个动画:

  • 线动成圆
  • 同心圆扩大与缩小

虽然是简单,但是不可否认的是,用到的东西并不少。 关于类,之前在翻译文章有专门提到过,这里不再重复,在代码分析的过程中,会简略提一点。 虽然这里可以不用类直接写,但从今天开始,这边分享的代码都将用类来组织,这样读起来也会更加简单,复用性也会更好。

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();
 }

1.绘制同心圆相对简单一些,反向覆盖同心圆时,注意调节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; 
  }
 } 
} 
}

外部调用:

Circle c ; 
void setup()
{
 size(400,400); 
 background(255); 
 smooth(); c = new Circle(width/2, height/2,0); 
} 
void draw() 
{ 
 smooth(); 
 c.drawCircle(); 
if(frameCount < 400) 
{ 
  c.addRadius(); 
} 
else 
{
   c.minusRadius(); 
} 
} 

这个没有用到三角函数,主要是用ellipse绘制,并通过addRadiusminusRadius两个函数来增加或者缩小半径。
上面的两个例子都用到的是draw()函数每帧执行一次。 也因此,写在draw函数中的函数,每帧会被调用一次。background(255)写在setup函数中,整个执行过程就执行一次,如果写在draw函数中,将每帧都会更新背景,所以绘制在背景上的东西全被覆盖,达不到线动成圆和同心圆扩大的效果。

文来自微信公众号:

简单动画实现与类的使用(一)_第1张图片
Processing学习部落

你可能感兴趣的:(简单动画实现与类的使用(一))