2009年7月アーカイブ

(section03-04 Vectorクラスで作る配列から抜粋)

 ベクターはエレメントのデータ型だけでなく、配列の長さすなわちエレメントの個数も固定できます。エレメントの個数を固定するにはベクターを作る際に第1引数で配列の長さ、第2引数でtrueを指定します。長さを決めてベクターを作ると各エレメントにはベース型に合わせた初期値が入ります。
 次の例はベース型がintで長さを5に固定したベクターvlistを作っています。作られたvlistを確認するとint型の初期値の0が5個入ったベクターが作られています。

[:script:]長さを決めたベクターを作る
var vlist:Vector.<int>=new Vector.<int>(5,true);
trace(vlist);//出力:0,0,0,0,0
 長さが決まっているベクターに値を入れるには[]演算子を使ってエレメントにアクセスします。push()やshift()で値を追加すると長さが変化するので使えません。pop()、unshift()、splice()での値の抜き出しも長さを変更するので利用できません。

[:script:]長さが決まっているベクターに値を設定する
var vlist:Vector.<int>=new Vector.<int>(5,true);
//エレメントの値を設定する
vlist[0]=45;
vlist[1]=21;
vlist[2]=74;
trace(vlist);//出力:45,21,74,0,0
 ベクターの長さを固定するかどうかはfixedプロパティで設定できます。そこで長さを固定せずに値を追加し、後からfixedをtrueにして長さを固定することができます。

[:script:]ベクターに値を追加した後で長さを固定する
//ベース型がStringのベクターcolorsを作る
var colors:Vector.<String>=new Vector.<String>();
//ベクターに値を追加する
colors.push("green");
colors.push("red","blue");
//ベクターの長さを固定する
colors.fixed=true;
(section03-04 Vectorクラスで作る配列から抜粋)

 Arrayクラスの配列にはいろんなデータ型の値を混ぜて入れることができる手軽さがありますが、配列に入れる値は数値だけに限りたいというようにデータ型を限定したい場合があります。
 Vectorクラスで作る配列は値のデータ型を限定できるという点が大きな違いです。Vectorクラスで作る配列をベクターと呼び、ベクターのエレメント(値)のデータ型を「ベース型」と呼びます。
 次のスクリプトではベース型がStringのベクターcolorsを作っています。つまり、colorsにはString型の値しか入れることができません。変数colorsを宣言する際にはVector型を指定すると同時にベース型をVector.<ベース型>の書式で指定します。ベクターに値を入れるにはpop()やshift()を使って値を追加していきます。

[:script:]ベース型がStringのベクターを作り値を入れる
//ベース型がStringのベクターcolorsを作る
var colors:Vector.<String>=new Vector.<String>();
//ベクターcolorsに値を追加する
colors.push("green","red","blue");
trace(colors);//出力:green,red,blue
 ベクターにベース型とは異なるデータ型の値を追加するとエラーになるか、強制的にベース型で指定したデータ型に変換されます。たとえば、ベクターcolorsに数値を追加すると値をストリングに強制的に変換されて入ります。数値を入れてもストリングになっているので、取り出した値に+演算子で数値を足すとストリングの連結になり、数値演算をしようとするとエラーになります。

[:script:]ベース型とは異なるデータ型の値を追加した場合
//ベース型がStringのベクターcolorsを作る
var colors:Vector.<String>=new Vector.<String>();
//エレメントに数値を追加する
colors.push(100,200,300);
trace(colors[0]+99);//10099 -- 文字列として連結される
trace(colors[1]*2);//数値演算はエラーになる

旧AS3入門ノートは472ページで3800円でしたが、新AS3入門ノートは496ページで3500円です!どうして、ページ数が増えたのに安くなったんでしょう?!

その答は、楽しいActionScriptのためです。(T_T)泣ける。

(section09-03 Flash Player 10の新しいGraphicsメソッドから抜粋)

 drawPath()は描画コマンドと座標をセットにしてパスを描くメソッドですが、実際にはさらに線のスタイル、塗りのスタイルを組み合わせることで図形の描画が完成します。  drawGraphicsData()は、これらの描画に必要な値をgraphicsDataベクターにまとめ、drawGraphicsData(graphicsData)のように実行することで図形の描画を完成させることができます。
 次のHexagonクラスではdrawGraphicsData()を使って六角形の図形を描いています。スクリプトを見るとわかるように引数のgraphicsDataはstroke、fill、pathの3つの値が入っているベクターです(47〜49行目)。
var graphicsData:Vector.<IGraphicsData> = new Vector.<IGraphicsData>();
graphicsData.push(stroke, fill, path);
graphics.drawGraphicsData(graphicsData);
 stroke、fill、pathは、それぞれが線のスタイル、塗りのスタイル、描画パスを示すデータです。Hexagonクラスでは、これらの3つのデータをsetStroke()、setFill()、setPath()で作成しています。

Amazonで予約開始です!

|

毎日チェックしてたんですが、やっとAmazonで予約を開始しました。
よろしくお願いします。

まったく新しいAS3の世界にようこそ。
全面書き下ろし!Flash CS4の楽園への招待状。

Adobe Flash CS4 詳細!ActionScript3.0入門ノート[完全改訂版](CD-ROM付)
Adobe Flash CS4
詳細!ActionScript3.0入門ノート[完全改訂版](CD-ROM付)

定価3500円+税、496ページ、2色刷り

楽しいActionScript
確かにActionScript 3は少々手強いプログラム言語になってきました。時間をかけてじっくりと取り組まなければ簡単には習得できそうにありません。中級者、上級者と名乗れるまでには幾多の山がありそうです。
でも、つらいことだけじゃないですよね。ぼくは笑顔のFlasherをたくさん知ってます。ActionScriptはけっこう楽しい。どうもそれが真実です。新たなる1歩へと踏み出しましょう。

これを読め!!

|

見本が届きました。夏らしいアロハなデザインです!
首都圏の大きな書店では来週には店頭に並ぶと思います。

IMG_0975.jpg IMG_0972.jpg
予想よりちょっと分厚いかな。(^ ^)/ 496ページです。

windingプロパティ

|
(section09-03 Flash Player 10の新しいGraphicsメソッドから抜粋)

 drawPath()の第3引数で設定するwindingプロパティは図形のパスが交差してできる領域を塗るかどうかの湾曲規則を指定します。初期値では"evenOdd"になっていて、重なりが奇数回の場合に塗ります。
 次の例ではdata1、data2、data3と3つの図形が重なったパスを使って図形を描いています。このとき、2度重なっている部分は色が塗られず、3回重なっている部分は色が塗られているのがわかります。
fig09-03-03.jpg
[:script:]重なりがある図形をwindingプロパティを"evenOdd"で塗る
var w:int=120;
var h:int=150;
var data1:Array=[0,0, w,0, w,h, 0,h, 0,0];
var data2:Array=[25,25, w+25,25, w+25,h+25, 25,h+25, 25,25];
var data3:Array=[50,50, w+50,50, w+50,h+50, 50,h+50, 50,50];
var datalist:Array=data1.concat(data2,data3);
var commands:Vector.<int>=Vector.<int>([1,2,3,2, 1,2,3,2, 1,2,2,2,2]);
var data:Vector.<Number>=Vector.<Number>(datalist);
//描画の交差領域の塗りの処理法
var winding:String=GraphicsPathWinding.EVEN_ODD;
//図形を描く
var shape:Shape=new Shape();
shape.graphics.beginFill(0xFF0000);
shape.graphics.drawPath(commands, data, winding)
shape.graphics.endFill();
shape.x=200;
shape.y=150;
addChild(shape);

 windingプロパティのもう一方の値は"nonZero"です。この値はGraphicsPathWinding.NON_ZEROとして定数が定義してあります。windingプロパティを"nonZero"に設定すると湾曲タイプ(点を順に線で結ぶ方向)が時計回りか反時計回りかで図形を区別します。時計回りの値を+1、反時計回りの値を-1とし、重なっている領域はこの値を合計します。そして、値の合計が0の領域は塗らず、0以外の領域は塗ります。
 次の例ではすべてがdata1、data2、data3の全部が時計回りで+1なので、重なっている領域で合計が0になるところはありません。したがって、すべての領域が塗られます。
