加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

转 第四章 渲染技术(1)(as3.0)

发布时间:2020-12-15 06:44:14 所属栏目:百科 来源:网络整理
导读:?前一章面所看到的绘图示例中,? ? ? 只使用了一些非常简单的绘图指令,? ? ? ? ? ? ? 前面我们也几次提 到 了 这 个 神 秘 的 "drawing API" , 但 没 有 加 以 详 细 的 解 释 。 本 章 我 们 将 学习使用 ActionScript 创建视觉元素,? ? 其中包括 Action

?前一章面所看到的绘图示例中,??? 只使用了一些非常简单的绘图指令,??????? 前面我们也几次提
到 了 这 个 神 秘 的 "drawing API" , 但 没 有 加 以 详 细 的 解 释 。 本 章 我 们 将 学习使用
ActionScript 创建视觉元素,?? 其中包括 ActionScript 的颜色,?????? 绘图 API , ColorTransform
类,滤镜(filter)和 BitmapData(位图) 类。在本章的很多地方都会用到颜色,那么就先来
学习第一课吧。


Flash 中的颜色
??? 在 Flash 中,颜色就是一串特殊的数字,一个颜色值可以是 0 到 16,777,215 中的任
意数值,这就是 24 位(bit)色彩。也许大家会问,为什么有 16,216 (256 * 256 * 256)
种颜色值,因为 Flash 使用 RGB 颜色值,意味着每个颜色都可以由红(red),绿(green),
蓝(blue)三种颜色构成。这三种合成色的每一种都是一个从 0 到 255 中的数,所以,对于
每个红黄蓝都有 256 种可能的深度,结果会有约 1,678 万种颜色。
??? 这个系统之所以叫做 24 位颜色是因为要使用 8 位(0 或 1)才能表示 256 个数值。 位
????????????????????????????????????????????????????????????????????????????? 8
乘以 3 (红,黄,蓝)意味着需要 24 位才能表示 1678 万种颜色值。我们马上还要学到 32 位
色系统,它有额外的 8 位数值表示透明度(alpha)。
??? 很难想像一个值为 11,273,634 的颜色是什么样的。 因此,开发人员通常采用另一种数
值表示系统:十六进制。如果大家在 HTML 中使用过颜色,那么这对于你来说并不会陌生,
但不管怎样还是让我们来学习一下这些基础知识吧。

?

使用十六进制表示颜色值
???? 十六进制(Hexadecimal,简写 hex),以 16 为基础,每位数都是 0 到 15 中的任意一
个数,而十进制则是以 10 为基础,每位数都是 0 到 9 中的任意一个数。由于没有可以表
示 10 到 15 的数,所以要借用字母表的前六个字母, A 到 F,来表示它们。这样,每个
16 进制数都可以是 0 到 F 中的一个(在 Flash 中,??? 十六进制数不区分大小写,? 使用 A 到 F
或 a 到 f 均可)。在 HTML 中使用 16 进制数,要加上 # 作为前缀加以标识。与其它语言一
样, ActionScript 中,
???? 在????????????????? 使用 0x 作为前缀。? 比如,十六进制的 0xA 与十进制的 10 相等,
0xF 等于 15,0x10 等于 16。在十进制中,每一位都是它右边一位数的十倍,如 243 表示
为 2 的 100 倍,4 的 10 倍,3 的 1 倍。在十六进制中,每一位都是它右边一位数的十
六倍,如 0x2B3 表示为 2 的 256 倍,B(或 11)的 16 倍,3 的 1 倍。
???? 对于 24 位来说,就等于 0xFFFFFF,此外,这 6 个十六进制数可以分为三部分。第一
部分代表红色,第二部分代表绿色,最后两位表示蓝色,被象征性地记为 0xRRGGBB。
???? 记住每一个合成色都可以为 0 至 255(十六进制表示:0x00 到 0xFF)中的值。因此,
红色可以表示为 0xFF0000,? 表示纯红色,因为它的绿色为 0,? 蓝色为 0。同样,0x0000FF 表
示纯蓝色。
???? 拿 11,634 为例,将它转换为十六进制(稍后为大家介绍一种简单的方法),结果
为 0xAC05A2,可以把它分解为 red(红色) = AC,green(绿色) = 05,blue(蓝色) = A2。
可以看出 red(红色)和 blue(蓝色)的值比较高,而绿色几乎没有,我们就可以猜到这个颜
色大概为紫色,这是在十进制数中看不出来的。请注意,在 ActionScript 中,使用哪种进
制表示都可以,在一个函数中使用颜色值既可使用十进制又可使用十六进制。??? 对于 Flash 来
说,11,634 和 0xAC05A2 是一个数,只是对于可怜的人类来说后面一种表示法更易读
懂。
???? 那么如何在两种进制之间进行转换呢,? 将十六进制转换为十进制非常容易。??? 只要输出这
个十六进制数就可以了,trace 函数会自动将它转换为十进制。
trace(0xAC05A2);
将十进制转换为十六进制要用到 toString(16)函数,如:
trace((11273634).toString(16));
输出结果为 ac05a2,如果要使用这个数,不要忘记加上 0x。

