前一章面所看到的绘图示例中,
到 了 这 个 神 秘 的 "drawing API" , 但 没 有 加 以 详 细 的 解 释 。 本 章 我 们 将 学习使用
ActionScript 创建视觉元素,
类,滤镜(filter)和 BitmapData(位图) 类。在本章的很多地方都会用到颜色,那么就先来
学习第一课吧。
Flash 中的颜色
意数值,这就是 24 位(bit)色彩。也许大家会问,为什么有 16,777,216 (256 * 256 * 256)
种颜色值,因为 Flash 使用 RGB 颜色值,意味着每个颜色都可以由红(red),绿(green),
蓝(blue)三种颜色构成。这三种合成色的每一种都是一个从 0 到 255 中的数,所以,对于
每个红黄蓝都有 256 种可能的深度,结果会有约 1,678 万种颜色。
乘以 3 (红,黄,蓝)意味着需要 24 位才能表示 1678 万种颜色值。我们马上还要学到 32 位
色系统,它有额外的 8 位数值表示透明度(alpha)。
值表示系统:十六进制。如果大家在 HTML 中使用过颜色,那么这对于你来说并不会陌生,
但不管怎样还是让我们来学习一下这些基础知识吧。
使用十六进制表示颜色值
个数,而十进制则是以 10 为基础,每位数都是 0 到 9 中的任意一个数。由于没有可以表
示 10 到 15 的数,所以要借用字母表的前六个字母, A 到 F,来表示它们。这样,每个
16 进制数都可以是 0 到 F 中的一个(在 Flash 中,
或 a 到 f 均可)。在 HTML 中使用 16 进制数,要加上 # 作为前缀加以标识。与其它语言一
样, ActionScript 中,
0xF 等于 15,0x10 等于 16。在十进制中,每一位都是它右边一位数的十倍,如 243 表示
为 2 的 100 倍,4 的 10 倍,3 的 1 倍。在十六进制中,每一位都是它右边一位数的十
六倍,如 0x2B3 表示为 2 的 256 倍,B(或 11)的 16 倍,3 的 1 倍。
部分代表红色,第二部分代表绿色,最后两位表示蓝色,被象征性地记为 0xRRGGBB。
红色可以表示为 0xFF0000,
示纯蓝色。
为 0xAC05A2,可以把它分解为 red(红色) = AC,green(绿色) = 05,blue(蓝色) = A2。
可以看出 red(红色)和 blue(蓝色)的值比较高,而绿色几乎没有,我们就可以猜到这个颜
色大概为紫色,这是在十进制数中看不出来的。请注意,在 ActionScript 中,使用哪种进
制表示都可以,在一个函数中使用颜色值既可使用十进制又可使用十六进制。
说,11,273,634 和 0xAC05A2 是一个数,只是对于可怜的人类来说后面一种表示法更易读
懂。
个十六进制数就可以了,trace 函数会自动将它转换为十进制。
trace(0xAC05A2);
将十进制转换为十六进制要用到 toString(16)函数,如:
trace((11273634).toString(16));
输出结果为 ac05a2,如果要使用这个数,不要忘记加上 0x。
透明度和 32 位色
度制与弧度制一样(第三章内容),AS 3 在 24 和 32 位色的使用上有些混杂。AS 3 的绘图
API 很大程度上是基于 Flash MX(Flash 6) 建立的,总之,绘图 API 函数使用一个特殊的
参数来指定透明度,所以还要延用 24 位色。另外, BitmapData 类,是从 Flash 8 才加
入的,并且使用的是 32 位色彩。如果大家对某个函数使用哪种色彩体系有疑问的话,请查
看 ActionScript 参考手册。
色也是如此,以 0xAARRGGBB 这样的格式来表示,其中 AA 表示透明度。因此,0xFFFFFFFF
就表示不透明的白色,0x00FFFFFF 表示完全透明的白色,而0x80FFFFFF 表示近似 50%透明
度的白色。
新的数值类型:int 和 uint
整数或是浮点数(或 0)。我们已经习惯了这种自由的用法,但是现在多增加的两种数值类型
可以让我们的代码更加清晰。
们把一个浮点数值声明为 int 类型的话,小数部分会自动被去掉。比如,把 1.9 声明为
int,结果为 1。因此,当我们确定只使用整数时,就把变量声明为 int ,在循环中用于计
数的变量一般应该是 int 。下面这段代码中,i 变量永远不会得到浮点数值,这时使用 int
类型就有了意义。
for(var i:int = 0; i < 100; i++) {
}
数。32 位颜色值在 AS 3 中总是以 uint 类型存储,这是因为无符号整型比(有符号)整型
能够保留更多的数值。 Int 和 uint 都可以存储 32 位数,这个数值大于 40 亿,但是 int
有一个特殊位用于存储符号(+-), 所以只有 31 位数(大于 20 亿),这样就可以标记正数或
负数了。所以,使用 int 类型声明一个正的 32 位色彩值就显得太大了!如果用了又会怎
样?让我们来试试:
var color1:int = 0xffffffff;
trace(color1);
var color2:uint = 0xffffffff;
trace(color2);
所以结果被“反转”了过来变成了 -1!当然这不是我们所期望的结果。如果使用 uint 类
型的话,就没问题了。因此,由于色彩值永远都是正数,并有可能超出 int 的值域范围,
所以要使用 uint 来存储它们。
色彩合成
变量 red,green,blue,每个变量里面保存一个 0 到 255 之间的数。下面是这个公式:
color24 = red << 16 | green << 8 | blue;
加入透明度后,建立一个 32 位色彩值,公式如下:
color32 = alpha << 24 | red << 16 | green << 8 | blue;
这里用到了两个位操作符,大家以前可能没有接触过。位操作是对二进制(0 或 1)进行的操
作,对于 24 位色来说,如果把颜色值的每一位都列出来,就会得到一串由 24 个 0 或 1 组
成的字串。把十六进制 0xRRGGBB 分解成二进制后是这样的:RRRRRRRRGGGGGGGGBBBBBBBB
我们看到有 8 位 red,8 位 green,8 位 blue,也就是说 8 位二进制数等于 256。
制数值向左侧移动。比如,红色值(red)为 0xFF 或 255,可以由二进制表示为:
11111111
将它向左移动 16 位,结果是:
111111110000000000000000
在 24 位色彩中,它表示红色,转换为二进制后为 0xFF0000,是纯红色。
下面,假设有一个绿色值(green)为 0x55(十进制 85),二进制表示为:
01010101
将它向左移动 8 位后,结果为:
000000000101010100000000
这样一来,这 8 位数完全移动到了绿色值的范围。
处在蓝色(blue)的范围,所以不需要再去移动它。这样我们总共就拥有了三组数:
111111110000000000000000
000000000101010100000000
000000000000000011110011
或(OR)运算,符号是 | 。它会将两组数的每个二进制位进行比较,如果两个之中有一个数
为 1,那么结果就为 1,如果两个数都为 0,那么结果就为 0。可以使用或(OR)运算将 red,
green, blue 的值相加起来,也可以这么说“如果这个数或这个数或这个数中有一个数等于
1,那么结果就为 1”。最终结果为:
111111110101010111110011
将这个数转换为十六进制就等于 0xFF55F3 。当然,我们无法看到这些二进制位,也不会与
这些 0 或 1 打交道,只需要学会这种写法:
var color24:Number = 0xFF << 16 | 0x55 << 8 | 0xF3;
十进制写法是:
var color24:Number = 255 << 16 | 85 << 8 | 243;
Flash 并不关心人们使用的是十进制数还是十六进制数。
接成一条很长的字符串, 最后再把它们转换为十六进制数。但是,如果这样做的话会很麻烦,
而且使用字符串操作会非常慢。相反,使用二进制操作是 ActionScript 中最快的运算,因
为它们属于低级运算。
位。例如,有一组 32 位数为 0xFFFF55F3,将 alpha 值向左移动 24 位,结果如下:
111111111111111101010101
前 8 位数表示透明度,后面的 red, green, blue 值与前面的一样。
获取颜色值
首先是 24 位色彩:
red = color24 >> 16;
green = color24 >> 8 & 0xFF;
blue = color24 & 0xFF;
如果这些位向右移动得过多,那么这些数字就会消失,就没有数了。
下面从 red 开始:
111111110101010111110011
将颜色值向右移动 16 位,结果如下:
11111111,或是 0xFF(255)
对于 green,向右移动 8 位,结果如下:
1111111101010101
的地方,与(OR)操作符相同,都是对两组数值的比较,可以这样解释“两个数相比较,如果
两个都是 1 那么结果就为 1,如果其中有一个为 0,那么结果就为 0” 我们把它与 0xFF 进
行比较:
1111111101010101
0000000011111111
1 时结果才为 1,所以结果如下:
0000000001010101
32 位色彩,方法也是相同的,只不过需要一点小小的改动:
alpha = color32 >> 24;
red = color32 >> 16 & 0xFF;
green = color32 >> 8 & 0xFF;
blue = color32 & 0xFF;
知识,下面就要开始进行应用了。
绘图 API
写。总的来说,API 是指在程序中使用的一些属性和方法来访问某些相关的行为和属性。绘
图 API 允许我们使用 ActionScript 绘制直线,曲线,填充色,渐变填充的一些属性和方
法。在这个 API 中有些让人惊讶的方法,我们还要学习很多这方面的知识和灵活的技巧。
直至 Flash MX,已经拥有了如下这些绘图方法:
■ clear()
■ lineStyle(width, color, alpha)
■ moveTo(x, y)
■ lineTo(x, y)
■ curveTo(x1, y1, x2, y2)
■ beginFill(color, alpha)
■ endFill()
在 Flash 8 中,又为 lineStle 和 beginGradientFill 增加了几种新的方法,同时也加入
了 beginBitmapFill 和 lineGradientStyle 方法。在 AS 3 中,也增加了几种非常有用的
方法:
■ drawCircle(x, y, radius)
■ drawEllipse(x, y, width, height)
■ drawRect(x, y, width, height)
■ drawRoundRect(x, y, width, height, ellipseWidth, ellipseHeight)
绘图对象
片剪辑实例中直接调用,代码如下:
myMovieClip.lineTo(100, 100);
片和影片剪辑都有一个名为 graphics 的属性,用于访问绘图 API 的方法。为了直接访问
绘图方法,我们可以这样写:
下面在示例中看看这些方法的基本使用。
使用 clear 删除绘制
请注意,这个命令中对其它 graphics 绘制的图像不起作用。换句话讲,如果在编辑环境下
绘制了一个图形,再对其使用 clear() 命令,结果是无效的。
剪辑越多,运行速度就越慢。对于有很多绘制图形的影片来说,速度不会立刻慢下了,而是
随着每个图形所占用的绘制时间会越来越长,从而逐渐地变慢。就算新的图形完全覆盖住了
所有旧图形,旧图形的矢量信息也仍然存在并且每次都会被重绘,只有使用 clear 函数才
可以完全删除之前旧图形的矢量信息。
使用 lineStyle 设置线条样式
式,该命令对于前面使用的绘图线条不会产生影响。实际上,除了清除或覆盖之外,没有方
法可以影响或改变已经绘制的线条或填充。
缩放模式(scale mode),端点(caps),拐角类型(joints)和切断尖角(mitres)。如果大家需
要更多的设置,也许会用到它们,但是大多数情况下,只会用到下面这些参数。对于它们无
需做太多解释,只是来复习一下:
■ width:线条的宽度以像素为单位。只能使用 0 或正整数。虽然可以使用十进制浮点数,
但会被取整为最接近的正整数。如果输入的是 0 或负数, Flash 将绘制 1 像素宽的线。这
与在 Flash IDE 中在属性面板中选择“细线”的功能相同。
■ color:线条的颜色。使用十进制或十六进制的 24 位色彩值表示。
■ alpha:线条的透明度。使用 0.0 到 1.0 数字之间的数表示透明度的比例。值为 1.0 表
示完全不透明,值为 0.0 表示完全透明或不可见。注意,这与 AS 2 中使用 0 到 100 表
示法是不同的。
由于这些参数是可选的,可以只使用 lineStyle(1) 来设置一条 1 像素宽的黑色线条。 其实
第一个参数也是可选的,如果不填 widh 参数,只使用 lineStyle() 的话,那么线条就被
清除,只获得了一条不可见的线,相当于使用绘图指令时没有设置线条样式(lineStyle)。
另一个容易出错的地方是,在使用 clear 方法时,不仅清除了当前绘制的图形而且也清除
了当前使用的线条样式。如果在影片绘图时设置了一个普通的线条样式,而后又将线条清除,
那么在绘制其它图形之前还需要重新设置线条样式。
见的,调用 clear 方法同时还会将绘图指针位置归为 0,0。
使用 lineTo 和 moveTo 绘制直线
和一个终点,并在这两点之间画一条直线。另一种是使用 lineTo 指令,只需要一个终点。
那么 ActionScript 是怎样工作的呢,
进行过画线,那么起点就是 0,0 点,可以这样写:
结果将会看到一条从左上角(0,0)画到 100,100 像素位置的线(假设已经设置了线条样式)。
在绘制完最少一条线后,这条线的终点位置就会成为下一条线的起点位置。不过,我们还可
以使用 moveTo 方法为下一条线指定一个新的起点位置。
们告诉它向某点画一条线时,它就将笔在纸上划过,并向这个位置移动。 moveTo 方法就像
在说“OK,现在抬起笔,放到下一个点上。”虽然仅使用 moveTo 指令不会产生一个新的图
形,但是它会影响下一次绘图时的位置。通常使用 moveTo 作为第一条绘图指令,用于将绘
图 API 的“笔”移动到起点位置。现在大家已经拥有了足够的知识可以来实践一下了,让
我们创建一个简单的绘图应用程序,
package {
}
线条样式设置为 1 像素黑色线,并增加 mouseDown 和 mouseUp 作为事件侦听器。
当前鼠标位置画线了。
置,以鼠标坐标为参数,随后为 mouseMove 添加了一个侦听器。
为这个程序加入一些简单的控制,
和线条宽度(width)创建一些变量,再创建一些按钮什么的用来改变它们,并重新调用
lineStyle 方法使用这些新的值。对了,还可以再放一个按钮用于调用 clear 方法。把这
个留做是一个练习,希望大家有兴趣的话,能够自行完成。
使用 curveTo 绘制曲线
画线的终点做为本次画线的起点,
画线默认的起点为 0,0。
曲线的终点。
曲线,这条曲线向着控制点弯曲。请注意,这条曲线不会与控制点接触,很像是曲线被它吸
引过去的。
下面来看动作脚本,文档类 DrawingCurves.as:
package {
}
位置作为控制点。请注意,曲线不会真正到达控制点位置,而只到达与控制点一半的位置。
过控制点的曲线
下面这个公式计算出控制点的实际位置,这样就可以让曲线穿过指定的点了。同样, x0,y0
为起点,以 x2,y2 为终点,x1,y1 为控制点,把将要穿过的点叫 xt,yt (目标点)。换言之,
如果让曲线穿过 xt,yt 点,那么 x1,y1 又需要如何使用呢?公式如下:
x1 = xt * 2 – (x0 + x2) / 2;
y1 = yt * 2 – (y0 + y2) / 2;
的原理,要么就直接学会使用它。
将下面两行:
x1 = mouseX;
y1 = mouseY;
替换为
x1 = mouseX * 2 - (x0 + x2) / 2;
y1 = mouseY * 2 - (y0 + y2) / 2;
或者直接看 CurveThroughPoint.as,现成的文件。
创建多条曲线
下面我们将目光转向创建多条曲线, 而不仅是一条曲线,创建一条平滑的向各个方向弯曲的
线。首先,来看一个错误的做法,是我原先尝试过的一种方法。从随便一个点位出发,经过
第一个点到第二个点再到第三个点, 经过第四个到达第五个,经过第六个到达第七个等等绘
制一条曲线。这里是代码(文档类 MultiCurve1.as):
package {
}
x,y 属性,它们的值都是舞台尺寸的随机数。当然,在一个真正的程序中,点位也许不是随
机的,只是用这种方法进行快速设置。
条是经过第一点到达第二点,然后从第三点到第四点,再从第五点到第六点,最后从第七点
到第八点。至此,循环停止,因为第八点是最后一个点。大家也许注意到了,这里至少要有
三个点,而且点的数量必需为奇数个。
这是因为曲线之间没有进行协调,它们之间共用了一个点。
加入一个新点(中间点)放在这两点的正中间。 然后使用这些中间点作为起点和终点,
初的那些点(原始点)作为控制点。
curveTo 方法,图中的点使用了不同的颜色,这样就能分辨出起点与终点了。(图 4-2 是
multicurvedemo.fla 文件的一张截图,可以在 www.friendsofted.com 的 books 页面下载)
图 4-2 带有中间点的多线条
注意, 4-2 中第一个中间点和最后一个中间点都没有被使用,
作曲线的两个端点,
级版,文档类 MultiCurve2.as:
package {
// curve through the last two points
graphics.curveTo(points[i].x, points[i].y, points[i+1].x,
points[i+1].y);
}
一个点和最后一个点。程序要做的是,创建新的 x,y 点,这个点是数组中后面两个点位的
平均值。然后从数组下一个点位开始画一条曲线到新的平均点(中间点)。当循环结束时, i
变量指向倒数第二个元素,因此,可以穿过这里向最后一个点画条曲线。
的限制。
间点,并移动到这里。然后,进行循环,获得每一个中间点,最后,将最后一条曲线画回初
始中间点。图 4-4 为显示结果
图 4-3 多条平滑曲线
package {
}
图 4-4 多条封闭曲线
使用 beginFill 和 endFill 创建图形
beginFill(color, alpha) 方法非常简单, 没有太多可说的。有一点值得注意, lineStyle
一样, alpha 的取值范围也变为了 0.0 到 1.0,而不是 0 到 100,这项也是可选的,默
认为 1.0。无论何时执行该帧的绘图代码 Flash 都会开始进行计算,
指令 Flash 都会停止计算。总结一下,过程如下:
■ moveTo
■ lineStyle (如果有参数可以填入)
■ beginFill
■ 在一系列的 lineTo 和 curveTo 方法后,要在最初的点位结束
■ endFill
住如果不指定线条样式就会得到一条看不见的线条,
制也不错。如果所绘制的线条没有回到最初开始的点位,一但调用了 endFill, Flash 将
会自动绘制一条封闭线,是为了能封闭这个图形。调用 endFill 后,无论线条样式如何,
都会自动将最后一条线绘制完成。当然,我们自己将线条封闭是个很好的习惯,这样一来,
既确保了最后的能够正确绘制,又可以让看代码的人知道我们究竟想画的是什么图形。
里已生成了一个封闭的图形。 只要将 beginFill 语句放在第一条 curveTo 前面的任何地方
——如 beginFill(0xff00ff);,这样就创建了亮紫色的填充——最后使用 endFill() 结
束。