1.8 开始第一幅“码绘”——运用条件判断,让懵逼脸能够做出不同表情

引言——分支流程

回顾我们之前的所有示例代码,都是完全的顺序执行的流程。

在教程之初,开始介绍“过程式编程”时,我们举了一个“起床”的例子,如下:

 
 
起床
醒来;
坐起;
下床;
这即一个完全顺序执行的流程。
然而,在现实生活种,很多事情并不是这样的简单顺序流程,就算是起床的过程,其中也会存在可选的步骤,例如:
   
   
起床
醒来;
坐起;
如果有点困,就伸伸懒腰;
下床。

还有可能出现非此即彼的选择,例如:

起床

醒来;

坐起;

如果有点困,就伸伸懒腰;

否则,播放点轻音乐;

下床;

亦有可能出现多种可选分支,例如:

起床

醒来;

坐起;

如果很困,就播放点带劲的音乐;

或如果有点困,就伸伸懒腰;

下床;


还有可能出现必选其一多个选项,例如:

起床

醒来;

坐起;

如果很困,就播放点带劲的音乐;

或如果有点困,就伸伸懒腰;

否则,就播放点轻音乐;

下床;

因此,过程式编程也必须能够表达上述这些情况。

事实上,所有支持过程式编程的语言都有相应的语法,以实现上述分支情况。


仿照JS语法表达“起床”的多种分支

把上面几种情况仿照Javascript的语法写出来,即如下形态:

可选项:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
      
      
function 起床()
{
醒来;
坐起;
if(有点困)
{
伸伸懒腰;
}
下床。
}

 
 
非此即彼选择:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
        
        
function 起床()
{
醒来;
坐起;
if(有点困)
{
伸伸懒腰;
}
else
{
播放点轻音乐;
}
下床;
}

多种可选分支:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
        
        
function 起床()
{
醒来;
坐起;
if(很困)
{
就播放点带劲的音乐;
}
else if(有点困)
{
伸伸懒腰;
}
下床;
}

必选其一的多个分支:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
        
        
function 起床()
{
醒来;
坐起;
if(很困)
{
就播放点带劲的音乐;
}
else if(有点困)
{
伸伸懒腰;
}
else
{
就播放点轻音乐;
}
下床;
}

Javascript的条件判断

上述伪代码种,用于实现分支的语法就是条件判断,在JS种,其形态如下:

  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
      
      
// 1 可选项
if(条件1)
{
// 代码略
}

// 2 非此即彼
if ( 条件 1 )
{
// 代码略
}
else
{
// 代码略
}

// 3 多个可选项
if(条件 1)
{
// 代码略
}
else if(条件 2)
{
// 代码略
}
else if(条件 3)
{
// 代码略
}
// 可以有无数个 else if()

// 4 必选其一
if(条件 1)
{
// 代码略
}
else if(条件 2)
{
// 代码略
}
else if(条件 3)
{
// 代码略
}
// 可以无数个 else if()
// ......
else
{
// 代码略
}

运用条件判断,实现多种懵逼脸分支

1.实现可选的绘制内容

首先试试实现可选的绘制内容,下面代码实现了在鼠标位于画布左半时才显示一些文本。

   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
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
      
      
// 函数setup() : 准备阶段
function setup () {
// 创建画布,宽度640像素,高度480像素
// 画布的坐标系统为,左上角坐标为(0,0),
// x方向水平向右,y方向垂直向下,单位像素
createCanvas ( 640 , 480 );
}

// 函数draw():作画阶段
function draw () {
// 在鼠标位置画懵逼脸
drawConfuseFace ( mouseX , mouseY , 200 , 0.4 , 0.2 , 0.2 );
// 将可选内容放在drawConfuseFace之后,是为了不被懵逼脸覆盖掉。
// 注意,在作画时要考虑各个步骤的顺序!
// 相同的一组操作,采用不同顺序,可能导致截然不同的结果。
if(mouseX<320) // 鼠标位于画布左半边时才执行下列语句
{
fill(0); // 文本为黑色
textSize(50); // 字体尺寸50像素
text("0o0",mouseX-40,mouseY-25);// 在鼠标位置附近显示文本"0o0"
}
}