透明度和 32 位色
??? 前面提到过,除了 24 位色以外,还有 32 位色,多出 8 位用于表示透明度。就像角
度制与弧度制一样(第三章内容),AS 3 在 24 和 32 位色的使用上有些混杂。AS 3 的绘图
API 很大程度上是基于 Flash MX(Flash 6) 建立的,总之,绘图 API 函数使用一个特殊的
参数来指定透明度,所以还要延用 24 位色。另外, BitmapData 类,是从 Flash 8 才加
入的,并且使用的是 32 位色彩。如果大家对某个函数使用哪种色彩体系有疑问的话,请查
看 ActionScript 参考手册。
??? 我们可以使用十六进制以 0xRRGGBB 这样的格式来表示一个色彩值。同样,32 位的颜
色也是如此,以 0xAARRGGBB 这样的格式来表示,其中 AA 表示透明度。因此,0xFFFFFFFF
就表示不透明的白色,0x00FFFFFF 表示完全透明的白色,而0x80FFFFFF 表示近似 50%透明

度的白色。

?

新的数值类型:int 和 uint
???? 在以前的 ActionScript 版本中,只有一种数值类型 Number,它可以表示正整数,负
整数或是浮点数(或 0)。我们已经习惯了这种自由的用法,但是现在多增加的两种数值类型
可以让我们的代码更加清晰。
???? 第一个新增加的数值类型是 int(整型),这个类型可以为正整数或负整数或零。如果我
们把一个浮点数值声明为 int 类型的话,小数部分会自动被去掉。比如,把 1.9 声明为
int,结果为 1。因此,当我们确定只使用整数时,就把变量声明为 int ,在循环中用于计
数的变量一般应该是 int 。下面这段代码中,i 变量永远不会得到浮点数值,这时使用 int
类型就有了意义。
for(var i:int = 0; i < 100; i++) {
???? // 在这儿做些事情!
}
???? 第二个新的类型是 uint(无符号整型),“无符号”意思是没有正负(+-)号,永远为正
数。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);
???? 0xFFFFFFFF 的值相当于十进制的 4,294,967,295,因为这个值对于 int 来说太大了,
所以结果被“反转”了过来变成了 -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,可以由二进制表示为:
22222111
将它向左移动 16 位,结果是:
222221110000000000000000
在 24 位色彩中,它表示红色,转换为二进制后为 0xFF0000,是纯红色。
下面,假设有一个绿色值(green)为 0x55(十进制 85),二进制表示为:
01010101
将它向左移动 8 位后,结果为:
000000000101010100000000
这样一来,这 8 位数完全移动到了绿色值的范围。
???? 最后,假设一个蓝色值为 0xF3(十进制 243),二进制表示为:11110011。因为它们都
处在蓝色(blue)的范围,所以不需要再去移动它。这样我们总共就拥有了三组数:
222221110000000000000000
000000000101010100000000
000000000000000011110011
??? 可以简单地将它们加起来,成为一个 24 位数,但是,还有一种更好更快的方法:使用
或(OR)运算,符号是 | 。它会将两组数的每个二进制位进行比较,如果两个之中有一个数
为 1,那么结果就为 1,如果两个数都为 0,那么结果就为 0。可以使用或(OR)运算将 red,
green,blue 的值相加起来,也可以这么说“如果这个数或这个数或这个数中有一个数等于
1,那么结果就为 1”。最终结果为:
222221110101010222220011
将这个数转换为十六进制就等于 0xFF55F3 。当然,我们无法看到这些二进制位,也不会与
这些 0 或 1 打交道,只需要学会这种写法:
var color24:Number = 0xFF << 16 | 0x55 << 8 | 0xF3;
十进制写法是:
var color24:Number = 255 << 16 | 85 << 8 | 243;
Flash 并不关心人们使用的是十进制数还是十六进制数。
??? 同样,还可以将 red,green,blue 的值全部转换为十六进制的字符串,然后将它们连
接成一条很长的字符串, 最后再把它们转换为十六进制数。但是,如果这样做的话会很麻烦,
而且使用字符串操作会非常慢。相反,使用二进制操作是 ActionScript 中最快的运算,因
为它们属于低级运算。
???? 对于 32 位数,其实道理也是一样的,加入 8 位 alpha(透明度)通道并将其向左移 24
位。例如,有一组 32 位数为 0xFFFF55F3,将 alpha 值向左移动 24 位,结果如下:
22222222222222210101010111110011
前 8 位数表示透明度,后面的 red,blue 值与前面的一样。

