创造第一个processing程序

在第一篇的引诱下,相信对processing感兴趣的读者,不用等到第二篇指南,自己已经在动手实践了。

这里为好学的读者整理了一份资源清单,也欢迎大家一起来补充。

Processing资源清单

  • 写在前面:只看教程是无法学会编程的,要动手,动手,动手~~

这一节,我们就来玩转 processing。

其他编程语言的经典入门大多从输出 “HelloWorld” 开始讲起。

但属于设计师的 “HelloWorld”,不应该是字符。咱们从画图开始!

画布与函数

在开始前,首先聊聊 Processing 中的画布—— Sketch 。Sketch 的字面含义就是素描,草图。程序设计者把工程文件的名字起得太优雅了,就是想告诉我们,这就是给设计师玩的Sketch!

打开Processing,它会自动新建一个叫名叫 sketch_xxxx 的文件。我们可以直接开始写代码。完成后点 File-save 就可以保存自己的作品。

第一步,我们先写下这行命令:

	size(500,500);

接着点击左上方的三角按钮运行程序。它会弹出一个灰色的窗口,这就是运行后的样子。

聪明的读者是不是已经能猜到这段代码的含义呢?

没错。size()就是用来设置画布大小的函数。以后如果看到这样的格式:一串英文字符,后面再跟一对括号,那在程序中就被称为函数。

格式:

函数名()

与数学函数的定义不一样。程序中的函数,其实是一些代码块的封装。我们可以无需搞清函数内部的构造和原理,只需要知道它究竟能做什么。正如要开汽车不需要懂引擎的运作原理。

现在再回到size函数。它后面的括号里还有两个参数,中间用逗号作了区分。前一个代表窗口的宽度,后一个代表窗口的高度,完整的调用形式如下。

	size(x,y)   // x设置运行窗口宽度,y设置高度

表达式写完后,请千万要记得在指令后面加一个;号,代表结束。这是初学者最容易踩的坑,请记得保持这个习惯,否则程序会出BUG(错误)。

这样具有历史意义的第一行代码就被我们敲出来了。后面介绍的绘图函数也会同样简单。函数相当神奇,使用它可以大大提高效率,它生来就是为懒人服务的。只要懂得正确地组装,就能写出功能丰富的程序。

坐标系统

在使用绘图函数之前,需要了解 Procssing 的坐标系统。这与我们中学阶段接触到的笛卡尔坐标系很不一样,它的 Y 轴方向是反的。假如我们定义了一个 150 X 100 的画布,那左上角的第一个像素坐标就为(0,0),右下角的最后一个像素坐标则为(149,99)。

觉得难记可以这么去理解,坐标数其实代表了偏移量。起始坐标点序号为 0,与它相邻的坐标就距离初始坐标一个单位,因此序号为 1 。第 150 个坐标距离与第 1 个坐标相比,偏移了 149 个单位,所以序号就为 149。

但为什么要从0计算到149而不是从1计算到150呢?看上去多麻烦。这是程序中约定俗成的,很多概念都是从0开始计数。

我尝试从另一个设计角度去解释它的优点。假如我们要在画布中确立一个中心点。

如果是从 0 开始计数,要寻找中心像素就会很方便。只需将屏幕的宽高各自除以 2 (除了像素点为偶数的情况不存在绝对的中心)。而如果从 1 开始计数,除以 2 之后横纵坐标还要再加 1,才能得到准确的中心位置。(程序中两数相除,不会进行四舍五入,会直接舍去小数点后的数字)

现在应该对这种计数方式印象更深了吧,其实如果你是ps老手,就会发现在ps的信息面板上早就是按这样的方式来标记图片像素的位置。

改变坐标系

这个坐标系可不是一成不变的,有一个函数 translate 可以改变它。

调用形式:

	translate(x,y);

它可以将整个坐标系进行平移,xy 可以取正数或者负数,数值的正负决定移动的方向,数值的大小决定移动距离。以 x 值为例,如果取正数,则会朝 x 轴的正方向平移 x 个单位。负数则往负方向平移 x 个单位。

例如:

translate(50, 50)

绘图函数

坐标系统就像地图一样。通过它,所有绘制的图形都有了立足之地。下面开始介绍各种绘图函数。

