Processing 允许使用面向对象编程(OOP)技术来使 Processing 应用程序更易于开发和维护。与其他面向对象的语言一样,Processing 使用 ​Class​​ 的概念来定义对象模板。

我们先来看一个例子:假设平坦的马路上跑着一辆轿车,轿车的颜色为白色,当前速度为1公里每小时,轿车类型为自动挡。现在我们想在Processing里绘制这样一个场景,如何做呢?

// 定义轿车的颜色
color c;
// 定义轿车的x坐标位置
float xpos;
// 定义轿车的y坐标位置
float ypos;
// 定义轿车的车速
float xspeed;
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
// 初始化窗口大小
size(200, 200);
// 初始化轿车颜色
c = color(255);
// 初始化轿车的x坐标
xpos = width/2;
// 初始化轿车的y坐标
ypos = height/2;
// 初始化轿车的车速
xspeed = 1;
}
// 画图。
// 此方法被系统默认循环调用。
void draw() {
// 设置窗体背景色为黑色
background(0);
// 调用display()方法
display();
// 调用drive()方法
drive();
}
// 自定义显示轿车的方法
void display(){
// 设置轿车的锚定点为矩形中心
rectMode(CENTER);
// 设置轿车的颜色
fill(c);
// 将轿车画成矩形
rect(xpos, ypos, 20, 10);
}
// 自定义轿车的制动方法
void drive(){
// 轿车将在x轴上向前移动,
// 移动的速度为xspeed
xpos = xpos + xspeed;
// 判断轿车是否超出了窗体的右侧,
// 若超出,则轿车将从窗体左侧重新驶入。
if(xpos > width){
// 将轿车的位置重新设置为窗体的左侧
xpos = 0;
}
}

上面的这段代码,就是我们通常最先想到的方法。这种方式很显然不太友好,为什么这么说呢?假设我们想要再创建一辆轿车,颜色为红色,速度为2公里每小时,那岂不是还要再定义一遍上面用到的变量?比如,车的颜色为了分别记录两辆车,所以要定义两个​​color​​,位置记录也要重新定义一遍,车速的变量也要重新定义一遍。以此类推,要是定义五辆轿车,那就要写五遍同样的变量。嗯,这确实是个问题。那应该怎么办呢?

嗯,这就涉及到今天所要讲的内容,对象。

真实的世界里,每个具体的事物都是对象,某一辆轿车,是一个对象,再一辆轿车,又是一个对象,多辆轿车,就是多个对象,以此类推。如果我们定义一个模具,通过这个模具可以马上定制出,具有不同属性的轿车,那不就方便了么?到那个时候,我们想要多少轿车,就可以很容易的定制出多少轿车。那这个模具,在Processing这里,称之为​​class​​,也就是类。我们定义一个类,也就是定义了一个模具,以后想要多少轿车,就可以用这个模具定制出多少轿车。妙哉吧!好,让我们看看这个类都包括哪些内容,具体怎么定义?

一般来说,一个类包括四部分,分别为,类名,数据,构造器,方法。那么,接下来让我们讲上面的示例改造成一个轿车的类,方便我们以后使用。

class Car{
color c;
float xpos;
float ypos;
float xspeed;

Car(color tempC, float tempXpos, float tempYpos, float tempXspeed){
c = tempC;
xpos = tempXpos;
ypos = tempYpos;
xspeed = tempXspeed;
}

void display() {
rectMode(CENTER);
fill(c);
rect(xpos, ypos, 20, 10);
}

void drive(){
xpos = xpos + xspeed;
if (xpos > width) {
xpos = 0;
}
}
}

上面代码中,分别定义数据、定义构造器、定义方法。

1)构造器:

其命名要与类名保持一样,然后会在定义对象的时候,自动调用。除此之外,构造器还可以进行初始化变量。定义一个新的对象,需要用到​new​关键字,紧接着就是类名,类名后面的括号,可以传入构造器中,括号里定义的参数。比如定义一个新的轿车对象,示例代码如下:

myCar = new Car(color(255, 0, 0), 0, 100, 1);