fig09-03-04.jpg
(section09-03 Flash Player 10の新しいGraphicsメソッドから抜粋)

 次の例はdrowPath()を使って渦巻き状に線を引くサンプルです。このように座標を計算式で求めることで図形を効率よく描けます。

[:script:]drawPath()を使って渦巻きを描く
var r:Number=1;
var rad:Number=2*Math.PI/8;
//描画コマンド
var commands:Vector.<int>=new Vector.<int>();
//描画に使う座標
var data:Vector.<Number>=new Vector.<Number>();
//コマンドと座標を追加する
commands.push(GraphicsPathCommand.MOVE_TO);
data.push(0,0);
for (var i:int=1; i<50; i++) {
	commands.push(GraphicsPathCommand.LINE_TO);
	r=i*i/20;
	var pt:Point=Point.polar(r,rad*i);
	data.push(pt.x,pt.y);
}
//図形を描く
var shape:Shape=new Shape();
shape.graphics.lineStyle(1,0x005500);
shape.graphics.drawPath(commands, data);
shape.x=stage.stageWidth/2;
shape.y=stage.stageHeight/2;
addChild(shape);
fig09-03-02.jpg
(section09-03 Flash Player 10の新しいGraphicsメソッドから抜粋)

 次にdrawPath()を使って図形を描くサンプルを示します。これを実行すると19行目でシェイプが作られ、このシェイプに図形を描画されます。drawPath()での描画はdrawRect()などの描画の手順と同じように図形を塗るならば描画する前にbeginFill()で塗りを開始し、描画終了でendFill()を実行します(20〜22行目)。実際に描画を行っているのは21行目のdrawPath()です。drawPathの3個の引数のcommandsとdataとwindingには、描画で必要となる値を入れておきます。
 commandsとdataはベクターです。ベクターを作るには、new Vector.<ベース型>()のようにベース型(値のデータ型)を指定してインスタンスを作ります。commandsは要素の値がint型なのでを指定します(4行目)。
fig09-03-01.jpg
[:script:]drawPath()を使って図形を描く
var w:int=150;
var h:int=120;
//描画コマンド
var commands:Vector.<int>=new Vector.<int>();
commands.push(GraphicsPathCommand.MOVE_TO);
commands.push(GraphicsPathCommand.LINE_TO);
commands.push(GraphicsPathCommand.CURVE_TO);
commands.push(GraphicsPathCommand.LINE_TO);
//描画に使う座標
var data:Vector.<Number>=new Vector.<Number>();
data.push(0,0);
data.push(w,0);
data.push(w,h);
data.push(0,h);
data.push(0,0);
//描画の交差領域の塗りの処理法
var winding:String=GraphicsPathWinding.EVEN_ODD;
//図形を描く
var shape:Shape=new Shape();
shape.graphics.beginFill(0xFF0000);
shape.graphics.drawPath(commands, data, winding);
shape.graphics.endFill();
shape.x=200;
shape.y=150;
addChild(shape);
 dataベクターを見るとわかるようにこの図形の描画には5個の点を使用し、ベクターには合計10個の値が入ります。commandsでは、dataから値を順に取り出してメソッドを実行していきます。commandsに追加したメソッドとdataの座標とを付き合わせると次のようになっています。moveTo()とlineTo()の引数は2個ですが、curveTo()はコントロールポイントの座標があるので4個の値を必要とします。
data.push(0,0);//moveTo(0,0)
data.push(w,0);//lineTo(w,0)
data.push(w,h);//curveTo(w,h,0,h)
data.push(0,h);
data.push(0,0);//lineTo(0,0)
(section09-03 Flash Player 10の新しいGraphicsメソッドから抜粋)

 moveTo()、lineTo()、curveTo()を使って直線や曲線で座標を結ぶことで図形を描くことができますが、辺の数だけ線を結ぶステートメントが必要です。新しく追加されたdrawPath()では、描画コマンドの配列と座標の配列を指定することで、図形の描画パスを1回で命令できます。drawPath()を使うことで描画スクリプトが簡潔になり、座標を数式で計算したり、外部から読み込む場合などにも対応しやすくなります。

書式
drawPath(commands:Vector, data:Vector, winding:String = "evenOdd"):void

 commandsは描画で使用するメソッドのベクター(データ型を指定した配列)です。使用できるコマンドは基本的にはmoveTo()、lineTo()、curveTo()と同じで、それぞれに1、2、3の数値が割り当ててあります。[1,2,2]ならば、moveTo()、lineTo()、lineTo()の順に実行することになります。dataは描画で使用する座標(x,y)のベクターです。[50,70,100,200,250,300]ならば、(50,70)と(100,200)と(250,300)の3つの点の座標を示しています。

 たとえば、commandsが[1,2,2]でdataが[50,70,100,200,250,300]ならば、moveTo(50,70)、lineTo(100,200)、lineTo(250,300)を実行することになり3つの点を結ぶ直線が引かれます。commandsが[1,3]ならば、moveTo(50,70)、curveTo(100,200,250,300)を実行して、(50,70)から(250,300)への曲線が引かれます。(100,200)の点は曲線を描くためのコントロールポイントの座標として使用されます。

 ところで、commandsには0、4、5の数値に割り当ててあるコマンドもあります。0は何もせずに次のコマンドに進みます。4、5はそれぞれmoveTo()とlineTo()を実行しますが、通常は引数が(x,y)と2個のところを(dummy,dummy,x,y)のように4個の座標値を使用し、最初の2個は無視します。これはcurveTo()で使用するコントロールポイントの座標を無視して描画するためです。先の例のcommandsが[1,3]のところを[1,5]にするとコントロールポイントの座標を無視して(50,70)から(250,300)へ直線で結びます。
 commandsで使用する0〜5の値は、次のようにGraphicsPathCommandクラスでクラス定数として定義してあります。


値  定数              実行するメソッド
0  GraphicsPathCommand.NO_OP  何も実行しない
1  GraphicsPathCommand.MOVE_TO  moveTo(x1,y1)
2  GraphicsPathCommand.LINE_TO  lineTo(x1,y1)
3  GraphicsPathCommand.CURVE_TO  curveTo(x1,y1,x2,y2)
4  GraphicsPathCommand.WIDE_MOVE_TO  値を2個とばしてmoveTo(x2,y2)
5  GraphicsPathCommand.WIDE_LINE_TO  値を2個とばしてlineTo(x2,y2)


 最後のwindingは図形が交差した領域を塗るかどうかを決めるパラメータです。値は"evenOdd"または"nonZero"をとります。この値については後ほどサンプルを示します。
(section09-02 図形の塗りと線の塗りから抜粋)

 線をビットマップで描く方法も基本的に同じです。線幅などのスタイルはlineStyle()で指定します。このとき、lineStyle()の設定をlineBitmapStyle()よりも先に行います。次のサンプルの線幅は40に指定しています(7行目)。円の塗りパターンに使う花柄のビットマップデータはビットマップシンボルから作っています(5行目)。
 線をビットマップデータのパターンで塗るにはlineBitmapStyle()を実行します。第2引数の変換マトリックスではビットマップデータを80%に縮小し、60度回転させています(9〜13行目)

fig09-02-09.jpg

[:script:]円をビットマップデータの線で描く
var shape1:Shape=new Shape();
var w:int=250;
var h:int=200;
//ビットマップデータを作る
var bmpdata:BitmapData=new PatternImg(0,0);
//線幅を設定する
shape1.graphics.lineStyle(40);
//変換マトリックス
var mtrx:Matrix=new Matrix();
mtrx.scale(0.8,0.8);
mtrx.rotate(Math.PI/3);
//線をビットマップデータのパターンで塗る
shape1.graphics.lineBitmapStyle(bmpdata,mtrx,true,true);
//円を描く
shape1.graphics.drawCircle(0,0,80);
//ステージに置く
shape1.x=stage.stageWidth/2;
shape1.y=stage.stageHeight/2;
addChild(shape1);
(section09-02 図形の塗りと線の塗りから抜粋)

 図形や線をビットマップデータで塗ることができます。図形をビットマップデータで塗るにはbeginBitmapFill()、線をビットマップデータで塗るにはlineBitmapStyle()でそれぞれ塗りに使うビットマップデータや塗り方を指定します。