画点

在 size 后面写下这段代码。

	point(250,250);

点三角符号运行。

嗯?什么也没看到?再凑近看看。你会发现中央出现了一个小黑点。

这就是用于画点的函数。在 processing 里,这个点刚好就是一个像素的大小。第一个参数代表横坐标,第二个参数代表纵坐标。由于屏幕宽高都为 500,所以这个点刚好处于中间的位置。

但若想在画布中心画点,可以用这种便捷的方式去表示。

	point(width/2, height/2);

其中 width 会获取屏幕的宽,height 会获取屏幕的高,“/”在程序中代表除号。这样写程序可以自动计算结果,而无需给出具体的坐标。

你甚至可以在里面写一个超复杂的表达式进去

	point(1 + 2 + 3 + 4 + 5, 100 - 50 - 20 - 10)

当然,没事可不要这么去写,除非是想研究什么古怪的数列规律~~

画圆

接着来看画圆函数,ellipse。

调用形式:

	ellipse(x, y, a, b)

括号中的前两个参数与point函数类似,后两个参数分别代表圆的宽和高。如果宽高值不一样,就能画出椭圆。

可以直接加在原代码后面试试:

整体代码:

size(500, 500);
point(250, 250);
ellipse(250, 250, 20, 20);

终于出现了一个大大的圆点。但有没有发现,之前绘制的点消失不见了!

其实,它只是被ellipse绘制的圆形覆盖了。在程序中,代码是由上到下,逐行执行的。先执行的先绘制,后执行的会覆盖前面的。有没有觉得和ps的图层很像?

画线,画三角,画方形

这几个函数的用法也很简单。

画线:

	line(x1, y1, x2, y2) 

x1, y1代表线条的一个端点坐标,x2,y2则代表另一个。函数会将两个坐标连起来。

画三角:

	triangle(x1, y1, x2, y2, x3, y3)

这里会用到三对坐标参数,分别代表3个顶点坐标。

画方形:

	rect(x,y,a,b)

前两个参数代表方形左上方的顶点坐标,a,b 分别代表方形的长和宽。

你可以单独地去试验这些函数,熟悉它们的用法。之后可以复制下面的代码:

size(500, 500);
ellipse(175, 220, 183, 183);
ellipse(width-175, 220, 183, 183);
rect(100, 100, 300, 300);
line(150, 160, 220, 240);
line(width-150, 160, width-220, 240);
ellipse(175, 220, 60, 60);
ellipse(width-175, 220, 60, 60);
point(width/2, height/2);
triangle(170, 300, width-170, 300, 250, 350);

这个例子将前面介绍的函数都一并用上了,还画了一个表情图形(姑且算吧),你也可以尝试自己画一些稍微复杂的图案。同时琢磨两个问题。

  • 每行函数对应的图形部件是哪一个?

  • width-x代表的含义?作用是什么?这种写法有什么优点?

上色

只有形状,不免无趣。我们还要学会上色。和我们预想的上色方式不一样,不是每个形状都会有一个对应的色彩属性,来让你去定义它的颜色。比如ellipse(200,200,20,20,?)后面再加一个参数之类的。

程序中上色要使用 fill 函数,这是一种通用的上色方法,并且要写在绘图函数前面,

fill 的输入参数很特别,允许几种输入方式。

可以这样

	fill(x)  

x代表灰度值,最小为0(代表黑色),最大为255(代表白色)

可以这样

	fill(x,a)  

x代表灰度值,a代表透明度(最小值0,最大值255)

也可以这样

	fill(r,g,b) 

r代表red(红),g代表green(绿),b代表blue(蓝)。设计师对RGB应该是相当熟悉了,代表的就是三原色。

还能这样

	fill(r,g,b,a) 

rgb就代表三原色,a代表alpha(透明度)

实例效果:

size(500, 500);
fill(125);
ellipse(100, 250, 100, 100);
fill(125, 100);
ellipse(200, 250, 100, 100);
fill(255, 0, 0);
ellipse(300, 250, 100, 100);
fill(255, 0, 0, 50);
ellipse(400, 250, 100, 100);

但如果前面只写一个fill呢?

