1.5 开始第一幅“码绘”——自定变量与函数,创一招“懵逼表情涂”
引言——想要重复绘制内容应该怎么办?
目前我们已经清晰地理解了如何用代码绘制1个懵逼脸。
现在升级一点难度,考虑一个问题:
如果要在屏幕上不同位置画N个懵逼脸,怎么办?
若采用之前一样的方法,我们可以在绘制完一个脸后,用重复的代码(不同参数)绘制另一个脸,比如:
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 |
|
这样就能绘制两个脸:
但是......我想画20个脸,咋办?????
不嫌累的话可以试试写20遍重复代码......,希望不要勾起被老师罚抄课文的苦难记忆......
可见,这个办法的局限也是相当明显的。
用自定义函数实现功能复用
为了解决这个麻烦,我们需要获得一项新技能:自定义函数。
回顾一下1.1节中讲到的“函数”,或者说“招数/方法/行为/职能/功能”,只要有了某个函数定义,也就是概括了某种做事的流程,然后在我们想要的地方便可以“调用”它,或者说是“施放/执行/行使/发招”。例如,我们可以设想已经定义了一个“DrawConfuseFace”的函数,然后,在draw()函数中就可以直接调用这个函数两次,实现画两个懵逼脸。也就是,我们现在期望的draw()函数写法:
这当然是可行的!而且实现后效果如下:// 函数draw():作画阶段function draw() {// 在(200,140)位置画第一个脸drawConfuseFace(200,140);// 在(320,280)位置画第二个脸drawConfuseFace(320,280);}
为了实现这个drawConfuseFace函数,我们要依次搞清楚3项技能: 1.自定义函数;2.自定义变量;3.函数参数
自定义函数
在1.1节的讲解中,已经了解到“函数定义”的基本办法,也就是现有代码中函数setup()和draw()的写法即函数定义。
那么,我们仿照draw()函数的写法,在其后新写一个函数,并在draw()函数中直接调用它20遍!希望能画出20个懵逼脸。
代码如下:
然而,却只能画出来1个脸:// 函数setup() : 准备阶段function setup() {// 创建画布,宽度640像素,高度480像素// 画布的坐标系统为,左上角坐标为(0,0),// x方向水平向右,y方向垂直向下,单位像素createCanvas(640,480);}// 函数draw():作画阶段function draw() {// 调用20遍,希望能画20个脸drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();drawConfuseFace();}// 自定函数:画懵逼脸function drawConfuseFace() {fill(255);// 填充白色// 1 画脸ellipse(320,240,200,200);// 圆圈// 2 左眼ellipse(280,240,50,50);// 另一个圆圈// 3 右眼ellipse(360,240,50,50);// 4 嘴巴ellipse(320,300,80,40);fill(0);// 填充黑色// 5 左眼珠ellipse(280,240,20,20);// 6 右眼珠ellipse(360,240,20,20);// 7 头发:从左到右画一排竖线line(260,180,260,100);line(280,180,280,100);line(300,180,300,100);line(320,180,320,100);line(340,180,340,100);line(360,180,360,100);line(380,180,380,100);}
这是为啥?原来,我们虽然施放了20次drawConfuseFace(),但由于每一次施放中,drawConfuseFace()函数的执行过程用到的参数完全一样,因此,上述代码相当于在相同位置重复画了20次,每一次绘制都覆盖掉前一次绘制的结果,那么最终也只能看到1个脸。这并非我们想要的函数形态,我们更希望drawConfuseFace()能够在不同位置画脸。于是,drawConfuseFace()函数需要进行改造,让它能够在释放时输入参数,并且根据参数的具体数值来发挥不同的效果,例如,我们希望施放该函数时可以用以下形态:drawConfuseFace(100,200); //在(100,200)位置画懵逼脸drawConfuseFace(300,50); // 在(300,50)位置画懵逼脸......为了实现它,还需要对变量的认识更进一步,即学会“自定义变量”。
自定义变量
在之前实现的用鼠标控制位置的代码中,我们用到了两个变量mouseX和mouseY,它们是p5.js提供的可以在任意时刻任意位置直接访问的变量。为了更加灵活地指定位置,我们可以用自定义变量。
下列代码示例了在程序中自定义变量:
var A,a; // 定义两个变量 A和a, 特别注意,大小写不同的名称对应不同变量!var B = 1; // 定义变量B,赋值1var Haha = 100; // 定义变量Haha, 赋值100;var Jam = B; // 定义变量Jam, 用变量B的值为其赋值;
在定义了上述变量后,便可以在需要的时候使用它们,就如同使用变量mouseX和mouseY一般,例如:
此外,在变量定义中,用到了赋值符"=",要注意,它的作用有点像是“等于”,但其实应该理解为“赋值”,其目的是将右边的表达式的计算结果赋予左边的变量,下面列出一些用法示例:ellipse(B,Haha,100,100); // 在位置(B,Haha)绘制长宽为100的圆形line(Jam,Haha,Haha,B); // 从(Jam,Haha)到(Haha,B)绘制一条线段
掌握了自定义变量,我们对原来的代码进行改造。原始代码为:
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 |
|
用自定义变量对其进行改造:
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 |
|
如此改造后,程序运行的结果并未变化,也就是绘制一个跟随鼠标运动的懵逼脸。
但这样改造仍然有两个好处,一方面是具备了更佳的可读性,因为我们定义的变量名称centerX和centerY本身就使用了具有明确含义的词汇center,其名称就说明了它们是绘制的懵逼脸的“中心”位置;另一方面,代码具有了更好的可扩展性:这两个变量的数值可以在后续过程中任意时刻发生变化,而不会像mouseX和mouseY那样始终是鼠标位置;并且,重点是,这种改造便于我们将这一段代码改造为带参数的函数。(●ˇ∀ˇ●)
函数参数
如此一来,我们便可以在draw()函数中以带参数的形态调用drawConfuseFace()了:function drawConfuseFace(posX, posY)// 定义了两个形式参数posX,posY,它们也是函数中的两个变量// 函数执行过程中所有绘图语句都基于变量posX和posY来指定位置{fill(255);// 填充白色// 1 画脸ellipse(posX,posY,200,200);// 圆圈// 2 左眼ellipse(posX-40,posY,50,50);// 另一个圆圈// 3 右眼ellipse(posX+40,posY,50,50);// 4 嘴巴ellipse(posX,posY+60,80,40);fill(0);// 填充黑色// 5 左眼珠ellipse(posX-40,posY,20,20);// 6 右眼珠ellipse(posX+40,posY,20,20);// 7 头发:从左到右画一排竖线line(posX-60,posY-60,posX-60,posY-140);line(posX-40,posY-60,posX-40,posY-140);line(posX-20,posY-60,posX-20,posY-140);line(posX ,posY-60,posX ,posY-140);line(posX+20,posY-60,posX+20,posY-140);line(posX+40,posY-60,posX+40,posY-140);line(posX+60,posY-60,posX+60,posY-140);}
// 函数draw():作画阶段function draw() {// 在(200,140)位置画第一个脸drawConfuseFace(200,140);// 在(320,280)位置画第二个脸drawConfuseFace(320,280);}
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 |
|
补充:变量的作用域和生命周期
为了用好变量,还需要了理解它的作用域和生命周期。
一个变量的作用域就是指在程序代码的哪些部分能够访问到这个变量,从下图中可以看出作用域的几种典型情况:
执行效果如下:
有关作用域,可以查看这里的解释:http://www.runoob.com/js/js-scope.html
知识点
函数:http://www.runoob.com/js/js-functions.html
作用域:http://www.runoob.com/js/js-scope.html
相关资源
教程示例程序:https://github.com/magicbrush/DrawingByCodingTutorialDemos/