書式:図形をビットマップで塗る
beginBitmapFill(bitmap:BitmapData, matrix:Matrix = null, repeat:Boolean = true, smooth:Boolean = false):void

書式:線をビットマップで塗る
lineBitmapStyle(bitmap:BitmapData, matrix:Matrix = null, repeat:Boolean = true, smooth:Boolean = false):void

 bitmapdataはビットマップデータです。ビットマップデータはBitmapDataクラスで作りますが、ビットマップシンボルや外部イメージファイルから読み込んで作るといったこともできます。matrixはグラデーションの塗りでも使用した変形マトリックスです。ビットマップの拡大縮小や回転などを設定できます。
 repeatはビットマップのサイズより大きな領域を塗ったときにビットマップのパターンを繰り返すかどうかをtrue、falseで指定します。falseを指定した場合はパターンの繰り返しを行わずにビットマップの境界の色がそのまま連続します。smoothは伸縮したビットマップにスムージング処理のアルゴリズムを適用するかどうかを指定します。trueに設定するとスムーズになりますが、表示の処理はfaleのほうが高速です。


図形をビットマップで塗る
 次のサンプルはスクリプトで描いた四角形をビットマップシンボルのビットマップデータで塗っています。ビットシンボルからビットマップデータを取り出すには、ビットマップシンボルのリンケージ書き出し設定を行い、new演算子でインスタンス化します(4行目)。このとき、EZ_logo(0,0)のように2個の数値の引数が必要です。数値の大きさには意味がありません。
 ビットマップデータが作れたならば、図形を描く前にbeginBitmapFill()を実行し、図形を描いたらendFill()を実行します。beginBitmapFill()の第2引数の変換マトリックスは45度回転させています。第4引数のsmoothもtrueにしているので、パターンを回転させていてもイメージのジャギーが目立たずにスムーズです(9行目)。

fig09-02-07.jpg  fig09-02-08.jpg

[:script:]ビットマップデータのパターンで塗った円形を描く
var shape1:Shape=new Shape();
var r:int=150;
//ビットマップデータを作る
var bmpdata:BitmapData=new EZ_logo(0,0);
//変換マトリックス
var mtrx:Matrix=new Matrix();
mtrx.rotate(Math.PI/4);
//図形をビットマップデータのパターンで塗る
shape1.graphics.beginBitmapFill(bmpdata,mtrx,true,true);
//円を描く
shape1.graphics.drawCircle(0,0,r);
//塗り終わり
shape1.graphics.endFill();
//ステージの中央に置く
shape1.x=stage.stageWidth/2;
shape1.y=stage.stageHeight/2;
addChild(shape1);
(section09-02 図形の塗りと線の塗りから抜粋)

 線をグラデーションで塗りたい場合は、先にlineStyle()で線の太さや両端の形などを指定し、続いてlineGradientStyle()を実行してグラデーションを指定します。線の設定を行ったならば線や図形を描きます。
 次の例は黄色と黒の斜めのグラデーションで線を縞々に塗っています。縞々の繰り返しのグラデーションにするには、spreadオプションをSpreadMethod.REFLECTかSpreadMethod.REPEATのどちらかにします。SpreadMethod.REPEATは単純な繰り返しですが、SpreadMethod.REFLECTは色の変化が反転するように繰り返されます(14行目)。縞の幅はcreateGradientBox()の第1引数で10に設定しています(12行目)。

fig09-02-05.jpg

[:script:]]四角形の線を斜めの縞々で塗る
var shape1:Shape=new Shape();
var w:int=250;
var h:int=200;
//線幅
shape1.graphics.lineStyle(15);
//線のグラデーション
var type:String=GradientType.LINEAR;
var colors:Array=[0xFFFF00,0x000000];
var alphas:Array=[1, 1];
var ratios:Array=[0,255];
var mtrx:Matrix=new Matrix();
mtrx.createGradientBox(10,h,0,0,0)
mtrx.rotate(Math.PI/4);
var spread:String=SpreadMethod.REFLECT;
shape1.graphics.lineGradientStyle(type,colors,alphas,ratios,mtrx,spread);
//四角形を描く
shape1.graphics.beginFill(0xFFFF99);
shape1.graphics.drawRect(0,0,w,h);
shape1.graphics.endFill();
//ステージの中央に置く
shape1.x=stage.stageWidth/2-w/2;
shape1.y=stage.stageHeight/2-h/2;
addChild(shape1);
(section09-02 図形の塗りと線の塗りから抜粋)

 図形や線をグラデーションで塗ることができます。図形をグラデーションで塗るにはbeginGradientFill()、線をグラデーションで塗るにはlineGradientStyle()でそれぞれグラデーションの色やタイプを指定します。

書式:図形をグラデーションで塗る
beginGradientFill(type:String, colors:Array, alphas:Array, ratios:Array, matrix:Matrix = null, spreadMethod:String = "pad", interpolationMethod:String = "rgb", focalPointRatio:Number = 0):void

書式:線をグラデーションで塗る
lineGradientStyle(type:String, colors:Array, alphas:Array, ratios:Array, matrix:Matrix = null, spreadMethod:String = "pad", interpolationMethod:String = "rgb", focalPointRatio:Number = 0):void

 typeはグラデーションのタイプをGradientType.LINEAR(線状)またはGradientType.RADIAL(放射状)のどちらかで指定します。colorsはグラデーションする色の配列です。たとえば、赤から緑のグラデーションならば[0xFF0000,0x00FF00]、赤緑青の三色のグラデーションならば[0xFF0000,0x00FF00,0x0000FF]のように指定します。alphasはそれぞれの色のアルファ値を配列で指定します。ratiosはグラデーションの各色の開始位置を比率(0〜255)で指定します。2色のグラデーションで両端が指定色になるようにするならば[0,255]になり、最初は1色で後半からグラデーションを開始するようにするには[127,255]のように指定します。
 matrixではグラデーションの幅と高さ、平行移動、回転、縮尺などを変換マトリックスを使って指定します。変換マトリックスはMatrixクラスのインスタンスを作り、createGradientBox()、translate()、scale()、rotate()といったメソッドを利用して変換の値を設定します。
 spreadMethodはグラデーションの広がりをSpreadMethod.PAD、SpreadMethod.REFLECT、SpreadMethod.REPEATから選びます。focalPointRatioはグラデーションの焦点を決める値(-1〜1)です。

(section09-01 基本的な図形を描くから抜粋)

 BezierSegmentクラスを利用すると比較的簡単にベジェ曲線を描くことができます。ベジェ曲線を描くには線の始点aと終点dのアンカーポイントと曲線の向きを決める2個のコントロールポイントb、cが必要です。BezierSegmentクラスのコンストラクタではこれらの4点のPointオブジェクトをa、b、c、dの順で引数として与えます。

書式
var bezier:BezierSegment=new BezierSegment(a:Point, b:Point, c:Point, d:Point);

 a、b、c、dの各点を図で示すと次のようになります。
fig09-01-20_shiji.jpg
 BezierSegmentクラスのインスタンスを作ると、コンストラクタで指定したアンカーポイントとコントロールポイントをもったベジェ曲線が作られます。ただし、BezierSegmentクラスには曲線を描くメソッドはなく、ベジェ曲線の軌跡の座標が計算されるだけです。ベジェ曲線を線として描くためには、getValue()を利用して曲線の途中の点の座標を求めて直線でつないでいきます。
 getValue()はPointクラスのinterpolate()と同じようなメソッドで、曲線を始点の位置を0、終点の位置を1として比率で途中の点を示します。たとえば、全体をtCnt分割するならば、t番目の位置の座標はbezier.getValue(t/tCnt)になります。分割するtCntの数が多いほど曲線の途中の点を細かく取ることになり、より滑らかな曲線を描けますが、その分だけ処理は重くなります。
 次のサンプルではステージのb_mcとc_mcの座標をコントロールポイントに使って、a_mcとc_mcの間にベジェ曲線を描いてます。便宜上、a-b、d-cを結ぶ補助線も引いていますが、もちろんこの線がなくてもベジェ曲線は描かれます

