Oh!Coder

Coding Life

有趣的Processing-自定义图形

| Comments

Hi,大家好!在之前的学习中,我们了解了基本图形的创建,图片以及文字的加载等等。但是还不够,按照之前所学习的方法,如果我们想自定义画出多边形的话,所用方法还是不够灵活。为了解决这个问题,我们这次学习一种新的方法,看看如何直接画出各种各样不同的图形。

具体来说,我们的学习方法还是遵循渐进的步骤,先简单后复杂,通过简单的例子来一步一步学习。好!长话短说,我们还是从创建一个新的项目窗口开始。

画矩形

首先,还是启动PDE工具,并新建一个项目窗口。

processing-new-window

图片来源:Processing新项目窗口

然后向其中添加如下代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 声明PShape类型对象
PShape rectangle;
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 设置窗口大小
  size(640, 360, P2D);
  // 创建PShape对象
  // 四个参数,从左到右,依次为:
  // 所创建的图形类型为RECT,
  // RECT是Processing提供的一个常量,
  // 接下来是图形的起始坐标x, y为 0, 0
  // 最后两个参数是图形的宽和高 100, 50
  rectangle = createShape(RECT, 0, 0, 100, 50);
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 设置背景色
  background(51);
  // 渲染矩形
  shape(rectangle);
}

完成之后,点击项目窗口上目录栏里的倒三角按钮,编译并运行这段代码。

processing-window-menu

图片来源:Processing新项目窗口中的菜单栏

成功执行后,会在窗口中看到如下运行结果。

processing-fun-pshape-1

图片来源:Processing程序执行结果

上面这个例子里,我们遇到了几个新面孔,作为入门,这也应该是最简单的例子了。首先,让我们认识一下这几个新面孔。首先是PShape类型,此类型是用来自定义图形的。程序的开始,我们先声明的是一个PShape类型的对象。此对象可以用来创建我们所需要的自定义图形。例如接下来的createShape()方法,此方法真正创建了PShape类型的对象。最后的shape()方法,用来渲染设置好的rectangle对象。

稍微总结一下,首先声明PShape类型的对象变量,然后通过createShape()方法进行创建,最后通过shape()方法来渲染。嗯,简单的三步走。

接下来,我们前进一步,看看如何对所渲染的图形设置颜色。我们基于上述例子之上添加几行代码。让我们还是新建一个项目窗口,然后向其中添加如下代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 声明PShape类型对象
PShape rectangle;
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 设置窗口大小
  size(640, 360, P2D);
  // 创建PShape对象
  // 四个参数,从左到右,依次为:
  // 所创建的图形类型为RECT,
  // RECT是Processing提供的一个常量,
  // 接下来是图形的起始坐标x, y为 10, 10
  // 最后两个参数是图形的宽和高 100, 50
  rectangle = createShape(RECT, 10, 10, 100, 50);
  // 设置矩形外边框颜色为白色
  rectangle.setStroke(color(255));
  // 设置矩形外边框的宽度
  rectangle.setStrokeWeight(4);
  // 设置矩形的内填充色
  rectangle.setFill(color(127));
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 设置背景色
  background(51);
  // 渲染矩形
  shape(rectangle);
}

编译并运行上述代码,运行结果大致如下所示。

processing-fun-pshape-2

图片来源:Processing程序执行结果

在这个例子中,我们对于这个矩形,我们做了三个方面的设置。首先,外边框设置为了白色,调用的setStroke()方法,其次是外边框的宽度,通过调用setStrokeWeight()方法设置成了4,最后调用setFill()方法,设置了矩形的内填充色。可以看到,这三个方法都是通过rectangle对象变量进行调用的。也就是说,PShape类型提供了相应的设置方法。
有朋友可能有疑惑了,不是说是自定义图形么?那除了矩形以外,怎样画其他类型的图形呢?按照画矩形的这种方式,RECT常量还可以换成ARCELLIPSETRIANGLE等等。随着所画图形类型的改变,createShape()方法后面的参数也会相应的有所变化。有兴趣的朋友,可以自己查一下文档,看看具体是怎样的,这里就不重复演示了?

就这些吗?当然不是!上面介绍的不管怎样,都是固定类型的图形。那么,接下来就让我们看看如何画任意多边形!

画五角星

话说,新建一个项目窗口,将如下代码填入其中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 声明PShape类型对象
PShape star;
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 设置窗口大小
  size(640,360,P2D);
  // 创建PShape类型对象。
  // 注意此处没有参数。
  star = createShape();
  // 开始设置图形
  star.beginShape();
  // 设置图形填充色
  star.fill(102);
  // 设置图形边框颜色
  star.stroke(255);
  // 设置图形边框宽度
  star.strokeWeight(2);
  // 设置图形的每一个点
  star.vertex(0, -50);
  star.vertex(14, -20);
  star.vertex(47, -15);
  star.vertex(23, 7);
  star.vertex(29, 40);
  star.vertex(0, 25);
  star.vertex(-29, 40);
  star.vertex(-23, 7);
  star.vertex(-47, -15);
  star.vertex(-14, -20);
  // 结束设置图形
  // 方法中传入一个常量为 CLOSE
  star.endShape(CLOSE);
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 设置背景色
  background(51);
  // 图形跟随鼠标坐标进行移动
  translate(mouseX, mouseY);
  // 渲染矩形
  shape(star);
}