size(500, 500);
fill(125);
ellipse(100, 250, 100, 100);
ellipse(200, 250, 100, 100);
ellipse(300, 250, 100, 100);
ellipse(400, 250, 100, 100);

那之后绘制的图像,都会填充同一个颜色。如果将 fill 放在中间,前面的依然会是默认的白色,只有后面的代码会产生影响。(代码由上至下执行的)

size(500,500);
ellipse(100, 250, 100, 100);
fill(125);
ellipse(200, 250, 100, 100);
ellipse(300, 250, 100, 100);
ellipse(400, 250, 100, 100);

  • 如果希望绘制的每个形状都是不同的颜色,就得在每个绘图函数的前面加上fill。

与fill相关的还有noFill函数。

	noFill()

它不需要输入任何参数,写在绘图函数前面,之后绘制的图形都不会填充颜色,而只显示边线。

size(500,500);
noFill();
ellipse(100,250,100,100);
ellipse(200,250,100,100);
ellipse(300,250,100,100);
ellipse(400,250,100,100);

除非你后面又写上fill(),那才会开启填充功能。

边线

除了能处理形状的填充色,还可以单独对边线的颜色和宽度进行处理。

边线颜色

	stroke(x)  

stroke 函数可以改变边线的颜色。括号内参数与 fill 函数的用法完全一样。代表边线的颜色。可以选择四种不同的参数输入方法。

	stroke(x)

x代表灰度值,最小为0(代表黑色),最大为255(代表白色)

	stroke(x,a)

x代表灰度值,a代表透明度alpha

	stroke(r,g,b)

rgb代表三原色RGB

    stroke(r,g,b,a)

rgb代表三原色RGB,a代表透明度alpha

边线宽度

    strokeWeight(x)

控制边线的粗细(还可以控制点的大小)

    noStroke() 

无需输入参数,代表不显示边线

stroke的用法就留待大家去探索了。如果把下面这行代码写在之前表情图案的前面,就会出现这个效果。

    strokeWeight(8);

所有的边线都被加粗了。

最后还有一个与上色相关的background函数,它可以用来填充背景,相当于油漆桶。括号中填的也是色彩参数,和前面的完全一致,有四种不同的参数输入方式。如果把background(200,0,0)写在前面可以得到。

size(500, 500);
strokeWeight(8);
background(200, 0, 0);
ellipse(175, 220, 183, 183);
ellipse(width-175, 220, 183, 183);
rect(100, 100, 300, 300);
line(150, 160, 220, 240);
line(width-150, 160, width-220, 240);
ellipse(175, 220, 60, 60);
ellipse(width-175, 220, 60, 60);
point(width/2, height/2);
triangle(170, 300, width-170, 300, 250, 350);

是不是开始像个“作品”了(姑且算吧)

End

学程序不要单纯去背知识点,而是要将它们灵活运用起来。除了一些特别常用的函数要记住以外,其余的在用的时候再去查也是没有问题的。

在 Processing 官网中可以查到各种函数的用法。(https://processing.org/reference/)

  • 说个小秘诀,如果在写程序的时候忘记怎么用某个函数。只要你的函数名书写正确的,就可以查询该函数的详细用法。先双击函数名,等变成黄色背景时再点右键,选择Find in reference。

函数介绍:

通过这节的介绍。是不是觉得代码没有以前那么神秘了?

在程序中画图,远没有用画笔或者ps工具那么形象和自由。里面的任何一个图形,都需要用数据来描述它的位置,大小或角度。而对于复杂的图形,是很难纯靠想象,直接写出代码的。一般是先绘制好草图,再用ps的信息面板查看关键点的坐标,最后选择合适的函数去表现。

  • 就像先前的例子

看到这里,有怀疑精神的设计师估计会跳出来。我在PS里面随便拉几下就能画出来的图形,为什么非要在用程序里画,过程还这么麻烦?这完全体现不出程序的优势呀?

说得很有道理,请保持好质疑的心态,答案在后面揭晓。之后还会聊聊两个“大头”函数,setup函数和draw函数。只要灵活运用它们,就可以让图片“动”起来。而我们在学校里曾经学习的那些有关数学函数的知识,也开始有了用武之地,那些看似枯燥的数学公式,将会成为我们控制图形的利器。