fig09-01-21.jpg

[:script:]ベジェ曲線を描く
import fl.motion.BezierSegment;
//アンカーポイントa,b コントロールポイントb,c
var a:Point=new Point(a_mc.x,a_mc.y);
var b:Point=new Point(b_mc.x,b_mc.y);
var c:Point=new Point(c_mc.x,c_mc.y);
var d:Point=new Point(d_mc.x,d_mc.y);
//補助線を描く
graphics.lineStyle(1,0x666666);
graphics.moveTo(a.x,a.y);
graphics.lineTo(b.x,b.y);
graphics.moveTo(d.x,d.y);
graphics.lineTo(c.x,c.y);
//ベジェ曲線を描く
var bezier:BezierSegment=new BezierSegment(a,b,c,d);
var tCnt:int=100;//曲線上の点の個数
graphics.lineStyle(2);
graphics.moveTo(a.x,a.y);
for (var t=0; t<=tCnt; t++) {
	//曲線上の点
	var tmpPt:Point=bezier.getValue(t/tCnt);
	//前の点と直線で結ぶ
	graphics.lineTo(tmpPt.x,tmpPt.y);
}

マスクの利用

|
(section09-01 基本的な図形を描くから抜粋)

 シェイプやスプライトで描く図形の活用としてマスクをあげることができます。次の例では写真のムービークリップインスタンスに円を描いたシェイプをマスクとして設定し、写真を円形に切り抜いて表示しています。

fig09-01-17.jpg  fig09-01-18.jpg

[:script:]写真にシェイプマスクをかける
//コンテナを作る
var container:Sprite=new Sprite();
container.x=100;
container.y=50;
addChild(container);
//写真のmcを作る
var photo_mc:MovieClip=new Photo();
//マスクに使うシェイプを作る
var shape1:Shape=new Shape();
shape1.graphics.beginFill(0xFF0000);
shape1.graphics.drawCircle(0,0,100);
shape1.graphics.endFill();
shape1.x=photo_mc.width/2;
shape1.y=photo_mc.height/2;
//コンテナに追加する
container.addChild(photo_mc);
container.addChild(shape1);
//shape1をphoto_mcのマスクに設定する
photo_mc.mask=shape1;

(section09-01 基本的な図形を描くから抜粋)

 描いた図形や線を消すにはclear()を実行します。描画によるアニメーションを行うには、描画とclear()を繰り返します。
 次のサンプルは曲線の描き方で使ったcurveTo.flaを改良し、線を結ぶインスタンスをドラッグできるようにしたものです。インスタンスをドラッグすると、それに合わせて線が再描画されます(36〜45行目)。

fig09-01-16b.jpgswfを試す

[:script:]ドラッグできるインスタンスを直線と曲線で結ぶ
var shape1:Shape=new Shape();
var stageRect:Rectangle=new Rectangle(0,0,stage.stageWidth,stage.stageHeight);
//ステージに配置する
shape1.x=0;
shape1.y=0;
addChild(shape1);

//最初に線を引く
updateLines();

//頂点をドラッグできるようにする
pt1.addEventListener(MouseEvent.MOUSE_DOWN, onStartDrag);
pt2.addEventListener(MouseEvent.MOUSE_DOWN, onStartDrag);
ctrlPt.addEventListener(MouseEvent.MOUSE_DOWN, onStartDrag);
stage.addEventListener(MouseEvent.MOUSE_UP, onStopDrag);

//ドラッグ開始
function onStartDrag(eventObj:MouseEvent):void {
	var mc:MovieClip=eventObj.target as MovieClip;
	mc.startDrag(false,stageRect);
	stage.addEventListener(MouseEvent.MOUSE_MOVE,updateLines);
}

//ドラッグ終了
function onStopDrag(eventObj:MouseEvent):void {
	stopDrag();
	stage.removeEventListener(MouseEvent.MOUSE_MOVE,updateLines);
}

//ドラッグ中は再描画する
function updateLines(eventObj:MouseEvent=null):void {
	if (eventObj != null) {
		//ドラッグに合わせて画面更新
		eventObj.updateAfterEvent();
	}
	//描画を消す
	shape1.graphics.clear();
	//pt1-pt2の曲線を引く
	shape1.graphics.lineStyle(1,0x000000);
	shape1.graphics.moveTo(pt1.x,pt1.y);
	shape1.graphics.curveTo(ctrlPt.x,ctrlPt.y,pt2.x,pt2.y);
	//pt1-ctrlPtの接線を引く
	shape1.graphics.lineStyle(1,0x666666);
	shape1.graphics.moveTo(pt1.x,pt1.y);
	shape1.graphics.lineTo(ctrlPt.x,ctrlPt.y);
}

塗りの閉じ

|
(section09-01 基本的な図形を描くから抜粋)

 endFill()を実行しなくても図形の塗りは実行されます。たとえば、次のように円を描いた場合、endFill()を実行しなくても図形が塗られます。

[:script:]endFill()を実行していない
var sp:Sprite=new Sprite();
sp.graphics.beginFill(0xFF0000);
sp.graphics.drawCircle(0,0,100);
sp.x=200;
sp.y=150;
addChild(sp);

fig09-01-13.jpg
 では、endFill()は必要ないかと言えばそうではありません。次のように重なるように円を描いた場合、塗りが重なっている部分は塗られません。

[:script:]円を重ねて描くと、塗りが重なった部分が塗られません。
var sp:Sprite=new Sprite();
sp.graphics.beginFill(0xFF0000);
sp.graphics.drawCircle(0,0,100);
sp.graphics.drawCircle(-80,0,50);
sp.x=200;
sp.y=150;
addChild(sp);

fig09-01-14.jpg
 2つの円がどちらも塗られるようにするには、図形の塗りの終了ごとにendFill()を実行することで円を1個ずつ塗ります。

[:script:]重なっている円を塗る
var sp:Sprite=new Sprite();
//塗りの開始
sp.graphics.beginFill(0xFF0000);
sp.graphics.drawCircle(0,0,100);
sp.graphics.endFill();
//塗り終了
//塗りの開始
sp.graphics.beginFill(0xFF0000);
sp.graphics.drawCircle(-80,0,50);
sp.graphics.endFill();
//塗り終了
sp.x=200;
sp.y=150;
addChild(sp);

fig09-01-15.jpg

図形の塗り

|
(section09-01 基本的な図形を描くから抜粋)

 図形の内部を塗るには図形の描画を開始する前にbeginFill()を実行し、図形の描画が終わったならばendFill()で塗りを終了します。beginFill()では塗り色と塗りの透明度を指定できます。
 次のサンプルではpt1からpt2、pt2からpt3の直線を2本引いています。2本の線では図形として閉じていませんが、塗りを行うと自動的にpt3からpt1への線が引かれて3点を頂点とした三角形になり、内部が塗られます。

fig09-01-11a.jpg fig09-01-11b.jpg
[:script:]図形を塗りつぶす
var pt1:Point=new Point(0,0);
var pt2:Point=new Point(150,100);
var pt3:Point=new Point(80,150);
var sp:Sprite=new Sprite();
//線のスタイル
sp.graphics.lineStyle(3,0x000000);
//塗り始め
sp.graphics.beginFill(0x999999);
//線を引く
sp.graphics.moveTo(pt1.x,pt1.y);
sp.graphics.lineTo(pt2.x,pt2.y);
sp.graphics.lineTo(pt3.x,pt3.y);
//塗り終わり
sp.graphics.endFill();
sp.x=100;
sp.y=100;
addChild(sp);

 また、線のスタイルを指定している6行目を取り去ると線が引かれれなくなりますが、線は見えなくても図形の塗りが行われます。
fig09-01-12.jpg

曲線を引く

