第五章 让方块动起来
运动是一个物理学概念,其中包含了时间与空间的因素。我们在第二章中介绍了坐标,在第三章中绘制了灰格方阵,并说明了方格位置的坐标表示法,这些都是对空间位置的描述。本章将引入时间的要素,让方格随着时间的推移而向下移动。
第一节 计时器组件
一、添加计时器组件
将App Inventor从编程视图切换到设计视图,打开组件面板的“传感器”分组,将“计时器”组件拖入预览窗口中,此时,计时器组件自动落到预览窗口下方,此处是非可视组件的陈列区。
计时器组件的功能之一是“计时”,这里的计时不同于日常生活中的计时。首先是时间的单位不同,在日常生活中,我们通常以秒、分钟或小时为单位来计时,如课间休息10分钟等,而计时器组件的计时单位是毫秒,1秒=1000毫秒;其次,日常生活中的计时通常不必重复进行,而在游戏编程中,计时是重复进行的。例如,在我们即将编写的程序中,每隔500毫秒(半秒钟)就产生一次计时事件,每当计时事件发生,组块将向下移动一行。就像时钟会不停地发出滴答声一样,计时器每隔一定时间(若干毫秒)就会发生一次的计时事件。
如图5-1所示,在组件列表中选中“计时器1”,在属性面板中将显示了计时器的默认设置,这里对计时器的三个属性稍加解释。首先,“一直计时”属性:默认为选中状态,这意味着在程序的运行过程中,计时器将重复发生计时事件,直到人为设置停止计时(设启用计时属性为假);其次,“启用计时”属性:默认为选中状态,表明程序一旦运行,计时器就开始工作,在程序运行过程中,可以随时开启或关闭该功能;最后,“计时间隔”属性:两次计时事件之间的毫秒数,默认为1000毫秒(1秒)。
二、添加计时事件处理程序
将操作区从设计视图切换到编程视图,在代码块的Screen1分组中,多出“计时器1”一项,点击“计时器1”,将打开与计时器1的代码块抽屉,如图5-2所示。其中第一个代码块“当计时器1到达计时点时”正是我们将要使用的块。点击该块,它会自动落到工作区域内。
为了了解计时器的工作方式,我们来写一段小程序。如图5-3所示。
在这段代码中,我们首次使用了代码注释,即环绕在代码周围的文字,它们不参与程序的运行,只是对代码的功能加以说明。在需要注释的代码块上点击鼠标右键,将弹出快捷菜单,选择其中的第二项,就可以为该代码块添加注释,如图5-4所示。
你能否读懂上面一段代码呢?下面我们来逐句地解释这些代码:
- 声明全局变量X:初始值为12,这个变量用于确定字母“A”在画布水平方向上的位置(x坐标,注:文字的x坐标基准点为文字中央,y坐标基准点为文字底部。);
- 对于在画布上书写的文字,可以设置其以下属性:
- 字号:设置画布1的字号属性为20;
- 画笔颜色:设置画布1的画笔颜色为红色;
- 要让画布写字,需要为“写字”功能提供以下参数:
- 书写内容:将“参数:文本”的值设置为“A”;
- 书写位置:字的位置在坐标(X,20)处,其中X是全局变量,初始值为12;
- 每写完一个字,将X的值增加25,作为下一个“A”字的x坐标:
- X = X + 25;
- 注意:上面的等式在编程语言中叫做“赋值语句”,它对应的操作是:将等号右边的值保存到等号左边的变量中,即,将当前的X值加上25之后,再保存到变量X中。具体来说,第1个“A”的x坐标是12,第2个“A”的x坐标是37(=12+25),第3个“A”的x坐标是62(=37+25)...第8个“A”的x坐标是187(=162+25),第9个“A”的x坐标是212(=187+25)。
- 一个满足条件才能执行的语句:
- 条件是X>200;按照上面计算,当写完第8个“A”之后,X值为187,加上25之后等于212,符合X>200的条件,此时执行“则”后面的语句;
- 设计时器1的启用计时为假:这一句将“计时器1”的“启用计时”属性设置为“假”,意味着让计时器1停止计时,也就是画布1将停止写“A”;
- 计时器停止计时,程序因此也停止运行。
图5-3B是图5-3A中代码在测试手机上的运行效果,图中的字母A自左向右每隔1秒钟增加一个。 通过上面的例子,我们了解到计时器的工作方式,这里介绍两个概念:事件与事件处理程序。
- 事件:由用户或系统内部触发,例如由用户触发的“按钮点击”事件,由系统触发的“计时事件”等等,事件是程序运行的启动器(或发动机)。
- 事件处理程序:当某个事件被触发时,需要执行的一段程序。例如,图5-3A中的所有代码,就被称作“计时事件处理程序”。
在人们所创建的绝大部分安卓应用中,都是由事件来推动程序运行的。
第二节 下落的方块
一、编写计时事件处理程序
这里我们用画布组件的画线功能来画一个方块,在图5-5A的代码中,有两个绘制方块的语句(紫色代码块),第一个用于绘制红色方块,第二个用于绘制灰色方块(与背景色相同),这正是产生运动效果的关键命令:当第一次计时事件发生时,在屏幕的第一行绘制一个红色方块,此时“所在行=1”,不满足>1的条件,因此,不执行第二个画线命令;此后,每发生一次计时事件,将在下一行绘制一个红色方块,这时屏幕上将出现两个红色方块,于是我们在原来红色方块的位置上绘制一个与背景色相同的灰色方块,最后屏幕上就只剩下了第二个红色方块,这就是红色方块向下移动的秘密。图5-5B中的红方方块自顶部逐行向下移动,最终停留在画布底部。
这段程序与图5-3A中的代码有几个相同之处,如设置画笔颜色、绘制图形/文字、给全局变量值增加1、在符合条件时让计时器停止工作,等等,所不同的是,方块下落的程序中多了一个绘制灰色方块的操作,我们把这个操作叫做“擦除”,而把绘制红色方块的操作叫做“画块”。给这两种操作起名字,是为了稍后引入“定义过程”的编程方法。
二、定义过程
我们先来做,然后再解释为什么要这么做。
- 在内置块中选中“过程”,就可以打开“过程”抽屉,里面有两个“定义过程”块,我们选择第一个,如图5-6所示。
图5-6 选择内置块中的“定义过程”块 - 将“我的过程”修改为“画块”,然后将图5-5A中的前两个块拖到“画块”过程中,如图5-7所示。注意,当拖动图5-5A中的第一个块时,下边的所有块都会跟着一起移动,需要把这些块放下来,将不需要的块拖回到原处。
图5-7 定义一个名为画块的过程 - 用同样方法再定义一个名字为“擦除”的过程 ,将绘制灰色方块的代码拖入到擦除的过程块中,如图5-8所示。
图5-8 定义一个名字为擦除的过程 - 这时打开“过程”抽屉,将多出两个块:调用画块及调用擦除,如图5-9所示。它们被称为自定义过程,我们可以直接使用这两个块。
图5-9 自定义的两个过程可供调用 - 选择两个自定义过程,并将它们拖到计时事件处理程序中,如图5-10所示。
图5-10 在计时事件处理程序中调用自定义过程
至此,我们完成了对代码的改造,那么,我们为什么要这么做呢?答案是:为了实现代码的复用。代码复用是编写程序的最基本原则,我们将在下一节给出更详细的解释。
第三节 逐步了解开发工具
一、代码复用
顾名思义,代码复用就是一段代码可以被多次使用。
在编写程序过程中,会在多处重复使用同一段代码,这时,我们就将这些被重复使用的代码集结成一个“过程”,并给这个“过程”起一个有意义的名字,此后,便可以在程序的任何地方,用这个名字来调用这个“过程”。
二、定义过程
“过程”是什么呢?“过程”,英文procedure,有以下解释:
- A particular course of action intended to achieve a result:为了达成某个结果而设定的具体的行动序列;
- A set sequence of steps, part of larger computer program:一系列的步骤,某个较大的计算机程序的一部分。
可以把“过程”理解为一个功能模块,我们只关心它的功能以及它的名字,并在需要的时候直接调用它,而不关心它的内部是如何实现这一功能的。就好像在建筑行业中的预制件一样。
考虑到在俄罗斯方块的游戏中,“画块”和“擦除”是两个最常用的基本操作,因此将它们定义为过程,以便在以后的程序中调用。
三、带参数的过程
我们希望提高代码的复用性,比如在“画块”的过程里,我们画的是红色方块,在接下来的程序中,我们还要画橙色、黄色等共7种颜色的块,如果为每种颜色都编写一个“画块”的过程,而这些过程里,除了颜色不同之外,其他代码完全相同,这样的七个过程,让程序显得非常臃肿,因此我们设法用一个“画块”的过程来绘制多种颜色的块,这时就需要为过程添加一个参数。
下面我们来改造前面的代码,为“画块”过程 添加一个名为“颜色”的参数。
- 为过程添加参数:如图5-11所示,点击“画块”过程左上角的蓝色标记,将弹出一个方框,里面有“输入项”及“参数x”两个块,将“参数x”拖到“输入项”中,此时“定义过程画块”的右上角出现一个橙色的附加变量“x”,这个“x”就被称为参数。将“x”改为“颜色”,看看这时“计时事件处理程序”发生了什么变化。
图5-11 为“画块”过程添加参数“颜色” - 在调用过程时,给参数赋值:如图5-12所示,“画块”过程代码块的右侧出现了一个缺口,这说明我们必须为这个缺口添加一个数据,才能使“画块”过程正常地运行起来。我们从“画块”过程中,将红色块拖入计时事件处理程序中“画块”过程的缺口处,并从“画块”过程的定义中取得参数“颜色”,添加到设置画笔颜色的语句块中。
图5-12 “颜色”是过程的参数,在调用过程时,要给这个参数一个具体的值 - 调用过程时,改变参数的值,将获得不同的执行效果。
图5-13 在调用画块过程时,给参数赋予不同的值,会改变过程的执行结果
小结
- 计时器的计时事件推动了程序的运行;
- 让方块动起来:在下一个位置绘制一个新方块,并“擦除”原有方块;
- 过程:将重复的代码定义为过程,可以在程序的任何地方来调用它;
- 过程中的参数:为过程添加参数,可以提高过程代码的复用性。