?

获取颜色值
???? 假如有这样一个数 0xFF55F3,要从中提取 red,blue 的值。下面请看公式,
首先是 24 位色彩:
red = color24 >> 16;
green = color24 >> 8 & 0xFF;
blue = color24 & 0xFF;
???? 一句句来看。首先,大家也许会猜到 >> 是按位右移运算符,用于将二进制位向右移动。
如果这些位向右移动得过多,那么这些数字就会消失,就没有数了。
下面从 red 开始:
222221110101010222220011
将颜色值向右移动 16 位,结果如下:
22222111,或是 0xFF(255)
对于 green,向右移动 8 位,结果如下:
2222211101010101
???? 这里已经得出了 blue 的值,但是 red 值还留在一旁。 这里就是要使用与(And)操作符
的地方,与(OR)操作符相同,都是对两组数值的比较,可以这样解释“两个数相比较,如果
两个都是 1 那么结果就为 1,如果其中有一个为 0,那么结果就为 0” 我们把它与 0xFF 进
??????????????????????????????????????????????????????????????
行比较:
2222211101010101
0000000022222111
???? 因为所有的 red 位的数字都与 0 相比较,所以它们的结果均为 0,只有当两个数都为
1 时结果才为 1,所以结果如下:
0000000001010101
???? 对于 blue 则不需要执行右移操作,只需要让它和 0xFF 执行与(AND)操作即可。对于
32 位色彩,方法也是相同的,只不过需要一点小小的改动:
alpha = color32 >> 24;
red = color32 >> 16 & 0xFF;
green = color32 >> 8 & 0xFF;
blue = color32 & 0xFF;
??? 这里,获取 alpha 的值需要向右移动 24 位。现在我们已经学到了很多 Flash 的色彩
知识,下面就要开始进行应用了。

?

绘图 API
??? 先说一下 API 是什么,它是应用程序接口(Application Programming Interface)的缩
写。总的来说,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()
??? beginGradientFill(fillType,colors,alphas,ratios,matrix)
在 Flash 8 中,又为 lineStle 和 beginGradientFill 增加了几种新的方法,同时也加入
了 beginBitmapFill 和 lineGradientStyle 方法。在 AS 3 中,也增加了几种非常有用的
方法:
■ drawCircle(x,y,radius)
■ drawEllipse(x,width,height)
■ drawRect(x,height)
■ drawRoundRect(x,height,ellipseWidth,ellipseHeight)
??? 先来预览一下这些方法,稍后再对每种方法进行详细的介绍。