|
(section09-01 基本的な図形を描くから抜粋)

 曲線はcurveTo()を使って引きます。描き方の手順はlineTo()を使った直線の描き方と基本的に同じですが、curveTo()では曲線の終点とは別に曲線の接線方向を示すコントロールポイントを指定します。
 次の例ではステージにpt1、pt2、ctrlPtの3つのインスタンスが作ってあります。そして、ctrlPtをコントロールポイントの座標に使い、始点pt1と終点pt2を結ぶ曲線を引きます(2〜5行目)。
 さらに始点pt1とコントロールポイントctrlPの直線も描いています。始点pt1とコントロールポイントctrlPの直線を引くと、この直線を接線として曲線が描かれているのがわかります(7〜9行目)。
 なお、lineTo()、curveTo()で指定する座標はshape1のローカル座標ですが、pt1、pt2、ctrlPtの座標はステージを基準としたグローバル座標です。この座標を合わせるためにshape1はステージの(0,0)の位置にaddChild()します。

fig09-01-10.jpgswfを試す

[:script:]曲線を引く
var shape1:Shape=new Shape();
//pt1-pt2の曲線を引く
shape1.graphics.lineStyle(1,0x000000);
shape1.graphics.moveTo(pt1.x,pt1.y);
shape1.graphics.curveTo(ctrlPt.x,ctrlPt.y,pt2.x,pt2.y);
//pt1-ctrlPtの接線を引く
shape1.graphics.lineStyle(1,0x666666);
shape1.graphics.moveTo(pt1.x,pt1.y);
shape1.graphics.lineTo(ctrlPt.x,ctrlPt.y);
//ステージに配置する
shape1.x=0;
shape1.y=0;
addChild(shape1);
(section09-01 基本的な図形を描くから抜粋)

 次の例はJapanと書いたjapan_mcインスタンスにトゲを刺すように線を引いています。まず、japan_mcの矩形内のランダムな点pt1(pt1x,pt1y)を求めます(9、10行目)。その座標をグローバル座標の点pt1に変換し、pt1がjapan_mcのイメージと衝突しているかどうかをhitTestPoint()で判定します(15行目)。そして、衝突しているならばその点を線を引く始点pt1にし、線の終点pt2は、ランダムに決めた線の長さと角度からPoint.polar(lineLength,rad)で計算します(19〜24行目)。そのままではpt2は(0,0)からの点になるので、pt1の位置からの距離と角度になるようにoffset()で座標を補正します(25行目)。これで線の始点pt1と終点pt2が決まったので、pt1にペン先を移動してpt2までの線を引きます(27、28行目)。

fig09-01-07.jpgswfを試す

[:script:]インスタンスにトゲを刺すように線を引く
//線(トゲ)の本数
var num:int=4000;
//線を描くシェイプ
var lines_shape:Shape=new Shape();
addChild(lines_shape);
//線を繰り返し描く
for (var i=1; i<=num; i++) {
	//線の始点pt1の座標
	var pt1x:Number=japan_mc.width*Math.random();
	var pt1y:Number=japan_mc.height*Math.random();
	var pt1:Point=new Point(pt1x,pt1y);
	//pt1をグローバル座標に変換する
	pt1=japan_mc.localToGlobal(pt1);
	//始点pt1がjapan_mcに刺さっているならば線を描く
	if (japan_mc.hitTestPoint(pt1.x,pt1.y,true)) {
		//線のスタイル
		var lineColor:Number=0xFFFFFF*Math.random();
		lines_shape.graphics.lineStyle(1,lineColor,0.6);
		//線の長さ
		var lineLength:Number=3+17*Math.random();
		//線の角度
		var rad:Number=2*Math.PI*Math.random();
		//線の終点pt2を求める
		var pt2:Point=Point.polar(lineLength,rad);
		pt2.offset(pt1.x,pt1.y);
		//線を引く
		lines_shape.graphics.moveTo(pt1.x,pt1.y);
		lines_shape.graphics.lineTo(pt2.x,pt2.y);
	}
}

 *元々はここまでのサンプルだったんですが、せっかくなのでトゲが動くバージョンも作りました。(書籍には動くスクリプトも掲載してあります)
トゲが動くバージョン

直線を引く

|
(section09-01 基本的な図形を描くから抜粋)

 直線を描くにはmoveTo()とlineTo()を使います。moveTo()は線を引き始める座標にペン先を移動します。lineTo()は現在のペン先位置から指定の座標まで直線を引きます。次の例では円を描いた後に円の中心を水平に横切る直線を引いています。横線を引く前にlineStyle()を設定し直しているので、横線は円の線とは違うスタイルで引かれます。
fig09-01-06.jpgswfを試す


[:script:]円に横線を引く
var shape1:Shape=new Shape();
shape1.graphics.lineStyle(5,0x666666);
//円を描く
var r:int=40;
shape1.graphics.drawCircle(0,0,r);
//横線を引く
shape1.graphics.lineStyle(10,0xFF0000,1,false,"normal","round");
var len:int=2*(r+10);
shape1.graphics.moveTo(len/2,0);
shape1.graphics.lineTo(-len/2,0);
//ステージの中央に置く
shape1.x=stage.stageWidth/2;
shape1.y=stage.stageHeight/2;
addChild(shape1);
(section09-01 基本的な図形を描くから抜粋)

 図形を描く線の色とスタイルはlineStyle()の引数で設定します。引数は次の書式のように8つあります。

書式:
lineStyle(thickness:Number = NaN, color:uint = 0, alpha:Number = 1.0, pixelHinting:Boolean = false, scaleMode:String = "normal", caps:String = null, joints:String = null, miterLimit:Number = 3):void

 pixelHintingは角丸四角形の角などの直線と曲線のつながりの部分でのピクセルのずれがめだたないように修正するかどうかを指定する設定です。初期値は修正しないfalseになっていますが、修正する場合はtrueに設定します。線の設定を変えて角丸四角形を描いた場合の比較例を次に示します。左がpixelHintingがfalseのshape1、右がpixelHintingがtrueのshape2です。左のshape1は左辺の角と辺のつながりが不連続になっている部分が目立ちます。

fig09-01-05.jpgswfを試す

[:script:]lineStyleのpixelHintingの設定を変えて角丸四角形を描く
var shape1:Shape=new Shape();
var shape2:Shape=new Shape();
//pixelHinting=false
shape1.graphics.lineStyle(3,0x000000,1,false);
shape1.graphics.drawRoundRect(0,0,100,100,30,80)
shape1.x=100;
shape1.y=150;
addChild(shape1);
//pixelHinting=true
shape2.graphics.lineStyle(3,0x000000,1,true);
shape2.graphics.drawRoundRect(0,0,100,100,30,80)
shape2.x=250;
shape2.y=150;
addChild(shape2);
(section09-01 基本的な図形を描くから抜粋)

 図形の描画はGraphicsクラスの描画メソッドを使いますが、Graphicsクラスのインスタンスを作って直接利用することはできません。また、Graphicsクラスを継承して描画可能なクラスを再定義することもできません。
 Graphicsクラスの描画メソッドを利用するには、Shapeクラス、Spriteクラス、そしてSpriteクラスのサブクラスであるMovieClipクラスのgraphicsプロパティを介してGraphicsクラスのオブジェクトにアクセスします。

図形を描く
 Graphicsクラスの描画メソッドを使うと、円、楕円、四角形、角丸四角形の図形を描くことができます。次のスクリプトはGraphicsクラスのdrawCircle()を使って、Shapeクラスのインスタンスに円を描いています。
 なお、Shapeクラスは単純なシェイプを作成するときに利用されます。ShapeクラスはSpriteクラスと違ってDisplayObjectContainerとInteractiveObjectを継承していません。つまり、ほかの表示オブジェクトを入れ子にもつことができず、クリックイベントなどのイベントを受け取りません。その分だけSpriteクラスよりもメモリを消費しません。

[:script:]円を描く
var shape1:Shape=new Shape();
//線幅3、赤色の線
shape1.graphics.lineStyle(3,0xFF0000);
//円を描く
shape1.graphics.drawCircle(0,0,80);
//ステージの中央に置く
shape1.x=stage.stageWidth/2;
shape1.y=stage.stageHeight/2;
addChild(shape1);
 drawCircle(0,0,80)は、中心点の座標(0,0)と半径80の円を描きます。座標の(0,0)はステージの座標ではなく、addChild()する親オブジェクトの中心点を基準とするローカル座標です。図形を描く線はlineStyle()で指定します。lineStyle()のオプションはたくさんありますが、ここでは線幅3と線色0xFF0000(赤)を指定しています。

