創(chuàng)建多條曲線(xiàn)
下面我們將目光轉(zhuǎn)向創(chuàng)建多條曲線(xiàn),而不僅是一條曲線(xiàn),創(chuàng)建一條平滑的向各個(gè)方向彎曲的線(xiàn)。首先,來(lái)看一個(gè)錯(cuò)誤的做法,是我原先嘗試過(guò)的一種方法。從隨便一個(gè)點(diǎn)位出發(fā),經(jīng)過(guò)第一個(gè)點(diǎn)到第二個(gè)點(diǎn)再到第三個(gè)點(diǎn),經(jīng)過(guò)第四個(gè)到達(dá)第五個(gè),經(jīng)過(guò)第六個(gè)到達(dá)第七個(gè)等等繪制一條曲線(xiàn)。這里是代碼(文檔類(lèi) 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); } } } }
第一次循環(huán)在 init 方法中,建立一個(gè)數(shù)組存儲(chǔ)九個(gè)點(diǎn)。每個(gè)點(diǎn)都是一個(gè) object 擁有 x,y 屬性,它們的值都是舞臺(tái)尺寸的隨機(jī)數(shù)。當(dāng)然,在一個(gè)真正的程序中,點(diǎn)位也許不是隨機(jī)的,只是用這種方法進(jìn)行快速設(shè)置。
隨后設(shè)置線(xiàn)條樣式,將筆移動(dòng)到第一個(gè)點(diǎn)位。下一個(gè)循環(huán)從1開(kāi)始每次遞增2,所以線(xiàn)條是經(jīng)過(guò)第一點(diǎn)到達(dá)第二點(diǎn),然后從第三點(diǎn)到第四點(diǎn),再?gòu)牡谖妩c(diǎn)到第六點(diǎn),最后從第七點(diǎn)到第八點(diǎn)。至此,循環(huán)停止,因?yàn)榈诎它c(diǎn)是最后一個(gè)點(diǎn)。大家也許注意到了,這里至少要有三個(gè)點(diǎn),而且點(diǎn)的數(shù)量必需為奇數(shù)個(gè)。
程序看起來(lái)還不錯(cuò),測(cè)試一下試試。如圖4-1所示,看起來(lái)不是非常平滑,有棱有角的,這是因?yàn)榍(xiàn)之間沒(méi)有進(jìn)行協(xié)調(diào),它們之間共用了一個(gè)點(diǎn)。
圖4-1 多條曲線(xiàn),錯(cuò)誤的方法。我們可以清楚地看到曲線(xiàn)的結(jié)束和開(kāi)始的位置。
我們也許不得不去加入更多的點(diǎn)才能使解決這個(gè)問(wèn)題。這里有個(gè)策略:在每?jī)蓪?duì)點(diǎn)之間,加入一個(gè)新點(diǎn)(中間點(diǎn))放在這兩點(diǎn)的正中間。然后使用這些中間點(diǎn)作為起點(diǎn)和終點(diǎn),而把最初的那些點(diǎn)(原始點(diǎn))作為控制點(diǎn)。
圖4-2 說(shuō)明了解決辦法。在圖中,白點(diǎn)為原始點(diǎn),黑點(diǎn)為中間點(diǎn)。這里使用了三條 curveTo 方法,圖中的點(diǎn)使用了不同的顏色,這樣就能分辨出起點(diǎn)與終點(diǎn)了。(圖4-2 是 multicurvedemo.fla 文件的一張截圖,可以在 www.friendsofted.com 的 books 頁(yè)面下載)
圖4-2 帶有中間點(diǎn)的多線(xiàn)條
注意,圖4-2中第一個(gè)中間點(diǎn)和最后一個(gè)中間點(diǎn)都沒(méi)有被使用,第一個(gè)和最后一個(gè)原始點(diǎn)留作曲線(xiàn)的兩個(gè)端點(diǎn),只需在第二個(gè)點(diǎn)和倒數(shù)第二個(gè)點(diǎn)之間進(jìn)行連接。這里是前一個(gè)例子的升級(jí)版,文檔類(lèi) 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, points[i].y, xc, yc); } // curve through the last two points graphics.curveTo(points[i].x, points[i].y, points[i+1].x, points[i+1].y); } } }
請(qǐng)注意,在新代碼中, for 循環(huán)從1開(kāi)始到 points.length -2 結(jié)束,也就避開(kāi)了第一個(gè)點(diǎn)和最后一個(gè)點(diǎn)。程序要做的是,創(chuàng)建新的 x,y 點(diǎn),這個(gè)點(diǎn)是數(shù)組中后面兩個(gè)點(diǎn)位的平均值。然后從數(shù)組下一個(gè)點(diǎn)位開(kāi)始畫(huà)一條曲線(xiàn)到新的平均點(diǎn)(中間點(diǎn))。當(dāng)循環(huán)結(jié)束時(shí), i 變量指向倒數(shù)第二個(gè)元素,因此,可以穿過(guò)這里向最后一個(gè)點(diǎn)畫(huà)條曲線(xiàn)。
這時(shí),就得到一個(gè)非常平滑的圖形,見(jiàn)圖4-3。注意,這時(shí)原始點(diǎn)的數(shù)量不再受奇數(shù)個(gè)的限制。
再加一點(diǎn)小小的變化,使用同樣的技術(shù)創(chuàng)建一條封閉的曲線(xiàn)。首先,計(jì)算一個(gè)初始的中間點(diǎn),并移動(dòng)到這里。然后,進(jìn)行循環(huán),獲得每一個(gè)中間點(diǎn),最后,將最后一條曲線(xiàn)畫(huà)回初始中間點(diǎn)。圖4-4 為顯示結(jié)果
圖4-3 多條平滑曲線(xiàn)
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, points[i].y, xc, yc); } // curve through the last point, back to the first midpoint graphics.curveTo(points[i].x, points[i].y, xc1, yc1); } } }
圖4-4 多條封閉曲線(xiàn)
使用 beginFill 和 endFill 創(chuàng)建圖形 beginFill(color, alpha) 方法非常簡(jiǎn)單,沒(méi)有太多可說(shuō)的。有一點(diǎn)值得注意,同 lineStyle 一樣, alpha 的取值范圍也變?yōu)榱?0.0 到 1.0,而不是 0 到 100,這項(xiàng)也是可選的,默認(rèn)為1.0。無(wú)論何時(shí)執(zhí)行該幀的繪圖代碼 Flash 都會(huì)開(kāi)始進(jìn)行計(jì)算,無(wú)論何時(shí)遇到 endFill 指令 Flash 都會(huì)停止計(jì)算?偨Y(jié)一下,過(guò)程如下:
- moveTo
- lineStyle (如果有參數(shù)可以填入)
- beginFill
- 在一系列的 lineTo 和 curveTo 方法后,要在最初的點(diǎn)位結(jié)束
- endFill
事實(shí)上,使用前三個(gè)方法的順序不會(huì)影響到繪圖。我們不是必需要指定線(xiàn)條樣式,請(qǐng)記住如果不指定線(xiàn)條樣式就會(huì)得到一條看不見(jiàn)的線(xiàn)條,非常適合繪制填充色,當(dāng)然兩者同時(shí)繪制也不錯(cuò)。如果所繪制的線(xiàn)條沒(méi)有回到最初開(kāi)始的點(diǎn)位,一但調(diào)用了 endFill, Flash 將會(huì)自動(dòng)繪制一條封閉線(xiàn),是為了能封閉這個(gè)圖形。調(diào)用 endFill 后,無(wú)論線(xiàn)條樣式如何,都會(huì)自動(dòng)將最后一條線(xiàn)繪制完成。當(dāng)然,我們自己將線(xiàn)條封閉是個(gè)很好的習(xí)慣,這樣一來(lái),既確保了最后的能夠正確繪制,又可以讓看代碼的人知道我們究竟想畫(huà)的是什么圖形。
下面來(lái)試一下繪制填充色,可以使用前面的封閉曲線(xiàn)示例(MultiCurve3.as)來(lái)完成,這里已生成了一個(gè)封閉的圖形。只要將 beginFill 語(yǔ)句放在第一條 curveTo 前面的任何地方——如 beginFill(0xff00ff);,這樣就創(chuàng)建了亮紫色的填充——最后使用 endFill() 結(jié)束。
出處:藍(lán)色理想
責(zé)任編輯:bluehearts
上一頁(yè) 渲染技術(shù) [5] 下一頁(yè) 渲染技術(shù) [7]
◎進(jìn)入論壇RIA設(shè)計(jì)與應(yīng)用版塊參加討論
|