Oh!Coder

Coding Life

有趣的Processing-挥舞手臂的机器人

| Comments

之前的学习当中,我们学习了Processing关于2d图形的基本变换,其中包括平移,旋转和缩放。为了能够进一步熟练掌握这些内容,这次我们将利用之前学过的一些知识,真正实现一个会自动挥舞手臂的机器人!好!多余的话我们就先不说,让我们直接进入正题吧!

设计轮廓

首先呢,我们因该先要想明白,画出来的机器人是个什么样子的。所以,第一步还是先新建一个项目窗口。

processing-new-windo

图片来源:Processing新项目窗口

向其中添加如下代码。

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
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup()
{
  // 设置窗口大小
  size(200, 200);
  // 设置背景色
  background(255);
  // 开启图形反锯齿效果,
  // 让图形的边缘变的更光滑
  smooth();
  // 画出机器人
  drawRobot();
}
// 画出机器人
void drawRobot()
{
  // 去掉图形边框
  noStroke();
  // 设置填充色
  fill(38, 38, 200);
  // 画出机器人的头
  rect(20, 0, 38, 30);
  // 画出机器人的身体
  rect(14, 32, 50, 50);
  // 画出机器人的左手臂
  rect(0, 32, 12, 37);
  // 画出机器人的右手臂
  rect(66, 32, 12, 37);
  // 画出机器人的左腿
  rect(22, 84, 16, 50);
  // 画出机器人的右腿
  rect(40, 84, 16, 50);
  // 设置填充色
  fill(222, 222, 249);
  // 画出机器人的左眼
  ellipse(30, 12, 12, 12);
  // 画出机器人的右眼
  ellipse(47, 12, 12, 12);
}

运行上面这个示例,让我们先大体看一看,设计完成后的机器人长什么样子。

点击项目窗口中,菜单栏里的三角形按钮,如下图所示。

processing-window-menu

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

一切顺利的话,我们会看到如下图所示的运行结果。

processing-fun-2d-robot-1

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

现在,我们看到了我们将要设计的机器人长的样子。首先,他有一双水汪汪的大眼睛……

好!接下来呢,我们就一步一步的改进,逐步完成可以挥舞手臂的那个机器人。

首先,基于上面的那个例子,我们一步一步的进行改造。第一步,先改造两只手臂,分别将左手臂和右手臂提炼出来,使用两个单独的方法分别画出来。改造后的代码如下:

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup()
{
  // 设置窗口大小
  size(200, 200);
  // 设置背景色
  background(255);
  // 开启图形反锯齿效果,
  // 让图形的边缘变的更光滑
  smooth();
  // 画出机器人
  drawRobot();
}
// 画出机器人
void drawRobot()
{
  // 去掉图形边框
  noStroke();
  // 设置填充色
  fill(38, 38, 200);
  // 画出机器人的头
  rect(20, 0, 38, 30);
  // 画出机器人的身体
  rect(14, 32, 50, 50);
  // 画出机器人的左手臂
  drawLeftArm();
  // 画出机器人的右手臂
  drawRightArm();
  // 画出机器人的左腿
  rect(22, 84, 16, 50);
  // 画出机器人的右腿
  rect(40, 84, 16, 50);
  // 设置填充色
  fill(222, 222, 249);
  // 画出机器人的左眼
  ellipse(30, 12, 12, 12);
  // 画出机器人的右眼
  ellipse(47, 12, 12, 12);
}
// 画出机器人的左手臂
void drawLeftArm()
{
  // 保存窗口当前坐标系位置
  pushMatrix();
  // 移动窗口坐标系位置
  translate(12, 32);
  // 画左手臂
  rect(-12, 0, 12, 37);
  // 恢复窗口当前坐标系位置
  popMatrix();
}
// 画出机器人的右手臂
void drawRightArm()
{
  // 保存窗口当前坐标系位置
  pushMatrix();
  // 移动窗口坐标系位置
  translate(66, 32);
  // 画右手臂
  rect(0, 0, 12, 37);
  // 恢复窗口当前坐标系位置
  popMatrix();
}

现在运行程序示例,从结果中我们可以看到,和上一个示例中的运行效果是一样的。为了让机器人的手臂有一个旋转的效果,我们需要再添加两行旋转代码。将这两行代码只需要添加在drawLeftArm()方法和drawRightArm()方法中。但是为了能够大家更容易的看到代码的全貌,我们这里还是将完整的示例代码展示出来。

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup()
{
  // 设置窗口大小
  size(200, 200);
  // 设置背景色
  background(255);
  // 开启图形反锯齿效果,
  // 让图形的边缘变的更光滑
  smooth();
  // 画出机器人
  drawRobot();
}
// 画出机器人
void drawRobot()
{
  // 去掉图形边框
  noStroke();
  // 设置填充色
  fill(38, 38, 200);
  // 画出机器人的头
  rect(20, 0, 38, 30);
  // 画出机器人的身体
  rect(14, 32, 50, 50);
  // 画出机器人的左手臂
  drawLeftArm();
  // 画出机器人的右手臂
  drawRightArm();
  // 画出机器人的左腿
  rect(22, 84, 16, 50);
  // 画出机器人的右腿
  rect(40, 84, 16, 50);
  // 设置填充色
  fill(222, 222, 249);
  // 画出机器人的左眼
  ellipse(30, 12, 12, 12);
  // 画出机器人的右眼
  ellipse(47, 12, 12, 12);
}
// 画出机器人的左手臂
void drawLeftArm()
{
  // 保存窗口当前坐标系位置
  pushMatrix();
  // 移动窗口坐标系位置
  translate(12, 32);
  // 旋转手臂
  rotate(radians(135));
  // 画左手臂
  rect(-12, 0, 12, 37);
  // 恢复窗口当前坐标系位置
  popMatrix();
}
// 画出机器人的右手臂
void drawRightArm()
{
  // 保存窗口当前坐标系位置
  pushMatrix();
  // 移动窗口坐标系位置
  translate(66, 32);
  // 旋转手臂
  rotate(radians(-45));
  // 画右手臂
  rect(0, 0, 12, 37);
  // 恢复窗口当前坐标系位置
  popMatrix();
}