fig09-01-01.jpgswfを試す

(section07-03 表示オブジェクトの重なりの変更から抜粋)

 インデックス番号は表示オブジェクトコンテナに追加された順に付けられますが、正確には表示オブジェクトの重なり順です。したがって、重なり順を変更したり、インスタンスを削除するとインデックス番号も付け変わります。
 次のサンプルではロールオーバーした表示オブジェクトの重なりを最前面にします。重なりを最前面にするには、インデックス番号が大きい物ほど重なりが上になるので、表示オブジェクトのインデックス番号を子オブジェクトの個数-1に設定します(10行目)。子オブジェクトの個数は親オブジェクトのnumChildrenプロパティで調べることができます(8行目)。
fig07-03-03a.jpgswfを試す

[:script:]ロールオーバーした表示オブジェクトを最前面にする
box_mc.addEventListener(MouseEvent.ROLL_OVER, onRollover);
ball_mc.addEventListener(MouseEvent.ROLL_OVER, onRollover);
penta_mc.addEventListener(MouseEvent.ROLL_OVER, onRollover);
//ロールオーバーで実行
function onRollover(eventObj:MouseEvent):void {
	var mc:MovieClip=eventObj.target as MovieClip;
	//子オブジェクトの個数-1
	var lastIndex:int=mc.parent.numChildren-1;
	//インデックス番号をセットする
	mc.parent.setChildIndex(mc,lastIndex);
}

書籍のデータが確定しましたのでお知らせします。

書名:
Adobe Flash CS4
詳細!ActionScript 3.0入門ノート[完全改訂版]

B5変形版/496ページ/2色刷り
価格:本体価格3,500+税
発売日:2009年8月1日
ISBN978-4-88166-694-4

694a.jpg

26664698_3824509921.jpg

目次はこちら→目次項目

(section07-02 表示リストから抜粋)

 表示オブジェクトをメモリから消去する場合、イベントのリスナー関数を登録したままだとイベントが発生したタイミングで参照エラーになるので注意が必要です。表示オブジェクトを表示リストから取り除く際には、登録しておいたイベントのリスナー関数を忘れずに取り除かなければなりません。Event.ENTER_FRAMEイベントなどは表示リストに登録していなくてもイベントが発生します。
 次のサンプルは、FlowerAクラスのインスタンスを再生イベントの繰り返しを利用して作成し、ステージの上から下へと回転しながら降らせるムービーです。このサンプルではインスタンスを大量に作成しますが、作成してすぐに表示リストに追加するので、アニメーションの途中でメモリから消去されてエラーになることはありません。また、インスタンスを回転しながら降らせるためにインスタンスに再生イベントのリスナーonFrowerStep()を登録していますが、表示リストから消去する前にこのリスナー関数も取り除いています。

fig07-02-09b.jpgswfを試す

(section07-01 表示オブジェクトの追加から抜粋)

 次のサンプルではクリックした位置に花のインスタンスを作ります。先のサンプルと同じように表示するフレームとスケールはランダムに決めています。インスタンスの座標は6〜7行目でクリックした座標に設定しています。クリックした座標はMouseEvent.MOUSE_DOWNイベントの引数のイベントオブジェクトのstageX、stageYプロパティで取り出せます。
fig07-01-08b.jpgswfを試す

[:script:]クリックした位置にインスタンスを作る
1	stage.addEventListener(MouseEvent.MOUSE_DOWN, newFlower);
2	//クリックでインスタンスを作る
3	function newFlower(eventObj:MouseEvent):void {
4		var flower_mc:Flowers=new Flowers();
5		//クリックした座標に表示する
6		flower_mc.x=eventObj.stageX;
7		flower_mc.y=eventObj.stageY;
8		//スケールを0.8〜3.8の間でランダムに決める
9		var scale:Number=0.8+3*Math.random();
10		flower_mc.scaleX=flower_mc.scaleY=scale;
11		//表示するフレームをランダムに決める
12		var frame:uint=1+Math.floor(flower_mc.totalFrames*Math.random());
13		flower_mc.gotoAndStop(frame);
14		//ステージに表示する
15		addChild(flower_mc);
16	}	
(section06-03 衝突判定から抜粋)

 intersects()とcontainsRect()は矩形と矩形の衝突判定を行う関数です。intersects()は比較する矩形と矩形が少しでも重なっているときにtrueになり、containsRect()は矩形の中に比較する矩形が完全に入っているときにtrueになります。
 次の例はcontainsRect()のサンプルです。写真のphoto_mcインスタンスを写真枠のphotoFrame_mcインスタンスにドラッグ&ドロップしたとき、photo_mcがphotoFrame_mcの領域の中に完全に入っているかどうかを判定しています。photo_mcがphotoFrame_mcの領域の中に完全に入っているときはphoto_mcをphotoFrame_mcの中央に位置揃えし、領域内に完全に入っていないときはphotoFrame_mcの外に出してしまいます。

fig06-03-03a.jpgswfを試す

[:script:]photo_mcをphotoFrame_mcの矩形の中に入るようにドロップしたか判定する
//マウスダウンでドラッグ開始
photo_mc.addEventListener(MouseEvent.MOUSE_DOWN, onStartDrag);
//ドラッグ開始
function onStartDrag(eventObj:MouseEvent):void {
	photo_mc.startDrag(false);
	photo_mc.alpha=0.5;
	stage.addEventListener(MouseEvent.MOUSE_UP, onStopDrag);
}
//ドラッグ終了
function onStopDrag(eventObj:MouseEvent):void {
	photo_mc.stopDrag();
	photo_mc.alpha=1;
	containsCheck();
}
//photo_mcの矩形がphotoFrame_mcの矩形に完全に入っているかどうかチェックする
function containsCheck():void {
	//photoFrame_mcの矩形
	var frameBounds:Rectangle=photoFrame_mc.getBounds(stage);
	//photo_mcの矩形
	var photoBounds:Rectangle=photo_mc.getBounds(stage);
	//photo_mcの矩形がphotoFrame_mcの矩形に完全に入っているかどうか
	if (frameBounds.containsRect(photoBounds)) {
		//入っていれば中央に表示する
		var center_x:Number=frameBounds.left+photoFrame_mc.width/2;
		var center_y:Number=frameBounds.top+photoFrame_mc.height/2;
		photo_mc.x=center_x-photoBounds.width/2;
		photo_mc.y=center_y-photoBounds.height/2;
	} else {
		//photoFrame_mcの外に出してしまう
		photo_mc.x=frameBounds.right+photoBounds.width/2;
		photo_mc.y=frameBounds.top+photoBounds.height/2;
	}
}
(section06-03 衝突判定から抜粋)

 containsPoint()は点と領域を比較します。引数で指定した点が矩形領域の中に入っているときにtureになります。
 次のサンプルは写真の3つの部分を示すrect_1、rect_2、rect_3の矩形を作っておき、その領域にカーソルが入ったらその部分をインスタンスで囲んで示します。
 マウスカーソルが矩形の中に入っているかどうかをチェックするのは24行目です。矩形のrect_1、rect_2、rect_3は写真の左上角を座標の基準としているので、マウス座標と比較するために、20行目ではステージでの写真の左上角の頂点に合わせて座標をオフセットしています。このとき、矩形に対してoffset()を実行すると元の矩形が変化するので18行目のようにclone()で複製した矩形を使って比較を行います。
 ステージにはあらかじめ矩形を囲むインスタンスselectBox_mcを作っておきます。処理を簡単にするためにselectBox_mcは左上角に基準点があるように作ります。

fig06-03-01b.jpgswfを試す