// 画懵逼脸
function drawConfuseFace (
posX , posY , // 脸部中心位置
faceSize , // 脸部尺寸
scaleMouth , // 嘴巴尺度比例,相对于脸部尺寸
scaleLEye , // 左眼尺度比例, 相对于脸部尺寸
scaleREye ) // 右眼尺度比例, 相对于脸部尺寸
{
// -------------- 1 画脸 ---------------
fill ( 255 ); // 填充白色
ellipse ( posX , posY , faceSize , faceSize ); // 圆圈
// -------------- 2 画眼睛 ---------------
// 2.1 计算眼睛相对于脸中心点的偏移量
var EyeOffsetX = 0.2 * faceSize ; // 眼睛横向偏移量为脸部尺寸的0.2倍
var EyeOffsetY = 0 * faceSize ; // 眼睛纵向偏移量为脸部尺寸的0倍

// 2.2 计算眼睛尺寸
// 左右眼尺寸
var LEyeSize = faceSize * scaleLEye ;
var REyeSize = faceSize * scaleREye ;
// 左右眼珠尺寸
var LIrisSize = LEyeSize * 0.4 ;
var RIrisSize = REyeSize * 0.4 ;
// 2.2 画出左眼
fill ( 255 ); // 填充白色
ellipse (
posX - EyeOffsetX , // 脸的中心位置向左偏移EyeOffsetX
posY + EyeOffsetY , // 脸的中心位置向下偏移EyeOffsetY
LEyeSize ,
LEyeSize );
// 2.3 画出右眼
fill ( 255 ); // 填充白色
ellipse (
posX + EyeOffsetX ,
posY + EyeOffsetY ,
REyeSize ,
REyeSize );
// 5 左眼珠
fill ( 0 ); // 填充黑色
ellipse (
posX - EyeOffsetX , // 位置与左眼一样
posY + EyeOffsetY ,
LIrisSize , // 尺寸则采用比左眼小的尺寸
LIrisSize );
// 6 右眼珠
fill ( 0 ); // 填充黑色
ellipse (
posX + EyeOffsetX ,
posY + EyeOffsetY ,
RIrisSize ,
RIrisSize );
// -------------- 3 画嘴巴 ---------------
// 3.1 计算嘴巴相对于脸部中心位置的偏移量
var MouthOffsetX = 0.0 ;
var MouthOffsetY = 0.3 * faceSize ;

// 3.2 计算嘴巴尺寸
var MouthWidth = faceSize * scaleMouth ;
var MouthHeight = MouthWidth / 2.0 ;
// 3.3 画出嘴巴
fill ( 255 ); // 填充白色
ellipse (
posX + MouthOffsetX ,
posY + MouthOffsetY ,
MouthWidth ,
MouthHeight );
// -------------- 4 画头发 ---------------
drawOneHair ( posX , posY , faceSize , - 0.3 );
drawOneHair ( posX , posY , faceSize , - 0.2 );
drawOneHair ( posX , posY , faceSize , - 0.1 );
drawOneHair ( posX , posY , faceSize , 0 );
drawOneHair ( posX , posY , faceSize , 0.1 );
drawOneHair ( posX , posY , faceSize , 0.2 );
drawOneHair ( posX , posY , faceSize , 0.3 );
}

// 绘制一根头发
function drawOneHair (
faceX , faceY , // 脸的中心位置
faceSize , // 脸的尺寸
offsetXOnFaceSize ) // 头发X坐标的的偏移量,以脸部尺寸为单位尺寸
{
// ------------- 1 计算尺寸和位置 ---------//
// 头发相对脸部中心的Y偏移量
var HairOffsetY = faceSize * 0.3 ;
// 计算X偏移量
var offsetX = offsetXOnFaceSize * faceSize ;
// 头发长度
var HairLength = faceSize * 0.4 ;

// --------------- 2 画头发 ---------------//
line (
faceX - offsetX ,
faceY - HairOffsetY ,
faceX - offsetX ,
faceY - ( HairOffsetY + HairLength ) );
}

其效果如下:



在上述代码种,用红色标记的内容“mouseX<320”是一个用于表示条件的表达式。这种表达式是对变量、常量用比较/逻辑运算符连接而成。

关于这方面内容将在本节最后进行详细介绍。这里先直接翻译为口语解释,即这个条件就是”鼠标的横坐标mouseX小于320“,也就是鼠标位于屏幕左半边。


