Processing 是一门开源编程语言和及其配套IDE的名称,是JAVA语言的一个分支,通过它可以表达被数字化的美好创意。
1 打印“HELLO WORLD”
Processing程序一般由全局变量、setup()函数、draw()函数和其他自定义全局函数,在标签中定义的类(一般一个标签定义一个类)构成。
- setup()函数只会在程序开始运行时执行一次,一般做一些初始化工作;
- draw()函数每帧都会执行一次,默认帧速率是60fps,程序不断调用该函数,刷新画面,形成动画。
- 若在draw()中用到用户定义的全局变量控制形状的各种属性,那么更改全局变量的值即可改变每帧显示的内容。
| 描述 | 函数 |
|---|---|
| 每帧调用一次 | draw() |
| 只在程序开始运行时执行一次 | setup() |
| 设置帧速率(默认60fps) | frameRate(fps) |
| 查看帧速率 | 变量 frameRate |
| 查看当前是第几帧 | 变量 frameCount |
下面我们看一段示例代码:
float deg = 0;//全局变量deg:控制draw()函数每帧输出的画面不同
void setup() {//只在程序开始运行时执行一次
size(480, 200);//设置窗口大小
textSize(48);//设置字号大小
println("hello world!");//在控制台窗口输出
}
void draw() {//每帧都会调用一次
background(map(sin(-deg), -1, 1, 0, 255));//全屏幕填充纯色
fill(map(sin(deg), -1, 1, 0, 255));//设置(文字的)填充色
deg += 0.01;
text("HELLO WORLD", 75, 120);//绘制文字,文字左下角坐标为(75,120)
}
该函数实现的功能如下图所示:在控制台窗口输出“hello world!”,在图形窗口中显示“HELLO WORLD”,背景色和字体颜色的灰度随时间周期性改变。
由于背景色和字体颜色是动态变化的,所以绘制背景颜色的background()和绘制字体的text()应写在draw()函数中。若不清屏,每帧的图像都会叠加在窗口中显示,后绘制的覆盖之前绘制的。文字在背景上方,因此先调用background(),后调用text()。
灰度值的范围在0~255之间,我们需要使一个变量在0到255之间来回震荡,由于sin()函数的曲线较为平滑且具有周期性,故定义一个不断增大的全局变量deg,通过map()函数把sin(deg)的值域映射到0到255之间。
2 绘制
1.1 绘制基本图形
| 形状 | 函数 |
|---|---|
| 点 | point(x, y) |
| 线 | line(x1, y1, x2, y2) |
| 三角形 | triangle(x1, y1, x2, y2, x3, y3) |
| 四边形 | quad(x1, y1, x2, y2, x3, y3, x4, y5) |
| 矩形 | rect(x, y, width, height) |
| 椭圆 | ellipse(x, y, radius_x, radius_y) |
| 扇形 | arc(x, y, weight, height, start_deg, end_deg) |
void setup() {
size(900, 300);\\设置窗口大小
point(50, 50);
\\在坐标(50,50)处绘制一个点
line(100, 50, 100, 250);
\\以坐标(100,50),(100,250)为端点画线
triangle(150, 50, 150, 250, 250, 250);
\\以坐标(150,50)(150,250)(250,250)为顶点绘制三角形
rect(300, 50, 100, 200);
\\以坐标(300,50)为左上定点,绘制宽100px、高200px的矩形
ellipse(500, 150, 100, 200);
\\以坐标(500,150)为中心,绘制长轴为100px、短轴为200px的椭圆
arc(700, 150, 200, 200, PI/4.0, 7*PI/4.0);
\\以坐标(700,150)为圆心,绘制直径为200的扇形,半径扫过角度为π/4~7π/4
}
运行结果:
1.2 绘制自定义多边形
| 描述 | 函数 |
|---|---|
| 表示开始绘制 | beginShape() |
| 多次调用,给定顶点坐标 | vertex(x, y) |
| 表示绘制结束 | endShape(CLOSE) |
void setup() {
size(900, 300);
beginShape();//开始绘制
vertex(50, 50);//给定多边形顶点
vertex(450, 140);
vertex(850, 50);
vertex(850, 250);
vertex(450, 160);
vertex(50, 250);
endShape(CLOSE);//结束绘制,加“CLOSE”表示曲线闭合
}
运行结果:
1.3 形状属性设置
| 描述 | 函数 |
|---|---|
| 描边粗细 | strokeWeight(pixel) |
| 描边端点样式(默认:ROUND) | strokeCap(ROUND/SQUARE/PROJECT) |
| 描边转角样式(默认:MITER) | stokeJoin(MITER/ROUND/BEVEL) |
| 填充颜色 | fill(r, g, b, alpha) |
| 描边颜色 | stroke(r, g, b, alpha) |
| 隐藏填充 | noFill() |
| 隐藏描边 | noStroke() |
| 形状绘制样式(函数名以Mode结尾) | 如:ellipseMode(CENTER/RADIUS) |
| 设置单个像素的颜色 | set(x, y, color) |
| 全屏填充纯色 | background(r, g, b, alpha) |
- 若要绘制多个不同属性的图形,那么各自在绘制之前需要先通过函数修改绘制属性。
- 函数fill(),stroke(),background()的参数都是与颜色相关的,其值都在0~255之间,若只有一个参数则表示灰度,若有三个参数则表示RGB值,若有第四个参数则表示不透明度。
- 形如“形状+Mode()”的函数,如ellipseMode(),用来修改形状绘制样式,椭圆的绘制样式默认为CENTER,改为RADIUS后要求输入半径而不是直径,当然还有更多样式。
- strokeCap()设置描边端点样式,有ROUND(圆角)/SQUARE(矩形)/PROJECT(扩展)三种,默认为ROUND。
- stokeJoin()设置描边转角样式,有MITER(斜接)/ROUND(圆角)/BEVEL(斜切)三种,默认为MITER。
void setup() {
size(900, 300);
translate(width / 2, height / 2);
background(255);
/*绘制参考线和注释*/
stroke(0, 0, 255, 128);
line(-450, -50, 450, -50);
line(-450, 50, 450, 50);
fill(0, 0, 255, 128);
textSize(28);
text("ROUND/SQUARE/PROJECT", -450, 100);
text("MITER/ROUND/BEVEL", 150, 100);
/*绘制中间部分*/
noStroke();
ellipseMode(RADIUS);
fill(255, 0, 0, 128);
ellipse(-50, 45, 80, 80);
fill(255, 255, 0, 128);
ellipse(50, 45, 80, 80);
fill(0, 0, 255, 128);
ellipse(0, -50, 80, 80);
set(50, 50, 0);
/*绘制3种描边端点样式*/
noFill();
stroke(32);
strokeWeight(15);
strokeJoin(MITER);
rect(-400, -50, 50, 100);
strokeJoin(ROUND);
rect(-300, -50, 50, 100);
strokeJoin(BEVEL);
rect(-200, -50, 50, 100);
/*绘制3种描边转角样式*/
strokeWeight(35);
strokeCap(ROUND);
line(200, -50, 200, 50);
strokeCap(SQUARE);
line(300, -50, 300, 50);
strokeCap(PROJECT);
line(400, -50, 400, 50);
}
运行结果:
2 数据类型
2.1 基本数据类型
| 类型名 | 描述 |
|---|---|
| boolean | 布尔型 |
| char | 字符型 |
| int | 整型 |
| float | 浮点型(8字节) |
| String | 字符串 |
2.2 图片类 PImage
| 描述 | 函数 |
|---|---|
| 从文件读取图片到图片对象 | PImage img = loadImage(“xxx.png”); |
| 在窗口绘制图片对象 | image(img, x, y) |
首先点击“速写本”>“添加文件”,导入你的图片,此时会把导入的图片拷贝到工程文件中。如下代码演示了从图片文件加载图片到PImage对象中,然后用image()函数在窗口中输出,image()函数的第一个参数是要显示的图片,第二、三个参数是显示的位置坐标,第四、五个参数可选,用来设置显示图片的宽高。
PImage pic;若要在draw()中使用该图片,需要定义为全局变量
void setup() {
size(500, 300);
pic = loadImage("mypic.jpg");//加载图片
image(pic, 0, 0, 500, 300);//在原点显示长500,宽300的图片
}
运行结果:
2.3 字体类 PFont
| 描述 | 函数 |
|---|---|
| 从文件加载字体到字体对象 | PFont font = createFont(“xxx.ttf”); |
| 设置当前字体 | textFont(font) |
| 设置当前字号 | textSize(size) |
和加载图片类似,需要点击“速写本”>“添加文件”,导入字体文件。
PFont font1;//若要在draw()中使用字体,需要定义为全局变量
PFont font2;
void setup() {
size(500, 300);
font1 = createFont("xxx.ttf", 32); //使用字体文件
font2 = createFont("微软雅黑", 32); //使用已安装字体
textFont(font1);//显示文字
text("hello world!",50, 100);
}
2.4 矢量图形类PShape
| 描述 | 函数 |
|---|---|
| 加载SVG文件到图形类中 | PShape shape = loadShape(“xxx.svg”); |
| 在窗口绘制图形对象 | shape(myShape, x, y, width, height) |
得到矢量图形的方法有两种,可以加载SVG文件到图形对象中,也可以用矢量图形对象的成员方法beginShape()、vertex()和endShape(CLOSE)自行绘制。
PShape shape1;
PShape shape2;
void setup() {
size(500, 300);
/*从svg文件中得到矢量图*/
shape1 = loadShape("xxx.svg");
shape(shape1, 0, 0, 100, 100);
/*在程序中自行绘制矢量图*/
shape2 = createShape();
shape2.beginShape();
shape2.vertex(50, 50);
shape2.vertex(50, 100);
shape2.vertex(100, 100);
shape2.endShape();
shape(shape2, 0, 0);
}
3 改变视角
| 描述 | 函数 |
|---|---|
| 平移:平移坐标系原点 | translate(x, y) |
| 旋转:以原点中心旋转坐标系 | rotate(deg) |
| 缩放:缩放坐标系 | scale(arg) |
| 保存当前视角 | pushMatrix() |
| 还原所保存的视角 | popMatrix() |
改变视角,即改变坐标轴和窗口的相对位置,图形的坐标是并不会改变,图形和坐标轴的相对位置不变。若把窗口看做参照物,变化的是整个坐标轴和图形整体。
- translate(x, y):将坐标轴向右平移x像素,向下平移y像素
- rotate(deg):以原点中心旋转坐标系deg个弧度
- scale(arg):以原点中心缩放坐标系arg倍数
- 通过pushMatrix()和popMatrix()函数,可以实现独立变换,使当前的变换效果只作用在一个图形上。在对该图形绘制前,先用pushMatrix()备份,然后进行针对该图形的变换,图形绘制完成后用popMatrix()还原,这样刚才的变换只作用于本次图形绘制。
可以在draw()中不断调用这三个函数,不断改变视角,绘制的图形就会动起来,当然我们并没有改变图形的坐标。三个函数可以同时调用,形成更加丰富的变换效果,若没有使用background()函数覆盖上一帧绘制的图形,则会在窗口上留下之前绘制的结果。
float x = 0;
void setup() {
size(900, 300);
}
//使坐标系的原点始终位于鼠标位置,并以每帧0.1弧度的速度旋转
void draw() {
translate(mouseX, mouseY);//平移,(mouseX, mouseY)为当前鼠标位置的坐标
rotate(x);//旋转
rect(0, 0, 50, 50);
x += 0.1;
}
运行结果:
4 通过鼠标和键盘交互
4.1 鼠标
| 描述 | 函数或变量 |
|---|---|
| 当前帧鼠标的位置坐标 | 变量 mouseX, mouseY |
| 前一帧鼠标的位置坐标 | 变量 pmouseX, pmouseY |
| 计算鼠标速度(实质是计算距离) | dist(mouseX, mouseY, pmouseX, pmouseY) |
| 判断鼠标是否按下 | 变量 mousePressed (按下为True) |
| 查看哪个按键被按下 | 变量 mouseButton |
如下代码绘制了一个小球跟随鼠标,鼠标按下则变色,鼠标划得快则直径变小:
void setup() {
size(900, 300);
}
void draw() {
background(0);
fill(255);//若鼠标不按下,小球显示白色
if(mousePressed){
if(mouseButton == RIGHT){
fill(255, 0, 0);//若按下鼠标左键,小球显示红色
}else if(mouseButton == LEFT){
fill(0, 255, 0);//若按下鼠标右键,小球显示绿色
}
}
float speed = dist(mouseX, mouseY, pmouseX, pmouseY);
if(speed > 30)speed = 30;//测量速度,上限为30px每帧
float radius = map(speed, 0, 30, 50, 30);
ellipse(mouseX, mouseY, radius, radius);
}
4.2 键盘
| 描述 | 变量 |
|---|---|
| 判断是否有按键按下 | 变量 keyPressed(按下为True) |
| 最后一次按键的信息 | key |
如下代码演示了如何在窗口中输出当前按下的按键所对应的字符:
float deg = 0;
float x = 0;
void setup() {
size(900, 300);
textSize(64);
}
void draw() {
translate(width / 2, height / 2);//平移
if(keyPressed){
rotate(deg);//旋转
scale(map(sin(x), -1, 1, 1, 5));//放大
deg -= 1;
x += 0.1;
fill(random(0, 255), random(0, 255) ,
random(0, 255), map(sin(x), -1, 1, 255, 0));
text(key, -80, -30);//输出从键盘得到的数
}
}
运行结果:
5 从文件录入数据
5.1 从CSV文件读取数据
| 描述 | 函数 |
|---|---|
| 读取CSV文件数据到Table对象中 | Table table = loadTable(“xxx.csv”, “header”) |
| 读取表格第i行第j列的数据 | table.getInt(1, 2) |
5.2 从JSON文件读取数据
| 描述 | 函数 |
|---|---|
| 从文件中读取一个JSON类 | JSONObject js = loadJSONObject(“xxx.json”); |
| 从文件中读取一个JSON数组 | JSONArray jsonArr = loadJSONArray(“xxx.json”); |
| 解析出JSON类中的JSON类 | JSONObject js = js.getJSONObject(String); |
| 解析出JSON类中的JSON数组 | JSONArray jsonArr = js.getJSONArray(String); |
| 解析出JSON类中的整数 | js.getInt(String); |
| 解析出JSON类中的浮点数 | js.getFloat(String); |
| 解析出JSON类中的字符串 | js.getString(String); |
| 查看JSON类的长度 | js.size(); |