[:script:]カーソルが領域に入ったならば領域を囲むインスタンスを表示する
//選択枠の初期化
selectBox_mc.visible=false;
selectBox_mc.alpha=0.5;
//ホット領域の矩形
var rect_1:Rectangle=new Rectangle(120,10,35,20);//江ノ島
var rect_2:Rectangle=new Rectangle(230,30,120,25);//サーファー
var rect_3:Rectangle=new Rectangle(170,75,120,70);//ボードキャリア
var rectList:Array=[rect_1,rect_2,rect_3];
//写真の矩形
var photoRect:Rectangle=photo_mc.getRect(stage);
//ロールオーバーのチェック
stage.addEventListener(MouseEvent.MOUSE_MOVE, rollCheck);
function rollCheck(eventObj:MouseEvent):void {
	for (var i:int=0; i<rectList.length; i++) {
		//チェックする矩形を取り出す
		var rect:Rectangle=rectList[i];
		//offset処理で変化しないように矩形の複製を作る
		var chkRect:Rectangle=rect.clone();
		//矩形をステージのグローバル座標に合わせる
		chkRect.offset(photoRect.left,photoRect.top);
		//マウス座標
		var mousePt:Point=new Point(stage.mouseX,stage.mouseY);
		//マウス座標がホット領域に入っているかチェックする
		if (chkRect.containsPoint(mousePt)) {
			//選択枠を表示する
			selectBox_mc.x=chkRect.x;
			selectBox_mc.y=chkRect.y;
			selectBox_mc.width=chkRect.width;
			selectBox_mc.height=chkRect.height;
			selectBox_mc.visible=true;
			//forによる無駄な繰り返しを抜ける
			break;
		} else {
			//選択枠を消す
			selectBox_mc.visible=false;
		}
	}
}
(section06-02 Rectangleクラスから抜粋)

 次のサンプルは回転しながら水平移動するインスタンスbox_mcがステージの両端で跳ね返ります。box_mcが回転しているので変化する領域をgetBounds()で取得し、box_mcの左右の辺の座標をleft、rightのプロパティで取り出しています。

fig06-02-06_shiji.jpgswfを試す

[:script:]回転しながら移動し、ステージの両端で跳ね返る
var dx:int=5;
var dd:int=15;
box_mc.addEventListener(Event.ENTER_FRAME, onEnterframe);
function onEnterframe(eventObj:Event):void {
	//box_mcの領域を調べる
	var bounds:Rectangle=box_mc.getBounds(stage);
	//左右の辺がステージからはみ出たら動作を反転する
	if (bounds.left<0) {
		dx*=-1;
		dd*=-1;
	} else if (bounds.right>stage.stageWidth) {
		dx*=-1;
		dd*=-1;
	}
	//移動と回転
	box_mc.x+=dx;
	box_mc.rotation+=dd;
}
(section06-01 Pointクラスから抜粋)

 次のサンプルではインスタンスball_mcとマウスカーソルの距離を測り、距離が200ピクセル以内になったとき、マウスが近づくほどball_mcが速く回転するというものです。ball_mcとマウスカーソルの距離は8行目のPoint.distance(ballPt,mousePt)で計算しています。ball_mcとマウスカーソルの距離はマウスカーソルがball_mcの左右上下のどの方向にあっても正の値になります。また、11行目では回転速度が大きく成りすぎないように距離が10ピクセルより近づいたときには、計算では10ピクセルを最低値として使用しています。

fig06-01-06.jpgswfを試す

[:script:]マウスが近づくほど回転が速くなる
addEventListener(Event.ENTER_FRAME, onEnterframe);
function onEnterframe(eventObj:Event):void {
	//インスタンスの座標
	var ballPt:Point=new Point(ball_mc.x,ball_mc.y);
	//マウスの座標
	var mousePt:Point=new Point(stage.mouseX,stage.mouseY);
	//インスタンスとマウスの距離
	var distance:Number=Point.distance(ballPt,mousePt);
	//距離が200以下の時に回転する
	if(distance<200){
		ball_mc.rotation+=2000/Math.max(10,distance);
	}
}
(section05-03 座標移動のアニメーションから抜粋)

 yoyo()はトゥイーンの逆再生を行うメソッドです。プロパティの値がaからbに変化するトゥイーンを作って実行している最中にyoyo()を実行すると、bからaへの逆向きのトゥイーンになります。さらに逆向きのトゥイーンの再生中にyoyo()を実行すると再びトゥイーンの方向が逆転してaからbへのトゥイーンになります。
fig05-03-06_shiji.jpgswfを試す

[:script:]ロールオーバーしている間、右回りと左回りを交互に繰り返す。
import fl.transitions.Tween;
import fl.transitions.easing.Regular;
import fl.transitions.TweenEvent;
var twObj:Tween;

//ロールオーバーとロールアウトの設定
box_mc.addEventListener(MouseEvent.ROLL_OVER, startSwing);
box_mc.addEventListener(MouseEvent.ROLL_OUT, stopSwing);

//右回転
function startSwing(eventObj:MouseEvent):void {
	//右に1回転する
	twObj=new Tween(box_mc,"rotation",Regular.easeInOut,0,360,1,true);
	//回転が完了したら逆回転する
	twObj.addEventListener(TweenEvent.MOTION_FINISH, rewind);
}
//逆回転
function rewind(eventObj:TweenEvent):void {
	twObj.yoyo();
}
//逆回転を行わない
function stopSwing(eventObj:MouseEvent):void {
	twObj.removeEventListener(TweenEvent.MOTION_FINISH, rewind);
}
(section05-03 座標移動のアニメーションから抜粋)

 次のサンプルでは、トゥイーンアニメーションの関数を配列motionListに入れておき、トゥイーンが完了したならばmotionListから順に次の関数を取り出して実行します。トゥイーンの関数には右へトゥイーンするmoveRight()、左へトゥイーンするmoveLeft()、180度回転するturn()の3つの種類の関数があります。これを9行目で示すように[moveRight,turn,moveLeft,turn]の順でmotionListに入れます。そしてnextMotion()でmotionListから関数を順に取り出して実行していきます。36行目ではmotionListから取り出した関数は変数motionに入れていますが、motion()と実行することで取り出した関数を実行できます。

 トゥイーンアニメーションのそれぞれの関数では、実行したトゥイーンが完了したならばnextMotion()を呼び出すようにTweenEvent.MOTION_FINISHイベントのリスナー関数を登録します。moveRight()、moveLeft()、turn()で毎回新しくtwObjインスタンスを作成するので、そのつどにTweenEvent.MOTION_FINISHイベントのリスナー関数を登録しなければなりません。

fig05-03-04_shiji.jpgswfを試す

[:script:]複数のトゥイーンアニメーションを連続して再生する
(section05-03 座標移動のアニメーションから抜粋)

トゥイーンの完了を待って次の処理に移りたいという場合があります。Tweenクラスではトゥイーンの完了をTweenEvent.MOTION_FINISHイベントで知ることができます。
 次のサンプルではこれを利用して2つのトゥイーンを連続させています。まず最初にステージの外から中央へトゥイーンで登場し、移動が完了したならば続いてスケールをトゥイーンさせてビヨンと弾むようなアニメーションを行います。トゥイーンの関数にElastic.easeOutを使うとビヨンと弾むように見えます。
fig05-03-03_shiji.jpgswfを試す
//利用するクラスをインポート
import fl.transitions.Tween;
import fl.transitions.easing.Regular;
import fl.transitions.easing.Elastic;
import fl.transitions.TweenEvent;
var twObj1:Tween;
var twObj2:Tween;
var twObj3:Tween;

//ステージの外から登場してくる
twObj1=new Tween(box_mc,"x",Regular.easeInOut,-100,275,1,true);
twObj1.addEventListener(TweenEvent.MOTION_FINISH, spring);

//移動が完了したらビヨンと弾む
function spring(eventObj:TweenEvent):void {
	twObj2=new Tween(box_mc,"scaleX",Elastic.easeOut,0.8,1,1,true);
	twObj3=new Tween(box_mc,"scaleY",Elastic.easeOut,0.8,1,1,true);
}
(section05-03 Tweenクラスを利用したアニメーションから抜粋)

 次のサンプルはステージにあるbox_mcインスタンスをx座標50の位置からx座標450の位置まで、Tweenクラスを利用して直線的に移動させる例です。引数は次のようになります。トゥイーンさせるインスタンスはbox_mc、値を変化させるプロパティはx、値の変化に利用する関数は標準的なイーズイン・アウトのRegular.easeInOut、xプロパティの開始値は50、終了値は450、移動には1秒間、秒数指定なので最後の引数はtrueです。