2)方法:

每个方法都有返回数值,关键字​​void​​​比较特殊,它定义了此方法可以没有返回值,或者说,返回值可以为空。紧接着,后面的​​display()​​​为方法名,括号里可以放传入的参数,此处为空。如果方法的返回类型不是​​void​​​,则需要在方法的最后一行添加一条​​return​​​语句,​​return​​​后面有一个空格,然后是需要返回的结果。由于此方法的返回类型为​​void​​​,所以方法的最后一行的省掉了​​return​​语句。

好了,回到项目主体

// 声明轿车变量myCar
Car myCar1;
Car myCar2;
// 环境初始化。
// 此方法在软件启动时,被系统调用一次。
void setup() {
// 设置窗口
size(200, 200);
// 创建myCar对象。
// 并传入四个参数:
// tempC = color(255, 0, 0)
// tempXpos = 0
// tempYpos = 100
// tempXspeed = 1
myCar1 = new Car(color(255, 0, 0), 0, 100, 1);
// 参见上面myCar1的注释
myCar2 = new Car(color(0, 255, 0), 0, 150, 1.5);
}
// 画图
// 此方法被系统默认循环调用
void draw() {
// 设置背景色为黑色
background(0);
// 调用myCar1对象的drive()方法
myCar1.drive();
// 调用myCar对象的display()方法
myCar1.display();
// 调用myCar2对象的drive()方法
myCar2.drive();
// 调用myCar2对象的display()方法
myCar2.display();
}

在上面的主体框架中,创建了两个轿车对象,一个是​​myCar1​​​,另一个是​​myCar2​​​。在框架​​setup​​​中进行创建,并初始化相应参数。在框架​​draw()​​​方法中,对两个对象的​​drive()​​​方法和​​display()​​​方法分别进行了调用。这里要说的一点是,调用对象的方法需要在对象后面加一个​​.​​,然后紧跟方法名。

Processing-对象(class)_构造器

参考:​​http://ohcoder.com/blog/2016/03/18/processing-fun-object/​

最后,我们举一个水滴扩散的例子:

class Drop {

int x, y; // Coordinate (center of circle)
int diameter; // Diameter of circle (unused == 0).

void init( int ix, int iy ) {
x = ix;
y = iy;
diameter = 1;
}

void spread() {
if (diameter > 0) diameter += 1;
}

void show() {
if (diameter > 0) {
ellipse( x, y, diameter, diameter );
if (diameter > 500) diameter = 0;
}
}

}

现在我们来看一下如何使用 ​​Drop​​​ 类来构建一些利用用户输入的图形。清单 4 给出使用 ​​Drop​​​ 类的应用程序。第一步是创建一个水滴数组(称为 ​​drops​​​)。之后进行几个定义(​​drops​​​ 数组中的水滴数和工作索引)。在 ​​setup​​​ 函数中,您可以创建显示窗口并初始化 ​​drops​​​ 数组(所有直径为 0 或未使用)。​​draw​​​ 函数相当简单,因为水滴的核心功能在类本身内部(​​清单 3​​​ 中的 ​​spread​​​ 和 ​​show​​​)最后,添加 UI 部分,该部分允许用户定义水滴从何处开始。​​mousePressed​​ 回调函数通过当前鼠标位置(目前有一个直径且是使用过的)初始化水滴,然后递增当前水滴索引。

Drop[] drops;
int numDrops = 30;
int curDrop = 0;

void setup() {
size(400, 400);
ellipseMode(CENTER);
smooth();
drops = new Drop[numDrops];
for (int i = 0 ; i < numDrops ; i++) {
drops[i] = new Drop();
drops[i].diameter = 0;
}
}

void draw() {
background(0);
for (int i = 0 ; i < numDrops ; i++) {
drops[i].spread();
drops[i].show();
}
}

void mousePressed() {
drops[curDrop].init( mouseX, mouseY );
if (++curDrop == numDrops) curDrop = 0;
}

Processing-对象(class)_构造器_02

参考:

​https://www.ibm.com/developerworks/cn/opensource/os-datavis2/index.html​