2. 实现多个可选项分支

将代码做一定改造,实现在屏幕左边1/3或中间1/3时显示两种不同信息,代码如下:

   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
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
      
      
// 函数setup() : 准备阶段
function setup () {
// 创建画布,宽度640像素,高度480像素
// 画布的坐标系统为,左上角坐标为(0,0),
// x方向水平向右,y方向垂直向下,单位像素
createCanvas ( 600,400 );
}
       
       
// 函数draw():作画阶段
function draw () {
// 在鼠标位置画懵逼脸
drawConfuseFace ( mouseX , mouseY , 200 , 0.4 , 0.2 , 0.2 );
// 将可选内容放在drawConfuseFace之后,是为了不被懵逼脸覆盖掉。
// 注意,在作画时要考虑各个步骤的顺序!
// 相同的一组操作,采用不同顺序,可能导致截然不同的结果。
if(mouseX<200)
// 鼠标位于画布左边1/3
// 鼠标横坐标mouseX小于200
{
fill(0); // 文本为黑色
textSize(50); // 字体尺寸50像素
text("0o0",mouseX-40,mouseY-25);// 在鼠标位置附近显示文本"0o0"
}
else if(mouseX>=200 && mouseX<400)
// 鼠标位于屏幕中间1/3
// 鼠标横坐标mouseX大于等于200 并且 小于400
{
fill(0); // 文本为黑色
textSize(40); // 字体尺寸50像素
text("T_T",mouseX-25,mouseY-25);// 在鼠标位置附近显示文本"0o0"
}
}
// 画懵逼脸
function drawConfuseFace (
posX , posY , // 脸部中心位置
faceSize , // 脸部尺寸
scaleMouth , // 嘴巴尺度比例,相对于脸部尺寸
scaleLEye , // 左眼尺度比例, 相对于脸部尺寸
scaleREye ) // 右眼尺度比例, 相对于脸部尺寸
{
// -------------- 1 画脸 ---------------
fill ( 255 ); // 填充白色
ellipse ( posX , posY , faceSize , faceSize ); // 圆圈
// -------------- 2 画眼睛 ---------------
// 2.1 计算眼睛相对于脸中心点的偏移量
var EyeOffsetX = 0.2 * faceSize ; // 眼睛横向偏移量为脸部尺寸的0.2倍
var EyeOffsetY = 0 * faceSize ; // 眼睛纵向偏移量为脸部尺寸的0倍

// 2.2 计算眼睛尺寸
// 左右眼尺寸
var LEyeSize = faceSize * scaleLEye ;
var REyeSize = faceSize * scaleREye ;
// 左右眼珠尺寸
var LIrisSize = LEyeSize * 0.4 ;
var RIrisSize = REyeSize * 0.4 ;
// 2.2 画出左眼
fill ( 255 ); // 填充白色
ellipse (
posX - EyeOffsetX , // 脸的中心位置向左偏移EyeOffsetX
posY + EyeOffsetY , // 脸的中心位置向下偏移EyeOffsetY
LEyeSize ,
LEyeSize );
// 2.3 画出右眼
fill ( 255 ); // 填充白色
ellipse (
posX + EyeOffsetX ,
posY + EyeOffsetY ,
REyeSize ,
REyeSize );
// 5 左眼珠
fill ( 0 ); // 填充黑色
ellipse (
posX - EyeOffsetX , // 位置与左眼一样
posY + EyeOffsetY ,
LIrisSize , // 尺寸则采用比左眼小的尺寸
LIrisSize );
// 6 右眼珠
fill ( 0 ); // 填充黑色
ellipse (
posX + EyeOffsetX ,
posY + EyeOffsetY ,
RIrisSize ,
RIrisSize );
// -------------- 3 画嘴巴 ---------------
// 3.1 计算嘴巴相对于脸部中心位置的偏移量
var MouthOffsetX = 0.0 ;
var MouthOffsetY = 0.3 * faceSize ;

// 3.2 计算嘴巴尺寸
var MouthWidth = faceSize * scaleMouth ;
var MouthHeight = MouthWidth / 2.0 ;
// 3.3 画出嘴巴
fill ( 255 ); // 填充白色
ellipse (
posX + MouthOffsetX ,
posY + MouthOffsetY ,
MouthWidth ,
MouthHeight );
// -------------- 4 画头发 ---------------
drawOneHair ( posX , posY , faceSize , - 0.3 );
drawOneHair ( posX , posY , faceSize , - 0.2 );
drawOneHair ( posX , posY , faceSize , - 0.1 );
drawOneHair ( posX , posY , faceSize , 0 );
drawOneHair ( posX , posY , faceSize , 0.1 );
drawOneHair ( posX , posY , faceSize , 0.2 );
drawOneHair ( posX , posY , faceSize , 0.3 );
}

