生活在内蒙古,从小时候开始就经常看草原上的赛马,也一直很喜欢《草原夜色美》这首歌。受此启发,制作了一个交互动画“草原夜赛马”,使用的工具是p5的网页编辑器。
草原夜赛马
点开下面这个网址就可以玩了
下面是制作步骤:
步骤一:上传图片素材
先准备一些素材,因为是逐帧动画,下面是一套完整奔跑动作的十二张图,并且按顺序排列好了。
在根据需要制作出反方向的图,和其他颜色的图。现在有了黑马,白马和红马的图片。
还需要一张草原夜色的背景图片。
然后就开始上传图片。先打开p5网页编辑器http://editor.p5js.org,然后新建一个文件夹。点击草稿,添加文件夹,输入文件夹的名字,点击添加。
接下来就把所有用到的照片上传到这个文件夹。先点击草稿,添加文件,选择文件夹,点击白框,选择所有照片,点击打开。等一会就上传完成了。
可以点开左边的文件管理查看到上传的所有照片。
步骤二:初始化和加载图片
将所有图片分组建立图片数组,并且将图片加载到数组中。这里声明了六个数组,分别存放三种颜色、正反两个方向的六组马的图片。通过一个预加载的方法将图片加载到数组中。如下:
1 var horses = []; //声明一个horses的数组,用来存储Horse的对象
2 var img1 = []; //声明一个存储红马正方向图片的数组 3 var img2 = []; //声明一个存储红马反方向图片的数组
4 var img3 = []; //声明一个存储白马正方向图片的数组
5 var img4 = []; //声明一个存储白马反方向图片的数组
6 var img5 = []; //声明一个存储黑马正方向图片的数组
7 var img6 = []; //声明一个存储黑马反方向图片的数组
8 var img0; //声明一个背景图片的变量
9
10 function preload() { //建立一个加载图片的方法
11 for (let i = 1; i <= 12; i++) { //加载红马正方向的所有图片
12
13 img1[i] = loadImage("horse/horse" + i + ".png"); //加载红马正方向图片14 img2[i] = loadImage("horse/verhorse" + i + ".png"); //加载红马反方向图片
15 img3[i] = loadImage("horse/whorse" + i + ".png"); //加载白马正方向图片
16 img4[i] = loadImage("horse/wverhorse" + i + ".png"); //加载白马反方向图片
17 img5[i] = loadImage("horse/bhorse" + i + ".png"); //加载黑马正方向图片
18 img6[i] = loadImage("horse/bverhorse" + i + ".png"); //加载黑马反方向图片
19 }
20 }
21 function setup() {
22 createCanvas(772, 526); //设置画布的长宽,这里以背景图片的大小为画布的大小
23 frameRate(60); //设置屏幕刷新频率
24 img0 = loadImage("horse/back.png"); //加载背景图片
25 }
26 function draw() {
27 imageMode(CENTER); //设置图片显示模式为居中
28 image(img0, width / 2, height / 2); //显示背景图片
29}
这里用一个for循环来将每一组图片全部加载到数组中。
步骤三:定义马的对象
这里每匹马都是独立的个体,所以建立一个马的对象,来描述马的特征。马的特征有:颜色、大小、移动到的位置、移动速度的大小和方向。所以我们设置一些变量和方法来描述这些特征。并且马的一些特征在时刻的发生变化,所以用一个“更新”的方法来不断更新这些变量。最后用一个“显示”的方法来把马的图片动态的显示出来。
在这里定义了一个鼠标单击的方法,每次单击鼠标时,都会生成三个马的对象,并且都有确定的颜色,初始的位置和一个随机值。设置随机值的目的是使马的速度在跑的过程中也能够发生变化,这样比赛的结果一直就是不确定的。
1 var index = 1; //声明一个数组索引的变量,并赋初值
2 var speed = 10; //声明一个速度的变量,并赋初值
3 var direction = 1; //声明一个表示马前进方向的变量,并赋初值 4 var r = -60; //声明一个马向上移动距离的变量,并赋初值
5 var scales = 90; //声明一个表示马大小的变量,并赋初值
6 var coulor = 0; //声明一个表示马颜色的变量,,并赋初值 0是红,1是白,2是黑 7
8 function mousePressed() { //定义鼠标单击的方法
9 var rand1 = random(0, 2); //声明一个变量,用来存放随机值10 var a = new Horse(mouseX, mouseY, 0, rand1); //声明一个对象,并且给它设置参数
11 horses.push(a); //将一个对象添加到对象数组中
12 var rand2 = random(0, 2); //声明一个变量,用来存放随机值
13 var b = new Horse(mouseX, mouseY, 1, rand2); //声明一个对象,并且给它设置参数
14 horses.push(b); //将一个对象添加到对象数组中
15 var rand3 = random(0, 2); //声明一个变量,用来存放随机值
16 var c = new Horse(mouseX, mouseY, 2, rand3); //声明一个对象,并且给它设置参数17 horses.push(c); //将一个对象添加到对象数组中
18 }
19
20 function Horse(x, y, coulor, rand) { //定义一个马的对象,设置它的参数,以及包含的元素和方法21 //因为每个对象都是独立的个体,不能共用变量,所以要有各自的变量
22 this.x = x; //声明对象的一个元素“横坐标”,并将实际对象的横坐标,也就是鼠标的横坐标赋值给它
23 this.y = y; //声明对象的一个元素“纵坐标”,并将实际对象的纵坐标,也就是鼠标的纵坐标赋值给它
24 this.dir = direction; //声明对象的一个元素“方向”,并将初值1赋值给它
25 this.rand = rand; //声明对象的一个元素“速度的随机值”,并将实际对象的速度随机值,赋值给它
26 this.speed = speed + this.rand; //声明对象的一个元素“速度”,并将速度的初指与实际对象的速度随机值之和,赋值给它27 this.scale = scales; //声明对象的一个元素“大小”,并将初值赋值给它
28 this.coulor = coulor; //声明对象的一个元素“颜色”,并将实际对象的颜色值,赋值给它29
30 this.display = function() { //定义对象的一个方法“显示”
31 imageMode(CENTER); //设置图片显示模式为居中
32 image(this.img, this.x, this.y, this.scale, this.scale); //显示马的图片
33 }
34
35 this.update = function() { //定义对象的一个方法“更新”
36 this.x = this.x + this.speed; //使对象有水平的移动
37 if ((this.x > 800) || (this.x < -20)) { //如果马水平移动超过了左右的边界,就要使马反向
38 this.speed = -this.speed; //使马的速度变成相反数
39 this.dir = -this.dir; //使马的速度方向反转
40 this.y = this.y + r; //使马向上移动一段距离,模拟马的远离
41 this.scale = this.scale / 1.1; //使马的大小变小,近大远小,模拟马的远离
42 if (this.speed < 0) { //如果速度是负数
43 this.speed = -(abs(this.speed) - this.rand); //马的移动速度减小一个随机值,先取速度的绝对值,再取负数
44 }
45 else { //如果速度是正数
46 this.speed = this.speed - this.rand; //马的移动速度减小一个随机值,使马每次反向时,都有速度的改变47 }
48 }
49 if (this.y < 230) { //如果马向上移动超过了地平线,也就是马跑到了天上,就要使马消失
50 this.scale = 0.1; //就使马的大小变为0.1(不能取0),相当于隐形了
51 }
52 if (this.dir == 1) { //如果方向是正方向
53 if (this.coulor == 0) this.img = img1[index]; //如果是红色,显示红马正方向图片54 else if (this.coulor == 1) this.img = img3[(index+2)%12+1]; //如果是白色,显示红马正方向图片
55 else this.img = img5[(index+4)%12+1]; //如果是黑色,显示红马正方向图片
56 }
57 else { //如果方向是反方向
58 if (this.coulor == 0) this.img = img2[(index+6)%12+1]; //如果是红色,显示红马反方向图片
59 else if (this.coulor == 1) this.img = img4[(index+8)%12+1]; //如果是白色,显示白马反方向图片
60 else this.img = img6[(index+10)%12+1];//如果是黑色,显示黑马反方向图片
61 }
62 }
63 }
64
65 function draw() {
66 ...
67 if (frameCount % 3 == 0) index++; //通过求模,设置动画帧的刷新频率,是屏幕刷新率的三分之一
68 if (index >= 12) index = 1; //每12张图,开始循环一次
69 for (var i = 0; i <= horses.length - 1; i++) { //更新和显示数组里的所有对象
70 horses[i].update(); //调用对象的方法,来更新此对象
71 horses[i].display(); //显示对象的方法,来显示此对象72 }
73 }
这里显示图片时,使每组图片的索引各不相同。例如 index、(index+2)%12+1,目的是让马的步调不一致,这样可以模拟得更加真实一些。另外让马每次跑到边上时要掉头,并且向上移动一段距离、大小缩小一些,通过近大远小来模拟马在不断远离。每单击一次有三匹马,多次单击的话,就有一群马了。
下面是全部的代码,正好100行。
1 var horses = []; //声明一个horses的数组,用来存储Horse的对象 2 var img1 = []; //声明一个存储红马正方向图片的数组
3 var img2 = []; //声明一个存储红马反方向图片的数组
4 var img3 = []; //声明一个存储白马正方向图片的数组 5 var img4 = []; //声明一个存储白马反方向图片的数组
6 var img5 = []; //声明一个存储黑马正方向图片的数组
7 var img6 = []; //声明一个存储黑马反方向图片的数组
8 var img0; //声明一个背景图片的变量
9 var index = 1; //声明一个数组索引的变量,并赋初值
10 var speed = 10; //声明一个速度的变量,并赋初值
11 var direction = 1; //声明一个表示马前进方向的变量,并赋初值 12 var r = -60; //声明一个马向上移动距离的变量,并赋初值
13 var scales = 90; //声明一个表示马大小的变量,并赋初值
14 var coulor = 0; //声明一个表示马颜色的变量,,并赋初值 0是红,1是白,2是黑 15
16 function preload() { //建立一个加载图片的方法
17 for (let i = 1; i <= 12; i++) { //加载红马正方向的所有图片
18
19 img1[i] = loadImage("horse/horse" + i + ".png"); //加载红马正方向图片
20 img2[i] = loadImage("horse/verhorse" + i + ".png"); //加载红马反方向图片
21 img3[i] = loadImage("horse/whorse" + i + ".png"); //加载白马正方向图片
22 img4[i] = loadImage("horse/wverhorse" + i + ".png"); //加载白马反方向图片
23 img5[i] = loadImage("horse/bhorse" + i + ".png"); //加载黑马正方向图片
24 img6[i] = loadImage("horse/bverhorse" + i + ".png"); //加载黑马反方向图片
25 }
26 }
27
28 function mousePressed() { //定义鼠标单击的方法
29 var rand1 = random(0, 2); //声明一个变量,用来存放随机值
30 var a = new Horse(mouseX, mouseY, 0, rand1); //声明一个对象,并且给它设置参数
31 horses.push(a); //将一个对象添加到对象数组中
32 var rand2 = random(0, 2); //声明一个变量,用来存放随机值
33 var b = new Horse(mouseX, mouseY, 1, rand2); //声明一个对象,并且给它设置参数 34 horses.push(b); //将一个对象添加到对象数组中
35 var rand3 = random(0, 2); //声明一个变量,用来存放随机值
36 var c = new Horse(mouseX, mouseY, 2, rand3); //声明一个对象,并且给它设置参数
37 horses.push(c); //将一个对象添加到对象数组中
38 }
39
40 function Horse(x, y, coulor, rand) { //定义一个马的对象,设置它的参数,以及包含的元素和方法
41 //因为每个对象都是独立的个体,不能共用变量,所以要有各自的变量
42 this.x = x; //声明对象的一个元素“横坐标”,并将实际对象的横坐标,也就是鼠标的横坐标赋值给它 43 this.y = y; //声明对象的一个元素“纵坐标”,并将实际对象的纵坐标,也就是鼠标的纵坐标赋值给它
44 this.dir = direction; //声明对象的一个元素“方向”,并将初值1赋值给它 45 this.rand = rand; //声明对象的一个元素“速度的随机值”,并将实际对象的速度随机值,赋值给它
46 this.speed = speed + this.rand; //声明对象的一个元素“速度”,并将速度的初指与实际对象的速度随机值之和,赋值给它
47 this.scale = scales; //声明对象的一个元素“大小”,并将初值赋值给它
48 this.coulor = coulor; //声明对象的一个元素“颜色”,并将实际对象的颜色值,赋值给它
49
50 this.display = function() { //定义对象的一个方法“显示”
51 imageMode(CENTER); //设置图片显示模式为居中
52 image(this.img, this.x, this.y, this.scale, this.scale); //显示马的图片
53 }
54
55 this.update = function() { //定义对象的一个方法“更新”
56 this.x = this.x + this.speed; //使对象有水平的移动
57 if ((this.x > 800) || (this.x < -20)) { //如果马水平移动超过了左右的边界,就要使马反向 58 this.speed = -this.speed; //使马的速度变成相反数
59 this.dir = -this.dir; //使马的速度方向反转
60 this.y = this.y + r; //使马向上移动一段距离,模拟马的远离
61 this.scale = this.scale / 1.1; //使马的大小变小,近大远小,模拟马的远离
62 if (this.speed < 0) { //如果速度是负数 63 this.speed = -(abs(this.speed) - this.rand); //马的移动速度减小一个随机值,先取速度的绝对值,再取负数
64 }
65 else { //如果速度是正数
66 this.speed = this.speed - this.rand; //马的移动速度减小一个随机值,使马每次反向时,都有速度的改变
67 }
68 }
69 if (this.y < 230) { //如果马向上移动超过了地平线,也就是马跑到了天上,就要使马消失 70 this.scale = 0.1; //就使马的大小变为0.1(不能取0),相当于隐形了
71 }
72 if (this.dir == 1) { //如果方向是正方向
73 if (this.coulor == 0) this.img = img1[index]; //如果是红色,显示红马正方向图片
74 else if (this.coulor == 1) this.img = img3[(index+2)%12+1]; //如果是白色,显示红马正方向图片 75 else this.img = img5[(index+4)%12+1]; //如果是黑色,显示红马正方向图片
76 }
77 else { //如果方向是反方向
78 if (this.coulor == 0) this.img = img2[(index+6)%12+1]; //如果是红色,显示红马反方向图片
79 else if (this.coulor == 1) this.img = img4[(index+8)%12+1]; //如果是白色,显示白马反方向图片
80 else this.img = img6[(index+10)%12+1];//如果是黑色,显示黑马反方向图片
81 }
82 }
83 }
84
85 function setup() {
86 createCanvas(772, 526); //设置画布的长宽,这里以背景图片的大小为画布的大小
87 frameRate(60); //设置屏幕刷新频率
88 img0 = loadImage("horse/back.png"); //加载背景图片
89 }
90
91 function draw() {
92 imageMode(CENTER); //设置图片显示模式为居中
93 image(img0, width / 2, height / 2); //显示背景图片
94 if (frameCount % 3 == 0) index++; //通过求模,设置动画帧的刷新频率,是屏幕刷新率的三分之一
95 if (index >= 12) index = 1; //每12张图,开始循环一次
96 for (var i = 0; i <= horses.length - 1; i++) { //更新和显示数组里的所有对象
97 horses[i].update(); //调用对象的方法,来更新此对象 98 horses[i].display(); //显示对象的方法,来显示此对象
99 }
100 }