第三天是关于绘制三角形的,但我们并不是直接使用 triangle()函数,而是画点和线,我们会限制线条,只绘制基于规则三角形的网格。为了使它更有趣,稍后我们会加入一些动画效果。

图画的起始点位于窗口中央,因为我们要使线条动起来,所以我们需要跟踪当前点和前一个点的位置,把它们用线连接起来。我们还需要一个半径来计算新的点。我们最好在程序的开头就定义好这些变量。


float radius = 20; float x, y; float prevX, prevY;


下一步我们需要给这些变量赋值。起始点设在窗口的中心,所以我们将 width和 height除以2,然后分别赋值给x和y。width和height是内置系统变量,可以通过size()来赋值,并可以随时调用。


x = width / 2; y = height / 2;     prevX = x; prevY = y;


接着,我们该编写 draw()函数了。计算下一个点我们要用到 cos()和 sin(),它俩是我们在第一天用过的功能。因为我们要做的三角形是规则的,所以线条只需要在六个特定的方向移动,算法很简单。

1.三个角的度数之和是180度或者说是PI

2.我们做的是等边三角形,所以每个角是180/3=60度

3.一个圆是360度或者TWO_PI,如果我们用60去除,得到6个方向的线

4.这些线的角度分别是0,60,120,180,240和300

我想让电脑去决定画哪个方向,所以我用随机数来计算方向。但是,random()功能所产生的结果是float值,而我想要的结果是0,1,2,3,4,5之间的整数,所以我加了一个 floor()功能,它会达到取整的效果。


float angle = (TWO_PI / 6) * floor( random( 6 )); x += cos( angle ) * radius; y += sin( angle ) * radius;


这样每次 draw()函数每调用一次点就会移动到网格上的新位置。下一步我们需要在当前点和前一个点之间画线。我们还需要在 draw()的末尾将前一点替换为当前点,否则在第一帧之后就不会有动态了。


stroke( 255, 64 ); strokeWeight( 1 ); line( x, y, prevX, prevY ); strokeWeight( 3 ); point( x, y ); // update prevX and prevY with the new values prevX = x; prevY = y;


如果你运行程序会发现线条不断往窗口外扩散回不来了。我们需要在确定x和y值之后实现一个算法来确保线条留在屏幕内。我们要检查新的x是不是小于0或者超出了宽度范围。如果是这样,我们要把x和y值还原成之前的值,这样线条就不会超出窗口范围了,y值也做相同处理。


if ( x < 0 || x > width ) { x = prevX; y = prevY;


}


if ( y < 0 || y > height) { x = prevX; y = prevY;


}

为了使我们的图画更有趣,我们给背景加一个淡出效果,这样那些线会像蛇一样移动。加入一个开关功能使用键盘按键来控制这个效果。为了达到这样的目的,我们需要在程序前加一个boolean变量。

Boolean fade = true;

下面的代码应当放在 draw()函数的最前面,我们要先判断fade值是不是为真。如果为真,if语句中的代码会在最上层画一个透明的长方形。


if (fade) { noStroke(); fill( 0, 4 ); rect( 0, 0, width, height );


}

想要关闭淡出效果,我们要用到keyPressed()这个方法,它会在每次键盘有按键动作时被调用。如果用户按了**f** 键,系统就切换一次fade的真假值。


void keyPressed(){ if (key == 'f') {     fade = !fade; }


}

运行程序后你就能看到之前的线条都慢慢淡出背景,试一下f键关闭或启用淡出效果。

 

源码:

float radius = 40;  
float x,y;  
float prevX,prevY;  
Boolean fade = true;  
Boolean saveOne = false;  
void setup(){  
 size(450,400);  
 background(0);  
 stroke(255);  
 x = width/2;  
 y = height/2;  
 prevX = x;  
 prevY = y;  
 stroke(255);  
 strokeWeight(2);  
 point(x,y);  
   
}  
void draw(){  
   
 if(fade){  
   noStroke();  
   fill(0,4);  
  // fill(random(204),random(100),random(20),4);  
   rect(0,0,width,height);  
 }  
 float angle = (TWO_PI/6) * floor(random(6));  
 x += cos(angle) * radius;  
 y += sin(angle) * radius;  
   
 if(x<0||x>width){  
    x= prevX;  
    y= prevY;  
 }  
   
 if(y<0||y>height){  
   x = prevX;  
   y = prevY;  
 }  
 // stroke(255,64);  
 stroke(255,0,0,100);  
 strokeWeight(1);  
 line(x,y,prevX,prevY);  
 strokeWeight(3);  
 point(x,y);  
 prevX = x;  
 prevY = y;  
 if(saveOne){  
 saveFrame("image/triangle-grid-" + second() + ".png");  
 saveOne = false;  
 }  
 delay(50);  
 }  
void keyPressed(){  
   if(key=='f'){  
     fade =!fade;     
   }  
     
   if(key=='s'){  
    saveOne = true;  
   }  
}

效果显示

 

 

 

 

 

 

floor(x)函数:计算最接近的小于或等于X的整数值

Namefloor()
Examples
 

  float x = 2.88;  

 

  int a = floor(x); // Sets 'a' to 2  

 
DescriptionCalculates the closest int value that is less than or equal to the value of the parameter. 
Syntax     floor(n)
Parameters  n   float: number to round down 
Returns      int
 
ceil(x)函数:计算最接近的大于或等于X的整数值
Name  ceil()
Examples
 

  float x = 8.22;  

 

  int a = floor(x); // Sets 'a' to 9 

 

  DescriptionCalculates the closest int value that is greater than or equal to the value of the parameter. For example,  
 ceil(9.03)returns the value 10.  

 
Syntax   floor(n)
Parameters  n       float: number to round down 
Returns      int