// 绘制一根头发
function drawOneHair (
faceX , faceY , // 脸的中心位置
faceSize , // 脸的尺寸
offsetXOnFaceSize ) // 头发X坐标的的偏移量,以脸部尺寸为单位尺寸
{
// ------------- 1 计算尺寸和位置 ---------//
// 头发相对脸部中心的Y偏移量
var HairOffsetY = faceSize * 0.3 ;
// 计算X偏移量
var offsetX = offsetXOnFaceSize * faceSize ;
// 头发长度
var HairLength = faceSize * 0.4 ;

// --------------- 2 画头发 ---------------//
line (
faceX - offsetX ,
faceY - HairOffsetY ,
faceX - offsetX ,
faceY - ( HairOffsetY + HairLength ) );
}

绘制结果如下:



在第二个可选分支种,其条件表达式采取了更复杂的形态。这里可以先直接按注释种的解释来理解,待本节最后再来详细解读其语法。


3. 画非此即彼的内容

下面实现的功能是,鼠标位于画布上半部和下半部式,画出不同的懵逼脸。由于始终要画出懵逼脸,那么这种就属于非此即彼的情况。代码如下:

   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
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
      
      
// 函数setup() : 准备阶段
function setup () {
// 创建画布,宽度640像素,高度480像素
// 画布的坐标系统为,左上角坐标为(0,0),
// x方向水平向右,y方向垂直向下,单位像素
createCanvas ( 600 , 400 );
}

// 函数draw():作画阶段
function draw () {
// 在鼠标位置画懵逼脸
if(mouseY<200)
// 位于画布上半部分
{
drawConfuseFace(mouseX,mouseY,250,0.4,0.2,0.2);
}
else
// 位于画布下半部分
{
drawConfuseFace(mouseX,mouseY,200,0.2,0.1,0.1);
}
// 将可选内容放在drawConfuseFace之后,是为了不被懵逼脸覆盖掉。
// 注意,在作画时要考虑各个步骤的顺序!
// 相同的一组操作,采用不同顺序,可能导致截然不同的结果。
if ( mouseX < 200 )
// 鼠标位于画布左边1/3
{
fill ( 0 ); // 文本为黑色
textSize ( 50 ); // 字体尺寸50像素
text ( "0o0" , mouseX - 40 , mouseY - 25 ); // 在鼠标位置附近显示文本"0o0"
}
else if ( mouseX >= 200 && mouseX < 400 )
// 鼠标位于屏幕中间1/3
{
fill ( 0 ); // 文本为黑色
textSize ( 40 ); // 字体尺寸50像素
text ( "T_T" , mouseX - 25 , mouseY - 25 ); // 在鼠标位置附近显示文本"0o0"
}
}