运行上述代码,运行结果大致如下图所示。

processing-fun-pshape-3

图片来源:Processing程序执行结果

可以看到,在这个例子中,我们实现了自定义图形,每执行一句star.vertex()就会添加一个点,最后一句star.endShape(CLOSE)结束整个图形的设置。最后需要注意一点,在这个例子中,我们添加了translate(mouseX, mouseY)方法。图形会随着鼠标的移动而移动。也就是说,五角星会随着鼠标进行移动。

画正弦曲线

新建一个项目窗口,填入下面代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 声明PShape类型对象
PShape path;
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 设置窗口大小
  size(640,360,P2D);
  // 创建PShape类型对象。
  path = createShape();
  // 开始设置图形
  path.beginShape();
  // 取消填充色
  path.noFill();
  // 设置外边框颜色为白色
  path.stroke(255);
  // 设置外边框宽度为2
  path.strokeWeight(2);
  // 定义曲线x轴坐标变量
  float x = 0;
  // 计算正弦曲线各个的点
  // TWO_PI 为360 度
  for (float a = 0; a < TWO_PI; a += 0.1) {
    // 添加正弦曲线的点
    // y轴坐标值为 sin() 方法的求值结果
    path.vertex(x,sin(a)*100);
    // 向右移动5个坐标
    x+= 5;
  }
  // 终止图形设置
  path.endShape();
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 设置背景色
  background(51);
  // 图形跟随鼠标移动
  translate(mouseX, mouseY);
  // 渲染矩形
  shape(path);
}

运行示例代码,结果大致如下所示。

processing-fun-pshape-4

图片来源:Processing程序执行结果

从运行结果可以看出,我们画出了一条正弦曲线。这里主要用到了Processing为我们提供的sin()方法,此计算结果作为对应点的y轴数值。

内部图形剪切

除了我们可以根据自己的需要画出不同的图形以外,我们还可以画一些嵌套图形。下面,我们还是举例来说明。

首先,还是新建一个项目窗口。然后,填入下述代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 声明PShape类型对象
PShape s;
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 设置窗口大小
  size(640,360,P2D);
  // 创建PShape类型对象。
  s = createShape();
  // 开始设置图形
  s.beginShape();
  // 图形外围坐标点
  s.vertex(-100,-100);
  s.vertex(100,-100);
  s.vertex(100,100);
  s.vertex(-100,100);
  s.vertex(-100,-100);
  // 剪切图形内部坐标点
  s.beginContour();
  s.vertex(-30,-10);
  s.vertex(-10,10);
  s.vertex(10,10);
  s.vertex(10,-10);
  s.endContour();
  // 结束画图
  s.endShape();
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 设置背景色
  background(51);
  // 图形跟随鼠标移动
  translate(mouseX, mouseY);
  // 渲染矩形
  shape(s);
}

运行示例,得出类似如下运行结果。

processing-fun-pshape-5

图片来源:Processing程序执行结果

示例中出现了一对新面孔,那就是s.beginContour()s.endContour()。既然说这是一对方法,那就说明这两个方法通常来说都是成对使用的,跟s.beginShape()s.endShape()一样,但效果正好是截然相反。

图形分组

除了基本的画图以外,我们还可以对多个图形进行分组。嗯,我们还是以示例来说明。

首先呢,还是新建一个项目窗口,填入下面代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 声明PShape类型对象
PShape alien;
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
  // 设置窗口大小
  size(640,360,P2D);
  // 创建PShape对象变量,
  // 类型为GROUP
  alien = createShape(GROUP);
  // 创建PShape对象变量,
  // 类型为椭圆
  PShape head = createShape(ELLIPSE, 0, 0, 50, 50);
  // 创建PShape对象变量,
  // 类型为矩形
  PShape body = createShape(RECT, -25, 25, 50, 100);
  // 将PShape对象head添加到alien中
  alien.addChild(head);
  // 将PShape对象body添加到alien中
  alien.addChild(body);
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
  // 设置背景色
  background(51);
  // 将图形移到窗口中央
  translate(width/2, height/2);
  // 渲染图形分组
  shape(alien);
}

运行示例代码,运行结果大致如下所示。

processing-fun-pshape-6

图片来源:Processing程序执行结果

从执行结果中,看不出有什么不同。这个示例里面需要注意的地方是这句alien.addChild(),这一句是将其他子图形进行关联的语句。另外还有一点需要注意的是,创建alien对象类型的时候,使用的是GROUP

总结

这次学习的内容看起来好像还是蛮杂的,不过主要还是围绕着PShape展开。简单回顾一下,从学习简单的画矩形开始,通过使用此方法扩展到其他基本图形,比如椭圆啊,圆形啊等等。接下来学习如何画自定义图形,这里以画五角星为例,然后是画正弦图形,再接着是图形的剪切,最后是图形的分组。

下期预告

过去这段时间一直在学习图形方面的内容,是不是有点烦了?好!下一次我们就学习一下Processing对于数据的处理!

Comments