3.0Graphics.drawPath()メソッドを使うと、Graphicsクラスの基本的な描画メソッド、Graphics.moveTo()とGraphics.lineTo()およびGraphics.curveTo()を組合わせて1回の呼出しで線が描けます。パスの多い複雑なかたちを描くのに便利で、とくに同じ形状を数多くのインスタンスに描画する場合には処理が速められます。本稿ではGraphics.drawPath()メソッドの基本的な使い方をご説明します。パスの多いかたちのお題には、星形を選びました。関数として定めて、頂点の数や大きさは引数で自由に決められるようにします。Graphics.moveTo()とGraphics.lineTo()メソッドで星形を描くまずは、Graphics.moveTo()とGraphics.lineTo()メソッドを用いた関数の定義から始めましょう。次項でGraphics.drawPath()メソッドを使った関数に書替えます。3.0で始めるオブジェクト指向スクリプティング」第42回「Vector3Dクラスの3次元空間座標とインスタンスへの描画」の「Spriteインスタンスに直線を描く」をお読みください。星形を描く関数は、つぎのように定めます。引数には頂点数(山の数)に、山と谷の半径を数値で定め、描画するGraphicsオブジェクトも渡します(図001)。タイムラインに置くインスタンスでなくGraphicsオブジェクトを引数にしたのは、SpriteやMovieClip(Sprite.graphicsプロパティ)とShape(Shape.graphicsプロパティ)のいずれのインスタンスにも描けるようにするためです。中心は基準点とします。描画するGraphicsオブジェクト:Graphics):void図001■頂点数および山と谷の半径で描く星形を定める頂点数5星の描き方は、つぎのような流れです。頂点数は山の数としましたので、まず谷も含めて「頂点数×2」で360度(2πラジアン)を等分します。その角度を順に回しながら、山と谷の座標を交互にとって直線で1周結べばよいのです。直線でかたちを描くには、Graphics.moveTo()メソッドで書き初めの位置を定め、あとはGraphics.lineTo()メソッドで各点を直線で結びます。そのように定めた関数(xDrawStar())が、つぎのスクリプト001です。Math.sin(nRadians));}}スクリプト001は、前述のとおり、関数(xDrawStar())に渡された頂点数(numVertex)を谷も含めて2倍にしています(第5行目)。その頂点数で1周2πラジアン(360度)を割れば、頂点間の角度(nTheta)が導けます。実際には半周のπラジアンを分子にしたので、2倍にする前の頂点数が分母になっています(第3行目)。ひとつ気をつけるのは、星形の描き始めを時計の12時の向き、つまり-π/2ラジアン(-90度)にしたことです(スクリプト001第7行目)。角度0は時計の3時になりますので、頂点の角度から2/πラジアンを引かなければなりません。その値を予め変数(nStart)に納めています(第2および第6行目)。書き初めを山にしましたので(スクリプト001第7行目)、forループ内では谷と山を順に直線で結びます(第8〜13行目)。頂点ごとの角度を求めるとき、π/2を引いていることも確かめておきましょう(第9および第11行目)。y)座標はつぎの式で表されます。3.0で始めるオブジェクト指向スクリプティング」第16回「三角関数を使った楕円軌道のアニメーション」をお読みください。sinθフレームアクションにつぎのようなステートメントを加えれば、関数(xDrawStar())の呼出しが試せます。[ムービープレビュー]で確かめると、ステージの真ん中に置かれたShapeインスタンスに、5つの頂点をもつ青い星形が描かれます(図002)。Graphics.drawPath()メソッドで星形を描くGraphics.drawPath()メソッドには、引数としてふたつのVectorオブジェクトを渡します。第1引数はintベース型のVectorオブジェクトで、使うメソッドを順に整数で加えます。整数値は、GraphicsPathCommandクラスの定数として下表001のように定められていますので、それを用います。第2引数はNumberベース型のVectorオブジェクトで、メソッドに渡す座標値を納めます。3それでは、前掲スクリプト001のGraphics.moveTo()とGraphics.lineTo()メソッドを、Graphics.drawPath()メソッドに置換えましょう。関数(xDrawStar())の使い勝手も考えて、引数を少し変えます。初めの3つの数値はスクリプト001と同じです。Graphicsオブジェクトを渡すのは止め、替わりにふたつのVectorオブジェクトを加えました。これらは、後でGraphics.drawPath()メソッドにふたつの引数として渡すVectorオブジェクトで、中身は空です。座標Vector:Vector.<Number>):void前掲スクリプト001の関数(xDrawStar())は、引数のGraphicsオブジェクトに線を描きました。新しい関数はふたつのVectorオブジェクトに必要な値を納めるだけに止め、描画はしません。Graphics.drawPath()メソッドが、引数に渡されたふたつのVectorオブジェクトからかたちを描くからです。Graphics.drawPath()メソッドを使って書替えた関数が、つぎのスクリプト002です。Math.sin(nRadians));}}関数(xDrawStar())が行っている計算は、前掲スクリプト001と変わりません。Graphicsオブジェクトへの描画は行わず、呼出すメソッドの定数と座標値をふたつのVectorオブジェクト(commandsとcoordinates)それぞれに納めているという違いがあるだけです(スクリプト002第7〜15行目)。この関数数(xDrawStar())はつぎのようなスクリプトをフレームアクションに加えて呼出すと、前項と同じ5頂点の星形がステージ中央に描けます(前掲図002)。関数の呼出しだけでは何も描かれませんので、Graphics.drawPath()メソッドにふたつのVectorオブジェクトを渡して描画しています。Graphics.drawPath()メソッドは同じかたちをたくさん描くとき使うのがよい[ヘルプ]の「Graphics.drawPath()メソッド」には、Graphics.lineTo()やGraphics.curveTo()をGraphics.drawPath()メソッドに替えると直ちに描画が速くなるような説明があります。一般に、描画では、drawPath()を使用する方が、一連の個別のlineTo()メソッドとcurveTo()メソッドを使用するよりもレンダリングが高速です。筆者の試したかぎりでは、使うメソッドを替えただけで明らかに処理が速くなるということはなさそうでした。Graphics.drawPath()メソッドの使い方を活かすという捉え方がよさそうに思われます。ひとつは、複雑なパスを描く場合です。Graphics.drawPath()メソッドを用いれば、描画メソッドと座標をまとめて1度に呼出せるのは便利です。それだけでなく、座標値が多ければ予めVectorオブジェクトに納められていることも少なくないでしょう。そのVectorオブジェクトがNumberベース型なら、そのままGraphics.drawPath()メソッドの第2引数に渡せます。[ヘルプ]の[描画API]は、そのような場合を示しています。Graphics.moveTo()とGraphics.lineTo()メソッドを使った初めの例では、座標値がNumberベース型のVectorオフジェクトに納められていて、エレメントの座標値をひとつひとつ取出したうえでGraphics.moveTo()やGraphics.lineTo()メソッドに渡しています。coords[9]);それに対して、Graphics.drawPath()メソッドを使う例では、座標値のVectorオフジェクト(Numberベース型)はそのまま第2引数として渡されます。第1引数のコマンドVector(intベース型)を別につくらなければならないとはいえ、扱いは速められるでしょう[*1]。coords);Graphics.drawPath()メソッドの使い方がもっとも活かせるのは、同じかたちをたくさんのインスタンスに描く場合です。かたちが同じなら、引数に渡すふたつのVectorオブジェクトをつくり直さずに済み、そのまま使い回せるからです。前掲スクリプト002の関数を使って、タイムラインに数多くの星を描いてみます。前掲スクリプト002のフレームアクションにつぎのスクリプト003を加えると、タイムラインに置いた500個のShapeインスタンスに12頂点の同じ星を描きます。星の塗り色とインスタンスの位置は、ランダムに決めています(図003)。nHeight;}図003■12頂点の星形500個をランダムな色と位置で描くタイムラインのShapeインスタンスに星形を描く基本的な流れは、前項に掲げたフレームアクションと変わりません。500個のShapeをつくってタイムラインに置き、ランダムな塗りと位置に星形を描く処理はforループで行っています(第7〜16行目)。Graphics.drawPath()メソッドも、この繰返しの中で呼出します。ふたつの引数となるVectorオブジェクトをつくる関数(xDrawStar)は、forループの外で呼出されていることにご注目ください(第6行目)。描く星形は同じなので、ひとたびつくられたふたつのVectorオブジェクトは、そのまま繰返し使い回されているということです。その分、Graphics.moveTo()やGraphics.lineTo()メソッドを用いるより速く描画できます。メソッドGraphics.moveTo()とGraphics.lineTo()による描画の速さをGraphics.drawPath()と比べるGraphics.moveTo()とGraphics.lineTo()メソッドによる描画とGraphics.drawPath()メソッドの速さをサンプルスクリプトで比べてみましょう。wonderflに以下のテスト用コードをアップロードしました。100頂点の星形500個を描く3つのやり方について、処理にかかった時間をミリ秒で示します[*2]。onlineまず第3の手法が、本稿01「Graphics.moveTo()とGraphics.lineTo()メソッドで星形を描く」に当たります(スクリプト001)。つぎに第2は、前項03「Graphics.drawPath()メソッドは同じかたちをたくさん描くとき使うのがよい」と同じく、1度つくった引数のVectorオブジェクトふたつをforループの中で使い回しています(スクリプト002と003)。残る第1は、第2のスクリプト(003)でVectorオブジェクトをつぎのようにforループの中で繰返しつくった場合です。coordinates);myGraphics.endFill();結果は環境によっても試行によっても変わってきます。筆者の環境では、第1と第3とは速さに明らかな差が認められませんでした。第2はおおむね他のふたつより速く、Vectorオブジェクトの使い回しは有効と思われます。CS5以降なら、「エレメントをもったVectorインスタンスの生成」の04でご紹介した「新しいnewシンタックスを使う」方がVectorインスタンスはより速くつくれます。何度も参照するShape.graphicsプロパティは、予め変数にとっておくとよいでしょう。ランダムな色と位置を決めるために用いるMath.random()メソッドで時間が費やされないように、ふたつの500個分の数値はそれぞれ予めVectorオブジェクトに納め、計測時間には含めていません(initialize()メソッドwonderfl第38〜43行目)。Shapeインスタンスも予め500個Vectorオブジェクトとタイムラインに加えてあります(createInstances()メソッドwonderfl第44〜55行目)。