// 画懵逼脸
function drawConfuseFace (
posX , posY , // 脸部中心位置
faceSize , // 脸部尺寸
scaleMouth , // 嘴巴尺度比例,相对于脸部尺寸
scaleLEye , // 左眼尺度比例, 相对于脸部尺寸
scaleREye ) // 右眼尺度比例, 相对于脸部尺寸
{
// -------------- 1 画脸 ---------------
fill ( 255 ); // 填充白色
ellipse ( posX , posY , faceSize , faceSize ); // 圆圈
// -------------- 2 画眼睛 ---------------
// 2.1 计算眼睛相对于脸中心点的偏移量
var EyeOffsetX = 0.2 * faceSize ; // 眼睛横向偏移量为脸部尺寸的0.2倍
var EyeOffsetY = 0 * faceSize ; // 眼睛纵向偏移量为脸部尺寸的0倍

// 2.2 计算眼睛尺寸
// 左右眼尺寸
var LEyeSize = faceSize * scaleLEye ;
var REyeSize = faceSize * scaleREye ;
// 左右眼珠尺寸
var LIrisSize = LEyeSize * 0.4 ;
var RIrisSize = REyeSize * 0.4 ;
// 2.2 画出左眼
fill ( 255 ); // 填充白色
ellipse (
posX - EyeOffsetX , // 脸的中心位置向左偏移EyeOffsetX
posY + EyeOffsetY , // 脸的中心位置向下偏移EyeOffsetY
LEyeSize ,
LEyeSize );
// 2.3 画出右眼
fill ( 255 ); // 填充白色
ellipse (
posX + EyeOffsetX ,
posY + EyeOffsetY ,
REyeSize ,
REyeSize );
// 5 左眼珠
fill ( 0 ); // 填充黑色
ellipse (
posX - EyeOffsetX , // 位置与左眼一样
posY + EyeOffsetY ,
LIrisSize , // 尺寸则采用比左眼小的尺寸
LIrisSize );
// 6 右眼珠
fill ( 0 ); // 填充黑色
ellipse (
posX + EyeOffsetX ,
posY + EyeOffsetY ,
RIrisSize ,
RIrisSize );
// -------------- 3 画嘴巴 ---------------
// 3.1 计算嘴巴相对于脸部中心位置的偏移量
var MouthOffsetX = 0.0 ;
var MouthOffsetY = 0.3 * faceSize ;

// 3.2 计算嘴巴尺寸
var MouthWidth = faceSize * scaleMouth ;
var MouthHeight = MouthWidth / 2.0 ;
// 3.3 画出嘴巴
fill ( 255 ); // 填充白色
ellipse (
posX + MouthOffsetX ,
posY + MouthOffsetY ,
MouthWidth ,
MouthHeight );
// -------------- 4 画头发 ---------------
drawOneHair ( posX , posY , faceSize , - 0.3 );
drawOneHair ( posX , posY , faceSize , - 0.2 );
drawOneHair ( posX , posY , faceSize , - 0.1 );
drawOneHair ( posX , posY , faceSize , 0 );
drawOneHair ( posX , posY , faceSize , 0.1 );
drawOneHair ( posX , posY , faceSize , 0.2 );
drawOneHair ( posX , posY , faceSize , 0.3 );
}

// 绘制一根头发
function drawOneHair (
faceX , faceY , // 脸的中心位置
faceSize , // 脸的尺寸
offsetXOnFaceSize ) // 头发X坐标的的偏移量,以脸部尺寸为单位尺寸
{
// ------------- 1 计算尺寸和位置 ---------//
// 头发相对脸部中心的Y偏移量
var HairOffsetY = faceSize * 0.3 ;
// 计算X偏移量
var offsetX = offsetXOnFaceSize * faceSize ;
// 头发长度
var HairLength = faceSize * 0.4 ;

// --------------- 2 画头发 ---------------//
line (
faceX - offsetX ,
faceY - HairOffsetY ,
faceX - offsetX ,
faceY - ( HairOffsetY + HairLength ) );
}

其运行效果如下:



4.实现必选其一的多个分支

最后,再尝试实现多个必选其一的分支,代码如下:

   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
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
      
      
// 函数setup() : 准备阶段
function setup () {
// 创建画布,宽度640像素,高度480像素
// 画布的坐标系统为,左上角坐标为(0,0),
// x方向水平向右,y方向垂直向下,单位像素
createCanvas ( 600 , 400 );
}

// 函数draw():作画阶段
function draw () {
// 在鼠标位置画懵逼脸
if(mouseY<133)
// 位于画布上1/3部分
{
drawConfuseFace(mouseX,mouseY,250,0.4,0.2,0.2);
}
else if(mouseY>=133 && mouseY<266)
// 位于画布中间1/3部分
{
drawConfuseFace(mouseX,mouseY,300,0.0,0.4,0.4);
}
else
// 位于画布下1/3部分
{
drawConfuseFace(mouseX,mouseY,200,0.2,0.1,0.1);
}
// 将可选内容放在drawConfuseFace之后,是为了不被懵逼脸覆盖掉。
// 注意,在作画时要考虑各个步骤的顺序!
// 相同的一组操作,采用不同顺序,可能导致截然不同的结果。
if(mouseX<200)
// 鼠标位于画布左边1/3
{
fill(0); // 文本为黑色
textSize(50); // 字体尺寸50像素
text("0o0",mouseX-40,mouseY-25);// 在鼠标位置附近显示文本"0o0"
}
else if(mouseX>=200 && mouseX<400)
// 鼠标位于屏幕中间1/3
{
fill(0); // 文本为黑色
textSize(40); // 字体尺寸50像素
text("T_T",mouseX-25,mouseY-25);// 在鼠标位置附近显示文本"0o0"
}
}