可以看到,上述代码我们只是添加了两个rotate()方法。这里需要注意的是translate()方法和rotate()方法的先后顺序,这是不同的。如果将这两个方法颠倒过来会有什么效果呢?有兴趣的朋友可以试一试,看看有什么不同的效果。好,运行上述代码,会看到机器人的手臂位置不同了,但问题是,依然无法灵活转动,如下图所示。

processing-fun-2d-robot-2

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

最后一步,我们要想办法让机器人的手臂持续的转动起来。怎么做呢?嗯,我们需要添加几个全局变量。我们还是直接上代码,用代码示例来展示如何做。

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// 定义手臂角度变量
int armAngle = 0;
// 定义手臂转动速度
int angleChange = 5;
// 定义手臂最大转动角度
final int ANGLE_LIMIT = 135;
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup()
{
  // 定义窗口大小
  size(200, 200);
  // 开启图形反锯齿效果
  smooth();
}
// 画图。
// 此方法被系统默认循环调用。
void draw()
{
  // 设置窗口背景色
  background(255);
  // 保存窗口当前坐标系位置
  pushMatrix();
  // 将机器人移动至屏幕中央附近,
  // 保证机器人所有部位都在屏幕可见范围内
  translate(50, 50);
  // 画机器人
  drawRobot();
  // 改变手臂的角度
  armAngle += angleChange;
  // 判断手臂的旋转角度是否在0~135度之间。
  // 若不在此范围内,则改变手臂旋转角度
  if (armAngle > ANGLE_LIMIT || armAngle < 0)
  {
    // 改变角度的正负值
    angleChange = -angleChange;
    // 更新机器人手臂旋转角度
    armAngle += angleChange;
  }
  // 恢复窗口当前坐标系位置
  popMatrix();
}
// 画机器人
void drawRobot()
{
  // 去掉图形的外边框
  noStroke();
  // 设置填充色
  fill(38, 38, 200);
  // 画机器人的头部
  rect(20, 0, 38, 30);
  // 画机器人的身体
  rect(14, 32, 50, 50);
  // 画左手臂
  drawLeftArm();
  // 画右手臂
  drawRightArm();
  // 画左腿
  rect(22, 84, 16, 50);
  // 画右腿
  rect(40, 84, 16, 50);
  // 设置填充色
  fill(222, 222, 249);
  // 画左眼
  ellipse(30, 12, 12, 12);
  // 画右眼
  ellipse(47, 12, 12, 12);
}
// 画左手臂
void drawLeftArm()
{
  // 保存窗口当前坐标系位置
  pushMatrix();
  // 平移坐标系位置
  translate(12, 32);
  // 旋转左手臂
  rotate(radians(armAngle));
  // 画左手臂
  rect(-12, 0, 12, 37);
  // 恢复窗口当前坐标系位置
  popMatrix();
}
// 画右手臂
void drawRightArm()
{
  // 保存窗口当前坐标系位置
  pushMatrix();
  // 平移坐标系位置
  translate(66, 32);
  // 旋转右手臂
  rotate(radians(-armAngle));
  // 画右手臂
  rect(0, 0, 12, 37);
  // 恢复窗口当前坐标系位置
  popMatrix();
}

添加完成之后,我们运行上述代码,现在可以看到,机器人的手臂可以自动旋转啦!

processing-fun-2d-robot-3

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

现在,让我们看看是如何做到的。其实,相比于上面静止不动的例子,我们这里添加了三个全局变量。这三个全局变量分别定义了,手臂当前旋转的角度,手臂的旋转速度以及手臂的最大旋转角度。这里注意一下,我们在定义手臂最大旋转角度的时候,通过关键字final定义了一个常量。所谓常量,简单来说就是定义的时候赋值,之后的使用过程中,就不可对此常量的值进行修改了。例如这里的ANGLE_LIMIT常量,其数值在后面的程序中只能获取,不能赋值。

总结

今天学习的几段示例代码中,没有出现新的面孔,目的也是为了巩固已经学到的一些基础知识。为了能够达到这个目的,我们单独拿出一个例子来进行学习。

下期预告

之前我们学习了如何画出基本图形,以及最近学习了对基本图形的变换。那么,如果我们想画出一些自定义图形要怎么做呢?比如五边形,六边形等等。好!这个问题就留给我们下一次的学习吧!

Comments