绘图对象
??? 在 Flash 早期版本中,绘图 API 方法是影片剪辑(MovieClip)类中的方法,可以在影
片剪辑实例中直接调用,代码如下:
myMovieClip.lineTo(100,100);
??? 影片剪辑和 Sprite 都可以访问绘图 API,只是实现起来有些不同。目前,Sprite 影
片和影片剪辑都有一个名为 graphics 的属性,用于访问绘图 API 的方法。为了直接访问
绘图方法,我们可以这样写:
??? mySprite.graphics.lineTo(100,100);
下面在示例中看看这些方法的基本使用。

?

使用 clear 删除绘制
??? clear 是所有方法中最简单的,它可以用来删除在影片中所绘制的直线,曲线或填充色。
请注意,这个命令中对其它 graphics 绘制的图像不起作用。换句话讲,如果在编辑环境下
绘制了一个图形,再对其使用 clear() 命令,结果是无效的。
??? 在绘图中,使用 clear 方法会有些意想不到的效果。在绘图 API 中,如果绘制的影片
剪辑越多,运行速度就越慢。对于有很多绘制图形的影片来说,速度不会立刻慢下了,而是
随着每个图形所占用的绘制时间会越来越长,从而逐渐地变慢。就算新的图形完全覆盖住了
所有旧图形,旧图形的矢量信息也仍然存在并且每次都会被重绘,只有使用 clear 函数才
可以完全删除之前旧图形的矢量信息。

?