// 画懵逼脸
function drawConfuseFace (
posX , posY , // 脸部中心位置
faceSize , // 脸部尺寸
scaleMouth , // 嘴巴尺度比例,相对于脸部尺寸
scaleLEye , // 左眼尺度比例, 相对于脸部尺寸
scaleREye ) // 右眼尺度比例, 相对于脸部尺寸
{
// -------------- 1 画脸 ---------------
fill ( 255 ); // 填充白色
ellipse ( posX , posY , faceSize , faceSize ); // 圆圈
// -------------- 2 画眼睛 ---------------
// 2.1 计算眼睛相对于脸中心点的偏移量
var EyeOffsetX = 0.2 * faceSize ; // 眼睛横向偏移量为脸部尺寸的0.2倍
var EyeOffsetY = 0 * faceSize ; // 眼睛纵向偏移量为脸部尺寸的0倍

// 2.2 计算眼睛尺寸
// 左右眼尺寸
var LEyeSize = faceSize * scaleLEye ;
var REyeSize = faceSize * scaleREye ;
// 左右眼珠尺寸
var LIrisSize = LEyeSize * 0.4 ;
var RIrisSize = REyeSize * 0.4 ;
// 2.2 画出左眼
fill ( 255 ); // 填充白色
ellipse (
posX - EyeOffsetX , // 脸的中心位置向左偏移EyeOffsetX
posY + EyeOffsetY , // 脸的中心位置向下偏移EyeOffsetY
LEyeSize ,
LEyeSize );
// 2.3 画出右眼
fill ( 255 ); // 填充白色
ellipse (
posX + EyeOffsetX ,
posY + EyeOffsetY ,
REyeSize ,
REyeSize );
// 5 左眼珠
fill ( 0 ); // 填充黑色
ellipse (
posX - EyeOffsetX , // 位置与左眼一样
posY + EyeOffsetY ,
LIrisSize , // 尺寸则采用比左眼小的尺寸
LIrisSize );
// 6 右眼珠
fill ( 0 ); // 填充黑色
ellipse (
posX + EyeOffsetX ,
posY + EyeOffsetY ,
RIrisSize ,
RIrisSize );
// -------------- 3 画嘴巴 ---------------
// 3.1 计算嘴巴相对于脸部中心位置的偏移量
var MouthOffsetX = 0.0 ;
var MouthOffsetY = 0.3 * faceSize ;

// 3.2 计算嘴巴尺寸
var MouthWidth = faceSize * scaleMouth ;
var MouthHeight = MouthWidth / 2.0 ;
// 3.3 画出嘴巴
fill ( 255 ); // 填充白色
ellipse (
posX + MouthOffsetX ,
posY + MouthOffsetY ,
MouthWidth ,
MouthHeight );
// -------------- 4 画头发 ---------------
drawOneHair ( posX , posY , faceSize , - 0.3 );
drawOneHair ( posX , posY , faceSize , - 0.2 );
drawOneHair ( posX , posY , faceSize , - 0.1 );
drawOneHair ( posX , posY , faceSize , 0 );
drawOneHair ( posX , posY , faceSize , 0.1 );
drawOneHair ( posX , posY , faceSize , 0.2 );
drawOneHair ( posX , posY , faceSize , 0.3 );
}

// 绘制一根头发
function drawOneHair (
faceX , faceY , // 脸的中心位置
faceSize , // 脸的尺寸
offsetXOnFaceSize ) // 头发X坐标的的偏移量,以脸部尺寸为单位尺寸
{
// ------------- 1 计算尺寸和位置 ---------//
// 头发相对脸部中心的Y偏移量
var HairOffsetY = faceSize * 0.3 ;
// 计算X偏移量
var offsetX = offsetXOnFaceSize * faceSize ;
// 头发长度
var HairLength = faceSize * 0.4 ;

// --------------- 2 画头发 ---------------//
line (
faceX - offsetX ,
faceY - HairOffsetY ,
faceX - offsetX ,
faceY - ( HairOffsetY + HairLength ) );
}