//利用するクラスをインポート
import fl.transitions.Tween;
import fl.transitions.easing.Regular;
//box_mcのx座標をトゥイーンする
var twObj_x:Tween=new Tween(box_mc,"x",Regular.easeInOut,50,450,1,true);
swfを試す
(section05-02 座標移動のアニメーションから抜粋)

 次のサンプルでは5個のインスタンスがサイン波を描きながらステージを右から左へ横切ります。実際には最初の1個だけがサイン波を描いて動き、残りのインスタンスは1つ前のインスタンスを追いかけています。各インスタンスは前との間隔を少しずつ詰めるようにしてあり、アルファ値も少しずつ薄くしてあるので残像のように見えます。
 1個目のインスタンスはステージの右端まで来たら左端に戻ります。他のインスタンスも遅れてそれに追従します。インスタンスをサイン波を描いて動かせるためにY軸座標をMath.sin()で縦の振幅運動にしておき、X座標は5ピクセルずつ加算してステージを横切るようにしています。

#ステージ右まで行ったball_mcの5個がすべて右に抜け、左から出てくるようにするにはどうしたらいいでしょう?ぜひ、自分で考えてみてください。

fig05-02-11a.jpgswfを試す
//初期値設定
var offsetY:Number=200;
var deg:uint=0;
ball5_mc.x=ball4_mc.x=ball3_mc.x=ball2_mc.x=ball_mc.x=100;
ball5_mc.y=ball4_mc.y=ball3_mc.y=ball2_mc.y=ball_mc.y=offsetY;
ball2_mc.alpha=0.8;
ball3_mc.alpha=0.6;
ball4_mc.alpha=0.4;
ball5_mc.alpha=0.2;
//イベントリスナーの設定
addEventListener(Event.ENTER_FRAME, onEnterframe);
//フレーム再生イベントのリスナー関数
function onEnterframe(eventObj:Event):void {
	//10度ずつ進める
	deg = (deg+10)%360;
	//振幅100のサイン波
	ball_mc.y=offsetY-100*Math.sin(deg*Math.PI/180);
	//座標移動
	if ((ball_mc.x-ball_mc.width/2)>stage.stageWidth) {
		//ステージの外に出たら反対側に左に戻す
		ball_mc.x=- ball_mc.width/2;
	} else {
		//右へ進む
		ball_mc.x+=5;
	}
	//1つ前のインスタンスを追いかける
	ball2_mc.x += (ball_mc.x - ball2_mc.x)/3;
	ball2_mc.y += (ball_mc.y - ball2_mc.y)/3;
	ball3_mc.x += (ball2_mc.x - ball3_mc.x)/3;
	ball3_mc.y += (ball2_mc.y - ball3_mc.y)/3;
	ball4_mc.x += (ball3_mc.x - ball4_mc.x)/3;
	ball4_mc.y += (ball3_mc.y - ball4_mc.y)/3;
	ball5_mc.x += (ball4_mc.x - ball5_mc.x)/3;
	ball5_mc.y += (ball4_mc.y - ball5_mc.y)/3;
}
(section05-02 座標移動のアニメーションから抜粋)

 次のサンプルはマウスカーソルを回りを楕円形を描いてトンボのインスタンスが飛びます。トンボは進行方向を向くように回転に合わせて向きを変えます。マウスカーソルを動かすとトンボはゆっくり追いかけます。
 トンボが回る軌道を楕円形にするには、15〜16行目のようにX軸方向の振幅をY軸方向の振幅の2倍にします。これで横方向に2倍の長さの楕円になります。マウスカーソルの座標を楕円の中心にすればマウスカーソルの回りをトンボが回ります。このとき10〜11行目のようにマウスカーソルの座標にイージングで近づくようにすれば、マウスカーソルをゆっくり追いかける楕円軌道になります。
 トンボの向きを回転の進行方向に合わせているのは18行目です。トンボのインスタンスのrotationの値を周回の回転角度と同じにすれば向きが合いますが、時計回りなのでトンボを下向きに作っておく必要があります。

#このサンプルは「AS3入門ノート2」にもあるサンプルですが、好例なので取り上げました(説明は書き直してます)。

fig05-02-10_shiji.jpgswfを試す
var deg:uint = 0;
var r:uint = 90;
var tmpX:Number = stage.mouseX;
var tmpY:Number = stage.mouseY;
//イベントリスナーの設定	
tombo_mc.addEventListener(Event.ENTER_FRAME, roundCursor);
//フレーム再生イベントのリスナー関数
function roundCursor(eventObj:Event):void {
	//マウスカーソルの位置に近づく
	tmpX += (stage.mouseX-tmpX)/10;
	tmpY += (stage.mouseY-tmpY)/10;
	//15度ずつ回転する
	deg = (deg+15)%360;
	//(tmpX,tmpY)を中心点にして時計回りに楕円で回る
	tombo_mc.x = 2*r*Math.cos(deg*Math.PI/180) + tmpX;
	tombo_mc.y = r*Math.sin(deg*Math.PI/180) + tmpY;
	//回転に合わせて向きを変える
	tombo_mc.rotation = deg;
}

Twitterもスタート

|

このAS3入門ノート用のtwitterアカウントを作りました。
サポートページの更新情報、セミナー情報、Flash関連イベントやニュースなどをつぶやくのでフォローしてくださいね!

twitter.gif@as3note

ちなみに@oshigeは個人的な役に立たない横乗り生活のつぶやきです・・・(^ ^;;;

(section05-01 フレームのナビゲーションから抜粋)

次のサンプルではムービークリップの上でマウスカーソルを左右に水平に動かすだけでムービークリップのフレームの写真をブラウズできます。スライダーを動かして映像のコマ送りを行うような操作です。マウスカーソルがインスタンスの左端ならフレーム1の写真を表示し、右端なら最終フレームの写真を表示します。カーソルが途中の40%の位置にあるならば総フレーム数の40%の位置のフレームを表示します。
#これを応用すれば外部ファイルのサムネイルだけを先に読み込んでブラウズすることもできますよね。

fig05-01-03_shiji.jpg
カーソルが左端ならフレーム1,右端は最終フレームというようにロールオーバーしているカーソルの水平座標に応じてムービークリップのフレームを移動します。
swfを試す
photo_mc.stop();
photo_mc.addEventListener(MouseEvent.ROLL_OVER, onRollover);
photo_mc.addEventListener(MouseEvent.ROLL_OUT, onRollout);

//ロールオーバーで動作開始
function onRollover(eventObj:MouseEvent):void {
	var mc:MovieClip=eventObj.target as MovieClip;
	mc.addEventListener(Event.ENTER_FRAME, stepFrame);
}
//ロールアウトで動作停止
function onRollout(eventObj:MouseEvent):void {
	var mc:MovieClip=eventObj.target as MovieClip;
	mc.removeEventListener(Event.ENTER_FRAME, stepFrame);
	mc.gotoAndStop(1);
}
//マウス座標に応じたフレームへ移動
function stepFrame(eventObj:Event):void {
	var mc:MovieClip=eventObj.target as MovieClip;
	//幅を総フレーム数としたときのマウスが指すフレーム番号
	var frame:uint= Math.ceil(mc.totalFrames*mc.mouseX/mc.width);
	mc.gotoAndStop(frame);
}
まったく新しいAS3の世界!
694a.jpg
Adobe Flash CS4
詳細!ActionScript3.0入門ノート[完全改訂版](CD-ROM付)

楽しいActionScript。
新たなる1歩へと踏み出しましょう。
■内容は?→ 目次を見る
■評判は?→ 書評を読む
この本を書いたわけ

このアーカイブについて

このページには、2009年7月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2009年6月です。

次のアーカイブは2009年8月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

あわせて読みたいブログパーツ