使用 lineStyle 设置线条样式
??? 使用 lineStyle(width,alpha)方法,作用是为以后使用的绘图线条设置线条样
式,该命令对于前面使用的绘图线条不会产生影响。实际上,除了清除或覆盖之外,没有方
法可以影响或改变已经绘制的线条或填充。
??? 前面列出的这些参数将来会经常使用,还有一些额外的可选参数如像素提示(pixel),
缩放模式(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 点,可以这样写:
????? lineTo(100,100);
结果将会看到一条从左上角(0,0)画到 100,100 像素位置的线(假设已经设置了线条样式)。
在绘制完最少一条线后,这条线的终点位置就会成为下一条线的起点位置。不过,我们还可
以使用 moveTo 方法为下一条线指定一个新的起点位置。
????? 可以把绘图 API 想像成一个拿着笔和纸的机器人,开始的时候,笔处在 0,0 点。当我
们告诉它向某点画一条线时,它就将笔在纸上划过,并向这个位置移动。 moveTo 方法就像
在说“OK,现在抬起笔,放到下一个点上。”虽然仅使用 moveTo 指令不会产生一个新的图
形,但是它会影响下一次绘图时的位置。通常使用 moveTo 作为第一条绘图指令,用于将绘
图 API 的“笔”移动到起点位置。现在大家已经拥有了足够的知识可以来实践一下了,让
我们创建一个简单的绘图应用程序,? 这个程序是完全依赖绘图 API 完成的。这里是文档类:
package {
? import flash.display.Sprite;
? import flash.events.MouseEvent;
? public class DrawingApp extends Sprite {
?? public function DrawingApp() {
???? init();
?? }
?? private function init():void {
???? graphics.lineStyle(1);
???? stage.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
???? stage.addEventListener(MouseEvent.MOUSE_UP,onMouseUp);
?? }
?? private function onMouseDown(event:MouseEvent):void {
???? graphics.moveTo(mouseX,mouseY);
???? stage.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
?? }
?? private function onMouseUp(event:MouseEvent):void {
???? stage.removeEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
?? }
?? private function onMouseMove(event:MouseEvent):void {
???? graphics.lineTo(mouseX,mouseY);
?? }
? }
}
????? 首先,导入 MouseEvent 类,因为这里的每件事都要用到鼠标事件。在 init 方法中,
线条样式设置为 1 像素黑色线,并增加 mouseDown 和 mouseUp 作为事件侦听器。
????? 然后是 onMouseDown 方法,每当用户按下鼠标是都会调用它,这意味着用户要开始在
当前鼠标位置画线了。? 这个函数通过使用 moveTo 方法将那支虚拟的笔放置在当前鼠标的位
置,以鼠标坐标为参数,随后为 mouseMove 添加了一个侦听器。
????? 每当用户移动鼠标时,都会调用 onMouseMove 方法,向当前鼠标的位置画一条线。
????? 最后是 onMouseUp 方法,用于删除 mouseMove 侦听器使其不再进行画线。
????? 好的,现在已经制作好了一个短小精悍的绘图程序。我们不需要再费太大的力气就可以
为这个程序加入一些简单的控制,? 让它具有完整绘图程序的功能。只需要为线条颜色(color)
和线条宽度(width)创建一些变量,再创建一些按钮什么的用来改变它们,并重新调用
lineStyle 方法使用这些新的值。对了,还可以再放一个按钮用于调用 clear 方法。把这
个留做是一个练习,希望大家有兴趣的话,能够自行完成。

使用 curveTo 绘制曲线
????? 下一个绘图函数,curveTo(x1,y2),起点和 lineTo 一样,同样是以上一次
画线的终点做为本次画线的起点,? 也可以使用 moveTo 命令指定画笔的起点,如果是第一次
画线默认的起点为 0,0。
????? 可以看到, curveTo 函数中包括两个点。第一个是控制点影响曲线的形状,另一个是
曲线的终点。? 这里使用的是名为二次方贝塞尔曲线的标准公式,该公式可以计算出两点间的
曲线,这条曲线向着控制点弯曲。请注意,这条曲线不会与控制点接触,很像是曲线被它吸
引过去的。
下面来看动作脚本,文档类 DrawingCurves.as:
package {
? import flash.display.Sprite;
? import flash.events.MouseEvent;
? public class DrawingCurves extends Sprite {
?? private var x0:Number = 100;
?? private var y0:Number = 200;
?? private var x1:Number;
?? private var y1:Number;
?? private var x2:Number = 300;
?? private var y2:Number = 200;
?? public function DrawingCurves() {
???? init();
?? }
?? private function init():void {
???? stage.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
?? }
?? private function onMouseMove(event:MouseEvent):void {
???? x1 = mouseX;
???? y1 = mouseY;
???? graphics.clear();
???? graphics.lineStyle(1);
???? graphics.moveTo(x0,y0);
???? graphics.curveTo(x1,y2);
?? }
? }
}
??? 测试这个文件,把鼠标来回移动。这里使用了两个给定的点作为起点和终点,使用鼠标
位置作为控制点。请注意,曲线不会真正到达控制点位置,而只到达与控制点一半的位置。

?

过控制点的曲线
??? 现在,如果想让曲线真正地穿过控制点,那么这就是我们工具箱中的另一个工具。使用
下面这个公式计算出控制点的实际位置,这样就可以让曲线穿过指定的点了。同样, x0,y0
?????????????????????????????????????????????????????????????????????????
为起点,以 x2,y2 为终点,x1,y1 为控制点,把将要穿过的点叫 xt,yt (目标点)。换言之,
如果让曲线穿过 xt,yt 点,那么 x1,y1 又需要如何使用呢?公式如下:
x1 = xt * 2 – (x0 + x2) / 2;
y1 = yt * 2 – (y0 + y2) / 2;
??? 只需要把目标点乘以 2,然后减去起点与终点的平均值。大家可以画张图来究竟一下它
的原理,要么就直接学会使用它。
??? 把公式放在代码中,鼠标坐标用使用 xt,yt,我们只需要改变前一个文档类中的两行,
将下面两行:
x1 = mouseX;
y1 = mouseY;
替换为
x1 = mouseX * 2 - (x0 + x2) / 2;
y1 = mouseY * 2 - (y0 + y2) / 2;
或者直接看 CurveThroughPoint.as,现成的文件。

?

创建多条曲线
下面我们将目光转向创建多条曲线, 而不仅是一条曲线,创建一条平滑的向各个方向弯曲的
线。首先,来看一个错误的做法,是我原先尝试过的一种方法。从随便一个点位出发,经过
第一个点到第二个点再到第三个点, 经过第四个到达第五个,经过第六个到达第七个等等绘
制一条曲线。这里是代码(文档类 MultiCurve1.as):
package {
? import flash.display.Sprite;
? public class MultiCurves1 extends Sprite {
?? private var numPoints:uint = 9;
?? public function MultiCurves1() {
???? init();
?? }
?? private function init():void {
???? // first set up an array of random points
???? var points:Array = new Array();
???? for (var i:int = 0; i < numPoints; i++) {
????? points[i] = new Object();
????? points[i].x = Math.random() * stage.stageHeight;
????? points[i].y = Math.random() * stage.stageHeight;
???? }
???? graphics.lineStyle(1);
???? // now move to the first point
???? graphics.moveTo(points[0].x,points[0].y);
???? // and loop through each next successive pair
???? for (i = 1; i < numPoints; i += 2) {
????? graphics.curveTo(points[i].x,points[i].y,
????? points[i + 1].x,points[i + 1].y);
???? }
?? }
? }
}
????? 第一次循环在 init 方法中,建立一个数组存储九个点。 每个点都是一个 object 拥有
x,y 属性,它们的值都是舞台尺寸的随机数。当然,在一个真正的程序中,点位也许不是随
机的,只是用这种方法进行快速设置。
????? 随后设置线条样式,将笔移动到第一个点位。下一个循环从 1 开始每次递增 2,所以线
条是经过第一点到达第二点,然后从第三点到第四点,再从第五点到第六点,最后从第七点
到第八点。至此,循环停止,因为第八点是最后一个点。大家也许注意到了,这里至少要有
三个点,而且点的数量必需为奇数个。
????? 程序看起来还不错,测试一下试试。看起来不是非常平滑,有棱有角的,
这是因为曲线之间没有进行协调,它们之间共用了一个点。
??? 我们也许不得不去加入更多的点才能使解决这个问题。 这里有个策略:在每两对点之间,
加入一个新点(中间点)放在这两点的正中间。 然后使用这些中间点作为起点和终点,? 而把最
初的那些点(原始点)作为控制点。
??? 图 4-2 说明了解决办法。在图中,白点为原始点,黑点为中间点。这里使用了三条
curveTo 方法,图中的点使用了不同的颜色,这样就能分辨出起点与终点了。(图 4-2 是
multicurvedemo.fla 文件的一张截图,可以在 www.friendsofted.com 的 books 页面下载)



图 4-2 带有中间点的多线条
注意, 4-2 中第一个中间点和最后一个中间点都没有被使用,
???????? 图?????????????????????????????????????????????? 第一个和最后一个原始点留
作曲线的两个端点,? 只需在第二个点和倒数第二个点之间进行连接。这里是前一个例子的升
级版,文档类 MultiCurve2.as:
package {
? import flash.display.Sprite;
? public class MultiCurves2 extends Sprite {
?? private var numPoints:uint = 9;
?? public function MultiCurves2() {
???? init();
?? }
?? private function init():void {
???? // first set up an array of random points
???? var points:Array = new Array();
???? for (var i:int = 0; i < numPoints; i++) {
????? points[i] = new Object();
????? points[i].x = Math.random() * stage.stageHeight;
????? points[i].y = Math.random() * stage.stageHeight;
???? }
???? graphics.lineStyle(1);
???? // now move to the first point
???? graphics.moveTo(points[0].x,points[0].y);
???? // curve through the rest,stopping at each midpoint
???? for (i = 1; i < numPoints - 2; i ++) {
?????? var xc:Number = (points[i].x + points[i + 1].x) / 2;
?????? var yc:Number = (points[i].y + points[i + 1].y) / 2;
?????? graphics.curveTo(points[i].x,xc,yc);
???? }
// curve through the last two points
graphics.curveTo(points[i].x,points[i+1].x,
points[i+1].y);
??? }
? }
}
????? 请注意,在新代码中, for 循环从 1 开始到 points.length -2 结束,也就避开了第
一个点和最后一个点。程序要做的是,创建新的 x,y 点,这个点是数组中后面两个点位的
平均值。然后从数组下一个点位开始画一条曲线到新的平均点(中间点)。当循环结束时, i
变量指向倒数第二个元素,因此,可以穿过这里向最后一个点画条曲线。
????? 这时,就得到一个非常平滑的图形,见图 4-3。注意,这时原始点的数量不再受奇数个
的限制。
????? 再加一点小小的变化,使用同样的技术创建一条封闭的曲线。首先,计算一个初始的中
间点,并移动到这里。然后,进行循环,获得每一个中间点,最后,将最后一条曲线画回初
始中间点。图 4-4 为显示结果



图 4-3 多条平滑曲线
package {
? import flash.display.Sprite;
? public class MultiCurves3 extends Sprite {
?? private var numPoints:uint = 9;
?? public function MultiCurves3() {
???? init();
?? }
?? private function init():void {
???? var points:Array = new Array();
???? for (var i:int = 0; i < numPoints; i++) {
????? points[i] = new Object();
????? points[i].x = Math.random() * stage.stageHeight;
????? points[i].y = Math.random() * stage.stageHeight;
???? }
???? // find the first midpoint and move to it
???? var xc1:Number = (points[0].x + points[numPoints - 1].x) / 2;
???? var yc1:Number = (points[0].y + points[numPoints - 1].y) / 2;
???? graphics.lineStyle(1);
???? graphics.moveTo(xc1,yc1);
???? // curve through the rest,stopping at midpoints
???? for (i = 0; i < numPoints - 1; i ++) {
?????? var xc:Number = (points[i].x + points[i + 1].x) / 2;
?????? var yc:Number = (points[i].y + points[i + 1].y) / 2;
?????? graphics.curveTo(points[i].x,yc);
???? }
???? // curve through the last point,back to the first midpoint
???? graphics.curveTo(points[i].x,xc1,yc1);
?? }
? }
}

图 4-4 多条封闭曲线 使用 beginFill 和 endFill 创建图形 beginFill(color,alpha) 方法非常简单, 没有太多可说的。有一点值得注意, lineStyle ?????????????????????????????????????????????????????????????????????? 同 一样, alpha 的取值范围也变为了 0.0 到 1.0,而不是 0 到 100,这项也是可选的,默 认为 1.0。无论何时执行该帧的绘图代码 Flash 都会开始进行计算,? 无论何时遇到 endFill 指令 Flash 都会停止计算。总结一下,过程如下: ■ moveTo ■ lineStyle (如果有参数可以填入) ■ beginFill ■ 在一系列的 lineTo 和 curveTo 方法后,要在最初的点位结束 ■ endFill ???? 事实上,使用前三个方法的顺序不会影响到绘图。我们不是必需要指定线条样式,请记 住如果不指定线条样式就会得到一条看不见的线条,? 非常适合绘制填充色, 当然两者同时绘 制也不错。如果所绘制的线条没有回到最初开始的点位,一但调用了 endFill, Flash 将 会自动绘制一条封闭线,是为了能封闭这个图形。调用 endFill 后,无论线条样式如何, 都会自动将最后一条线绘制完成。当然,我们自己将线条封闭是个很好的习惯,这样一来, 既确保了最后的能够正确绘制,又可以让看代码的人知道我们究竟想画的是什么图形。 ???? 下面来试一下绘制填充色,可以使用前面的封闭曲线示例(MultiCurve3.as)来完成,? 这 里已生成了一个封闭的图形。 只要将 beginFill 语句放在第一条 curveTo 前面的任何地方 ——如 beginFill(0xff00ff);,这样就创建了亮紫色的填充——最后使用 endFill() 结 束。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读