运行效果如下:



Switch-Case语句

除了if-elseif-else外,还有一种表达分支的语句,即switch-case语句,这里仅贴一个示例:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
      
      
switch ( d ) // 变量d数值为0~6,用于标记一周七天
{
// 每一个case 语句都要判断d是否和它设定的数值相等,
// 若相等,则执行对应的代码
case 6 : x = "今天是星期六" ;
break ; // 直接跳出switch语句
case 0 : x = "今天是星期日" ;
break ; // 直接跳出switch语句
default : // 所有case都不满足,则执行这里的
x = "期待周末" ;
}

其实,if-elseif-else和switch-case可以完成完全一样的功能,只是在不同时候恰当选取这两种表达方式,有助于让程序代码更容易理解。关于switch-case的详细用法请自行查阅相关资料。


条件判断的语法

在上述示例程序种,条件判断是最关键的语法特征。

为了实现条件判断,需要掌握两个语法技能:数据类型——布尔型数据、逻辑运算符

1. 数据类型——布尔型数据

在之前的教程,已经学习了常量和变量,并且了解到它们都用于包含”数值“,于是,它们可以表达我们生活中无处不在的”数量“概念。

其实,变量和常量不仅可以表示数量,还可以表示文本/真假/物体等其它有关于计量的概念。在JS种,这就需要有不同的数据类型来表示。

JS种的数据类型有几种:字符串(String)、数值(Number)、布尔(Boolean)、数组(Array)、对象(Object)、空(Null)、未定义(Undefined)。

在本节的程序中,用到了三种,即字符串/数值/布尔。数值变量已经用得很多了,而字符串和布尔型数据也是常用类型,在上述程序中也出现了多处。

字符串型数据

例如:

 
 
text("0o0",mouseX-40,mouseY-25);// 在鼠标位置附近显示文本"0o0"
这个语句中,0o0就是一个字符串常量。

表达一个字符串常量,即用双引号包含起来即可,例如:

 
 
// 字符串常量
“Hahahahahaha!"
"Hello!"
"My name is Magicbrush!"
"a=3+5;" // 注意这是字符串,而非表达式
"100" // 注意这个是字符串100,而非数值100

字符串也可以放入变量中,例如:

 
 
// 字符串变量
var HelloText = "Hello";
var FormulaText = "1+1=2";
var MyWord = "!#¥@#¥!@#!@#";
var Face = "^_^";
若采用字符串变量,前述代码中的文本显示函数也可以用变量来指定参数,例如:
   
   
// 用变量输出
var Face = "0o0";
text( Face,mouseX-40,mouseY-25);

布尔型数据

布尔型数据用于表达真假/对错/正反/阴阳/有无/好坏等相对的概念。
其用法示例如下:
   
   
// 布尔型常量
true
false

// 布尔型变量
var right = true;
var alive = false;


在条件判断语句中,就必须用布尔型数据来实现条件指定,例如:
   
   
// 在条件判断中用布尔型数据
if(true)// 用布尔常量true指定条件
{
// 一定执行
}

if(false) // 用布尔常量false指定条件
{
// 一定不执行
}

if(right) // 用布尔变量right指定条件
{
// 根据布尔型变量right的取值来决定这里是否执行
}
else if(alive) // 用布尔变量alive指定条件
{
// 若right为false,
// 根据布尔型变量alive的取值来决定这里是否执行
}
据此可见,布尔型变量的核心用途就是在分支语句中作为条件判断的量。
那么在前述代码中,却都是用逻辑表达式,这是怎么回事呢?
其实,所有的逻辑表达式的最终计算结果就是布尔型数据。
例如,在条件判断“ if(mouseY<133)”中,表达式“mouseY<133”的计算结果就是一个布尔型数据,要么为true,要么为false。
于是,这个条件判断其实也可以写为:
   
   
var OnTopOfCanvas = (mouseY<133); // 用一个布尔型数据表达“是否在画布最上方”这个信息
if(OnTopOfCanvas)
{
// ...
}

