二十世纪 70 年代,有一种叫做 Logo 的编程语言,它非常简单但功能强大,当时被一些研究人员所使用。后来开发人员在这种编程语言中加入了现在被称为“Turtle Graphics(海龟绘图法)”的技术,并在屏幕上显示一个“海龟”图案 ,通过诸如 Move Forward (向前移动), Turn Right(向右转), Turn Left (向左转)等命令移动龟标。通过控制龟标的移动,编程人员可以绘制有趣的图形。这一新技术的引入,使得 Logo 变得更加简单易用,并对各个年龄的编程爱好者产生了吸引力,因此在 80 年代广为流行。
Small Basic 语言中也引入了 Turtle (龟标)对象,编程人员可以通过Small Basic 自带的很多命令调用这个对象。在本章中,我们将使用龟标绘制图形。
程序初始化时,我们需要在屏幕上显示龟标。代码如下:
Turtle.Show()
程序运行后,将显示一个白色窗口,这个窗口与我们在前面章节中看到的窗口唯一的不同就是窗口的中央多了一个龟标。这个龟标将会按照我们的指令绘制指定的图案。
图 37 – 窗口中央显示有龟标
Move(移动)是这只“海龟”可以听懂的命令之一。这个运算会读取用户输入的一个数值。该数值即是龟标要移动的距离。例如,在下面的代码中,我们指定龟标移动 100 象素。
Turtle.Move(100)
程序运行后,可以看到龟标缓慢地向上移动 100 象素,并在它经过的地方画下一条线。当龟标移动到指定位置后,将画出以下图案。
图 38 – 移动 100 象素
正方形由四条边组成,两条为水平方向,两条为垂直方向。因此,要绘制一个正方形,我们需要用龟标画一条线,右转,再画一条线,然后重复同样的动作直至画完四条边。我们可以将这些动作转换成以下代码。
Turtle.Move(100)
Turtle.TurnRight()
Turtle.Move(100)
Turtle.TurnRight()
Turtle.Move(100)
Turtle.TurnRight()
Turtle.Move(100)
Turtle.TurnRight()
程序运行后,龟标将会逐条边绘制出一个正方形,其结果如下图。
图 39 – 龟标绘制出一个正方形
如果用心观察,就会发现我们在一遍又一遍地使用同样的指令,确切地说是重复使用了四次。我们在前面介绍过,可以使用循环来实现像这样的重复命令。拿上面的这个程序来举例,如果用 For..EndFor 循环来实现,程序就会变得简单很多。
For i = 1 To 4
Turtle.Move(100)
Turtle.TurnRight()
EndFor
这个示例中龟标所在的 GraphicsWindow (图画窗口)和我们在前一章中所看到的相同。也就是说,前面所学的运算都可以在这里使用。例如,以下这段代码可以绘制一个每条边颜色不同的方形。
For i = 1 To 4
GraphicsWindow.PenColor = GraphicsWindow.GetRandomColor()
Turtle.Move(100)
Turtle.TurnRight()
EndFor
图 40 – 修改颜色
龟标除了可以执行 TurnRight (向左转)和 TurnLeft (向右转)运算以外,还可以执行 Turn (转向)运算。这个运算会按照用户指定的数值将龟标旋转相应的角度。使用这个运算,我们就可以绘制任意形状的多边形。以下程序可以绘制一个六边形。
For i = 1 To 6
Turtle.Move(100)
Turtle.Turn(60)
EndFor
运行一下这个程序,看看它的输出是否真的是一个六边形。因为边与边的夹角是 60 度,我们就使用 Turn(60)。对于这样每个边都等长的多边形,边与边之间的夹角即是 360 除以多边形的边数。我们可以利用这个原理并通过使用变量,实现一个可以绘制任意边数的多边形的通用程序。
sides = 12
length = 400 / sides
angle = 360 / sides
For i = 1 To sides
Turtle.Move(length)
Turtle.Turn(angle)
EndFor
使用这个程序,我们可以通过改变 sides (边数)变量绘制任意多边形。如果将变量设置为 4,将会绘制出和我们开始编写的那个程序一样的四边形。如果将变量设置为一个很大的数值,比如 50,将会绘制出的一个接近圆形的图案。
图 41 – 绘制一个十二边形
使用以上技术,利用龟标绘制多个圆形,并在绘制每个圆形之后移动一段距离,我们将会得到一个有趣的输出结果。
sides = 50
length = 400 / sides
angle = 360 / sides
Turtle.Speed = 9
For j = 1 To 20
For i = 1 To sides
Turtle.Move(length)
Turtle.Turn(angle)
EndFor
Turtle.Turn(18)
EndFor
以上程序中有两个嵌套的 For..EndFor 循环,内层的循环 (i = 1 to sides) 和多边形程序相似,负责输出圆形。外层的循环 (j = 1 to 20) 负责在每次绘制圆形后移动龟标。在程序中,我们指定使用龟标绘制 20 个圆形。程序的运行结果是一个如下所示的有趣图案。
图 42 – 在圆形中移动
可以使用 PenUp(停笔)运算让龟标停止移动。这样,就可以将龟标移动到屏幕的任意位置,而不留下痕迹。如果想重新使用龟标绘制图案,可以调用 PenDown(落笔)。通过使用这两个命令,可以绘制出像虚线这样的有趣效果。以下程序就使用这个方法绘制出一个以虚线组成的多边形。
sides = 6
length = 400 / sides
angle = 360 / sides
For i = 1 To sides
For j = 1 To 6
Turtle.Move(length / 12)
Turtle.PenUp()
Turtle.Move(length / 12)
Turtle.PenDown()
EndFor
Turtle.Turn(angle)
EndFor
和上面的程序一样,这个程序也有两个嵌套的循环,内部的循环绘制虚线,外部的循环根据指定数值绘制多边形的边。在这个的示例中,我们指定 sides(边数)变量为 6,得到一个由虚线组成的六边形,如下所示。
图 43 – 使用 PenUp 和 PenDown
寄存器的功能是存储二进制代码,它是由具有存储功能的触发器组合起来构成的。一个触发器可以存储1位二进制代码,故存放n位二进制代码的寄存器,需用n个触发器来构成。
事件就像被触发的信号,例如,为了应对类似移动或点击鼠标的用户操作。某种程度上说,事件同操作是相对的。对于操作,您作为一个程序员调用操作让计算机做一些事情;然后对于事件,计算机通知您一些有意思的事情发生了。
在编程时我们经常遇到需要重复执行相同一组步骤的情况。这种情况下,多次重写相同的语句是不合理的。这时我们需要借助子例程。
在这一章节中,我们将运用前面学到的知识来做一些有趣的事。
Small Basic 还有一组强大的图形功能。