可见,布尔型变量与逻辑运算密切关联,要用好布尔型数据,必须掌握语法技能”逻辑运算符“。


2.比较和逻辑运算符

在上述示例程序中,用到了一些逻辑运算,例如“mouseY<133”、“mouseY>=133&&mouseY<266”。

其实,这种逻辑运算也源自于生活。

平时,我们经常进行一些比较和逻辑运算:


比较运算:

如果升高低于140厘米,则购买半价票。

如果重量介于20KG30KG,则属于正常范围。

如果画面太暗,就加入更亮的颜色。


在这些比较运算中,可以概括出几种:

比较运算:大于/小于/大于等于/小于等于/等于/不等于

对应的运算符为:>, <, >=, <=, ==, !=

比较运算的结果为布尔型数据,下列代码示例了它们的用法,并在注释里写出了计算结果:

  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
      
      
// >
10 > 20 ; // false
10 > 10 ; // false
10 > 1 ; // true

// <
10 < 20 ; // true
10 < 10 ; // false
10 < 1 ; // false

// >=
10 >= 20 ; // false
10 >= 10 ; // true
10 >= 1 ; // true

// <=
10 <= 20 ; // true
10 <= 10 ; // true
10 <= 1 ; // false

// ==
10 == 20 ; // false
10 == 10 ; // true
10 == 1 ; // false

// !=
10 != 20 ; // true
10 != 10 ; // false
10 != 1 ; // true

其实,JS还有两个比较运算符: ===, !==。为了避免大家懵逼,这里暂且搁置,HP还有剩余的小朋友可以自己先行学习一下:

http://www.runoob.com/js/js-comparisons.html


逻辑运算:

如果天气晴朗并且今天休假,那么就出去玩。

如果天气晴朗并且气温不低于20摄氏度,就出去玩。

如果左边涂抹了红色绿色,则右边涂抹蓝色。

如果天网络通了,就睡觉。

如果台灯和挂灯都不亮了,就去检查修理。


从这些示例可以概括出几种逻辑运算:与/或/非

对应的运算符为:&&, ||, !

下面也列出用法示例并标注结果:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
      
      
// &&: 对前后两个布尔型数值进行“与”逻辑运算,
// 若前后两个布尔值为true,则结果为true;否则结果为false
var A = ( true && true ); // A为true
var B = ( true && false ); // B为false
var C = ( false && true ); // C为false
var D = ( false && false ); // D为false

// ||: 对前后两个布尔型数值进行“或”逻辑运算,
// 二者之一为true,则结果为true;否则结果为false
var E = ( true || true ); // E为true
var F = ( true || false ); // F为true
var G = ( false || true ); // G为true
var H = ( false || false ); // H为false

// !: 对一个布尔型数值进行“非”逻辑运算,其实就是取反,
// 若为true,则结果为false;若为false,则结果为true.
var I = ! true ; // I为false
var J = ! false ; // J为true


逻辑运算可以组合着用:

 1
 2
 3
 4
 5
 6
 7
      
      
//

// 高且胖,或者非常胖,则A为true; 否则A为false;
var A = ( Tall && Fat ) || VeryFat ;

// 不是( 矮或胖),则B为true;否则B为false;
var B = ! ( Short || Fat );


逻辑运算和比较运算经常组合着用:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
      
      
// 气温大于20,且天气晴朗:
var A = ( temperature > 20 ) && Sunshine ;

// 长度大于50并且重量大于40, 或者长度小于10且重量小于5:
var B =
( length > 50 && weight > 40 ) ||
( length < 10 && weight < 5 );
// 推荐把复杂的逻辑式化为多个步骤,例如:
var GoodWeather = ( temperature > 20 ) && Sunshine ; // 温度>20且晴天
var GoodCondition = Health && Full ; // 健康且吃饱了
if ( GoodWeather && GoodCondition ) // 好天气且状态好
{
// 出去玩
}



知识点

JS数据类型: http://www.runoob.com/js/js-datatypes.html

JS比较和逻辑运算: http://www.runoob.com/js/js-comparisons.html

JS条件判断语句if-else if-else:http://www.runoob.com/js/js-if-else.html

JS分支流程语句switch-case: http://www.runoob.com/js/js-switch.html


相关资源

教程示例程序:https://github.com/magicbrush/DrawingByCodingTutorialDemos/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>